From 8f62a47a28c9190a8e54782fdfa2a45b085a7b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 10 Feb 2022 12:07:21 +0100 Subject: [PATCH 001/275] refactor: allow the mock module to be used multiple times as base ibc application in middleware stack (#892) ## Description Currently the `AppModule` assumes a single scoped keeper. This doesn't allow the mock module to be used as a base application for different middleware stack (ica stack, fee stack, etc) I broke the API because I think it is cleaner. If we want this to be non API breaking, I can try to readjust ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- CHANGELOG.md | 1 + testing/README.md | 1 + testing/mock/ibc_app.go | 12 ++++++++++++ testing/mock/ibc_module.go | 22 +++++++++++----------- testing/mock/mock.go | 20 +++++++++++--------- testing/simapp/app.go | 6 +++--- 6 files changed, 39 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c42454c3ed..13b0b202822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/02-client) [\#536](https://github.com/cosmos/ibc-go/pull/536) `GetSelfConsensusState` return type changed from bool to error. * (channel) [\#644](https://github.com/cosmos/ibc-go/pull/644) Removes `CounterpartyHops` function from the ChannelKeeper. * (testing) [\#776](https://github.com/cosmos/ibc-go/pull/776) Adding helper fn to generate capability name for testing callbacks +* (testing) [\#892](https://github.com/cosmos/ibc-go/pull/892) IBC Mock modules store the scoped keeper and portID within the IBCMockApp. They also maintain reference to the AppModule to update the AppModule's list of IBC applications it references. Allows for the mock module to be reused as a base application in middleware stacks. * (channel) [\#882](https://github.com/cosmos/ibc-go/pull/882) The `WriteAcknowledgement` API now takes `exported.Acknowledgement` instead of a byte array ### State Machine Breaking diff --git a/testing/README.md b/testing/README.md index 97f540d5c4c..ad02a80e640 100644 --- a/testing/README.md +++ b/testing/README.md @@ -296,6 +296,7 @@ The mock module may also be leveraged to act as a base application in the instan The mock IBC module contains a `MockIBCApp`. This struct contains a function field for every IBC App Module callback. Each of these functions can be individually set to mock expected behaviour of a base application. +The portID and scoped keeper for the `MockIBCApp` should be set within `MockIBCApp` before calling `NewIBCModule`. For example, if one wanted to test that the base application cannot affect the outcome of the `OnChanOpenTry` callback, the mock module base application callback could be updated as such: ```go diff --git a/testing/mock/ibc_app.go b/testing/mock/ibc_app.go index a3f2db3bc6d..15f77d02d5a 100644 --- a/testing/mock/ibc_app.go +++ b/testing/mock/ibc_app.go @@ -2,6 +2,7 @@ package mock import ( sdk "github.com/cosmos/cosmos-sdk/types" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -10,6 +11,9 @@ import ( // MockIBCApp contains IBC application module callbacks as defined in 05-port. type MockIBCApp struct { + PortID string + ScopedKeeper capabilitykeeper.ScopedKeeper + OnChanOpenInit func( ctx sdk.Context, order channeltypes.Order, @@ -81,3 +85,11 @@ type MockIBCApp struct { relayer sdk.AccAddress, ) error } + +// NewMockIBCApp returns a MockIBCApp. An empty PortID indicates the mock app doesn't bind/claim ports. +func NewMockIBCApp(portID string, scopedKeeper capabilitykeeper.ScopedKeeper) *MockIBCApp { + return &MockIBCApp{ + PortID: portID, + ScopedKeeper: scopedKeeper, + } +} diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index fb46864709b..1ea1d3850ad 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -6,7 +6,6 @@ import ( "strconv" sdk "github.com/cosmos/cosmos-sdk/types" - capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -16,15 +15,16 @@ import ( // IBCModule implements the ICS26 callbacks for testing/mock. type IBCModule struct { - IBCApp *MockIBCApp // base application of an IBC middleware stack - scopedKeeper capabilitykeeper.ScopedKeeper + appModule *AppModule + IBCApp *MockIBCApp // base application of an IBC middleware stack } // NewIBCModule creates a new IBCModule given the underlying mock IBC application and scopedKeeper. -func NewIBCModule(app *MockIBCApp, scopedKeeper capabilitykeeper.ScopedKeeper) IBCModule { +func NewIBCModule(appModule *AppModule, app *MockIBCApp) IBCModule { + appModule.ibcApps = append(appModule.ibcApps, app) return IBCModule{ - IBCApp: app, - scopedKeeper: scopedKeeper, + appModule: appModule, + IBCApp: app, } } @@ -39,7 +39,7 @@ func (im IBCModule) OnChanOpenInit( } // Claim channel capability passed back by IBC module - if err := im.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + if err := im.IBCApp.ScopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { return err } @@ -56,7 +56,7 @@ func (im IBCModule) OnChanOpenTry( } // Claim channel capability passed back by IBC module - if err := im.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + if err := im.IBCApp.ScopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { return "", err } @@ -107,7 +107,7 @@ func (im IBCModule) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, re // set state by claiming capability to check if revert happens return capName := GetMockRecvCanaryCapabilityName(packet) - if _, err := im.scopedKeeper.NewCapability(ctx, capName); err != nil { + if _, err := im.IBCApp.ScopedKeeper.NewCapability(ctx, capName); err != nil { // application callback called twice on same packet sequence // must never occur panic(err) @@ -129,7 +129,7 @@ func (im IBCModule) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes } capName := GetMockAckCanaryCapabilityName(packet) - if _, err := im.scopedKeeper.NewCapability(ctx, capName); err != nil { + if _, err := im.IBCApp.ScopedKeeper.NewCapability(ctx, capName); err != nil { // application callback called twice on same packet sequence // must never occur panic(err) @@ -145,7 +145,7 @@ func (im IBCModule) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, } capName := GetMockTimeoutCanaryCapabilityName(packet) - if _, err := im.scopedKeeper.NewCapability(ctx, capName); err != nil { + if _, err := im.IBCApp.ScopedKeeper.NewCapability(ctx, capName); err != nil { // application callback called twice on same packet sequence // must never occur panic(err) diff --git a/testing/mock/mock.go b/testing/mock/mock.go index fd454aa80d9..a37536de37a 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -8,7 +8,6 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" @@ -89,15 +88,14 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { // AppModule represents the AppModule for the mock module. type AppModule struct { AppModuleBasic - scopedKeeper capabilitykeeper.ScopedKeeper - portKeeper PortKeeper + ibcApps []*MockIBCApp + portKeeper PortKeeper } // NewAppModule returns a mock AppModule instance. -func NewAppModule(sk capabilitykeeper.ScopedKeeper, pk PortKeeper) AppModule { +func NewAppModule(pk PortKeeper) AppModule { return AppModule{ - scopedKeeper: sk, - portKeeper: pk, + portKeeper: pk, } } @@ -124,9 +122,13 @@ func (am AppModule) RegisterServices(module.Configurator) {} // InitGenesis implements the AppModule interface. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { - // bind mock port ID - cap := am.portKeeper.BindPort(ctx, ModuleName) - am.scopedKeeper.ClaimCapability(ctx, cap, host.PortPath(ModuleName)) + for _, ibcApp := range am.ibcApps { + if ibcApp.PortID != "" { + // bind mock portID + cap := am.portKeeper.BindPort(ctx, ibcApp.PortID) + ibcApp.ScopedKeeper.ClaimCapability(ctx, cap, host.PortPath(ModuleName)) + } + } return []abci.ValidatorUpdate{} } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 890d7c4661d..a2b78e7d260 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -350,8 +350,8 @@ func NewSimApp( // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // not replicate if you do not need to test core IBC or light clients. - mockModule := ibcmock.NewAppModule(scopedIBCMockKeeper, &app.IBCKeeper.PortKeeper) - mockIBCModule := ibcmock.NewIBCModule(&ibcmock.MockIBCApp{}, scopedIBCMockKeeper) + mockModule := ibcmock.NewAppModule(&app.IBCKeeper.PortKeeper) + mockIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp(ibcmock.ModuleName, scopedIBCMockKeeper)) app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), @@ -369,7 +369,7 @@ func NewSimApp( icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) // initialize ICA module with mock module as the authentication module on the controller side - icaAuthModule := ibcmock.NewIBCModule(&ibcmock.MockIBCApp{}, scopedICAMockKeeper) + icaAuthModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) app.ICAAuthModule = icaAuthModule icaControllerIBCModule := icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthModule) From 843b459635da8cedd92945141c4efe3a762f305d Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 10 Feb 2022 13:32:50 +0100 Subject: [PATCH 002/275] feat: adding Pack/Unpack acknowledgement helper fns (#895) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: adding Pack/Unpack acknowledgement helper fns * chore: changelog * fix: docs * Update modules/core/04-channel/types/codec.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- CHANGELOG.md | 2 + modules/core/04-channel/types/codec.go | 34 ++++++++++++ modules/core/04-channel/types/codec_test.go | 58 +++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 modules/core/04-channel/types/codec_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 13b0b202822..0cc8794c755 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#432](https://github.com/cosmos/ibc-go/pull/432) Introduce `MockIBCApp` struct to the mock module. Allows the mock module to be reused to perform custom logic on each IBC App interface function. This might be useful when testing out IBC applications written as middleware. * [\#380](https://github.com/cosmos/ibc-go/pull/380) Adding the Interchain Accounts module v1 * [\#679](https://github.com/cosmos/ibc-go/pull/679) New CLI command `query ibc-transfer denom-hash ` to get the denom hash for a denom trace; this might be useful for debug +* (channel) [\#895](https://github.com/cosmos/ibc-go/pull/895) Adding UnpackAcknowledgement and PackAcknowledgement helper functions to pack or unpack an Acknowledgement to and from a proto Any type + ### Bug Fixes diff --git a/modules/core/04-channel/types/codec.go b/modules/core/04-channel/types/codec.go index 8981417130b..f77cd90c051 100644 --- a/modules/core/04-channel/types/codec.go +++ b/modules/core/04-channel/types/codec.go @@ -4,7 +4,9 @@ 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/msgservice" + proto "github.com/gogo/protobuf/proto" "github.com/cosmos/ibc-go/v3/modules/core/exported" ) @@ -50,3 +52,35 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { // The actual codec used for serialization should be provided to x/ibc/core/04-channel and // defined at the application level. var SubModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + +// UnpackAcknowledgement unpacks an Any into an Acknowledgement. It returns an error if the +// Any can't be unpacked into an Acknowledgement. +func UnpackAcknowledgement(any *codectypes.Any) (exported.Acknowledgement, error) { + if any == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil") + } + + ack, ok := any.GetCachedValue().(exported.Acknowledgement) + if !ok { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into Acknowledgement %T", any) + } + + return ack, nil +} + +// PackAcknowledgement constructs a new Any packed with the given acknowledgement value. It returns +// an error if the acknowledgement can't be casted to a protobuf message or if the concrete +// implemention is not registered to the protobuf codec. +func PackAcknowledgement(acknowledgement exported.Acknowledgement) (*codectypes.Any, error) { + msg, ok := acknowledgement.(proto.Message) + if !ok { + return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", acknowledgement) + } + + anyAcknowledgement, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error()) + } + + return anyAcknowledgement, nil +} diff --git a/modules/core/04-channel/types/codec_test.go b/modules/core/04-channel/types/codec_test.go new file mode 100644 index 00000000000..bb0c8b81ddb --- /dev/null +++ b/modules/core/04-channel/types/codec_test.go @@ -0,0 +1,58 @@ +package types_test + +import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + + "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v3/modules/core/exported" + ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" +) + +type caseAny struct { + name string + any *codectypes.Any + expPass bool +} + +func (suite *TypesTestSuite) TestPackAcknowledgement() { + + testCases := []struct { + name string + acknowledgement exported.Acknowledgement + expPass bool + }{ + { + "success", + &ibcmock.MockAcknowledgement, + true, + }, + { + "nil", + nil, + false, + }, + } + + testCasesAny := []caseAny{} + + for _, tc := range testCases { + ackAny, err := types.PackAcknowledgement(tc.acknowledgement) + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + + testCasesAny = append(testCasesAny, caseAny{tc.name, ackAny, tc.expPass}) + } + + for i, tc := range testCasesAny { + cs, err := types.UnpackAcknowledgement(tc.any) + if tc.expPass { + suite.Require().NoError(err, tc.name) + suite.Require().Equal(testCases[i].acknowledgement, cs, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +} From fb2f0416254b997f41ac69a079136b1092f5fa6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Thu, 10 Feb 2022 15:10:24 +0100 Subject: [PATCH 003/275] imp: support custom keys for testing (#893) --- CHANGELOG.md | 1 + testing/app.go | 18 +++++++++++------- testing/chain.go | 17 ++++++++++------- testing/coordinator.go | 2 -- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cc8794c755..a76fc67c396 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (testing) [\#893](https://github.com/cosmos/ibc-go/pull/893) Support custom private keys for testing. * (testing) [\#810](https://github.com/cosmos/ibc-go/pull/810) Additional testing function added to `Endpoint` type called `RecvPacketWithResult`. Performs the same functionality as the existing `RecvPacket` function but also returns the message result. `path.RelayPacket` no longer uses the provided acknowledgement argument and instead obtains the acknowledgement via MsgRecvPacket events. * (connection) [\#721](https://github.com/cosmos/ibc-go/pull/721) Simplify connection handshake error messages when unpacking client state. * (channel) [\#692](https://github.com/cosmos/ibc-go/pull/692) Minimize channel logging by only emitting the packet sequence, source port/channel, destination port/channel upon packet receives, acknowledgements and timeouts. diff --git a/testing/app.go b/testing/app.go index 1c5bbe7c88a..487e0569ba2 100644 --- a/testing/app.go +++ b/testing/app.go @@ -126,13 +126,17 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs // commit genesis changes app.Commit() - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{ - ChainID: chainID, - Height: app.LastBlockHeight() + 1, - AppHash: app.LastCommitID().Hash, - ValidatorsHash: valSet.Hash(), - NextValidatorsHash: valSet.Hash(), - }}) + app.BeginBlock( + abci.RequestBeginBlock{ + Header: tmproto.Header{ + ChainID: chainID, + Height: app.LastBlockHeight() + 1, + AppHash: app.LastCommitID().Hash, + ValidatorsHash: valSet.Hash(), + NextValidatorsHash: valSet.Hash(), + }, + }, + ) return app } diff --git a/testing/chain.go b/testing/chain.go index 281782f7837..8dfe4b8fb27 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -56,18 +56,23 @@ type TestChain struct { Vals *tmtypes.ValidatorSet Signers []tmtypes.PrivValidator - senderPrivKey cryptotypes.PrivKey + // autogenerated sender private key + SenderPrivKey cryptotypes.PrivKey SenderAccount authtypes.AccountI } // NewTestChain initializes a new TestChain instance with a single validator set using a -// generated private key. It also creates a sender account to be used for delivering transactions. +// generated secp256k1 Tendermint private key. It also creates a sender BaseAccount to be used for +// delivering transactions. // // The first block height is committed to state in order to allow for client creations on // counterparty chains. The TestChain will return with a block height starting at 2. // // Time management is handled by the Coordinator in order to ensure synchrony between chains. // Each update of any chain increments the block header time for all chains by 5 seconds. +// +// NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this +// constructor function. func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { // generate validator private/public key privVal := mock.NewPV() @@ -113,7 +118,7 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { Codec: app.AppCodec(), Vals: valSet, Signers: signers, - senderPrivKey: senderPrivKey, + SenderPrivKey: senderPrivKey, SenderAccount: acc, } @@ -237,7 +242,6 @@ func (chain *TestChain) sendMsgs(msgs ...sdk.Msg) error { // number and updates the TestChain's headers. It returns the result and error if one // occurred. func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) { - // ensure the chain has the latest time chain.Coordinator.UpdateTimeForChain(chain) @@ -250,7 +254,7 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) { chain.ChainID, []uint64{chain.SenderAccount.GetAccountNumber()}, []uint64{chain.SenderAccount.GetSequence()}, - true, true, chain.senderPrivKey, + true, true, chain.SenderPrivKey, ) if err != nil { return nil, err @@ -357,7 +361,6 @@ func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterpa header.TrustedValidators = trustedVals return header, nil - } // ExpireClient fast forwards the chain's block time by the provided amount of time which will @@ -468,7 +471,7 @@ func CreateSortedSignerArray(altPrivVal, suitePrivVal tmtypes.PrivValidator, // CreatePortCapability binds and claims a capability for the given portID if it does not // already exist. This function will fail testing on any resulting error. -// NOTE: only creation of a capbility for a transfer or mock port is supported +// NOTE: only creation of a capability for a transfer or mock port is supported // Other applications must bind to the port in InitGenesis or modify this code. func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.ScopedKeeper, portID string) { // check if the portId is already binded, if not bind it diff --git a/testing/coordinator.go b/testing/coordinator.go index 615bd830ced..be308c790d5 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -55,7 +55,6 @@ func (coord *Coordinator) IncrementTime() { func (coord *Coordinator) IncrementTimeBy(increment time.Duration) { coord.CurrentTime = coord.CurrentTime.Add(increment).UTC() coord.UpdateTime() - } // UpdateTime updates all clocks for the TestChains to the current global time. @@ -105,7 +104,6 @@ func (coord *Coordinator) SetupConnections(path *Path) { // are returned within a TestConnection struct. The function expects the connections to be // successfully opened otherwise testing will fail. func (coord *Coordinator) CreateConnections(path *Path) { - err := path.EndpointA.ConnOpenInit() require.NoError(coord.t, err) From c27d5b5f26b55d07489cc02fd0b8ce9fa8218e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 14 Feb 2022 12:08:27 +0100 Subject: [PATCH 004/275] chore: add ParsePacketFromEvents testing helper function (#904) ## Description ref: #891 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- CHANGELOG.md | 1 + modules/apps/transfer/keeper/relay_test.go | 8 +-- modules/apps/transfer/transfer_test.go | 33 ++++++------ testing/events.go | 60 ++++++++++++++++++++++ 4 files changed, 80 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a76fc67c396..6e9a2790b7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (testing) [\#904](https://github.com/cosmos/ibc-go/pull/904) Add `ParsePacketFromEvents` function to the testing package. Useful when sending/relaying packets via the testing package. * (testing) [\#893](https://github.com/cosmos/ibc-go/pull/893) Support custom private keys for testing. * (testing) [\#810](https://github.com/cosmos/ibc-go/pull/810) Additional testing function added to `Endpoint` type called `RecvPacketWithResult`. Performs the same functionality as the existing `RecvPacket` function but also returns the message result. `path.RelayPacket` no longer uses the provided acknowledgement argument and instead obtains the acknowledgement via MsgRecvPacket events. * (connection) [\#721](https://github.com/cosmos/ibc-go/pull/721) Simplify connection handshake error messages when unpacking client state. diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 8e77c73db9e..9d03bbde962 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -186,12 +186,12 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // send coin from chainB to chainA, receive them, acknowledge them, and send back to chainB coinFromBToA := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coinFromBToA, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 110), 0) - _, err := suite.chainB.SendMsgs(transferMsg) + res, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed - // relay send packet - fungibleTokenPacket := types.NewFungibleTokenPacketData(coinFromBToA.Denom, coinFromBToA.Amount.String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String()) - packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, clienttypes.NewHeight(0, 110), 0) + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + suite.Require().NoError(err) + err = path.RelayPacket(packet) suite.Require().NoError(err) // relay committed diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index ec36af78ceb..5190cdc8d29 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -8,7 +8,6 @@ import ( "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" ) @@ -56,13 +55,13 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { // send from chainA to chainB msg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0) - - _, err := suite.chainA.SendMsgs(msg) + res, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + suite.Require().NoError(err) + // relay send - fungibleTokenPacket := types.NewFungibleTokenPacketData(coinToSendToB.Denom, coinToSendToB.Amount.String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String()) - packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, 0) err = path.RelayPacket(packet) suite.Require().NoError(err) // relay committed @@ -82,18 +81,18 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { // send from chainB to chainC msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, coinSentFromAToB, suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0) - - _, err = suite.chainB.SendMsgs(msg) + res, err = suite.chainB.SendMsgs(msg) suite.Require().NoError(err) // message committed - // relay send - // NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment - fullDenomPath := types.GetPrefixedDenom(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, voucherDenomTrace.GetFullDenomPath()) - fungibleTokenPacket = types.NewFungibleTokenPacketData(voucherDenomTrace.GetFullDenomPath(), coinSentFromAToB.Amount.String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String()) - packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, timeoutHeight, 0) + packet, err = ibctesting.ParsePacketFromEvents(res.GetEvents()) + suite.Require().NoError(err) + err = pathBtoC.RelayPacket(packet) suite.Require().NoError(err) // relay committed + // NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment + fullDenomPath := types.GetPrefixedDenom(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, voucherDenomTrace.GetFullDenomPath()) + coinSentFromBToC := sdk.NewCoin(types.ParseDenomTrace(fullDenomPath).IBCDenom(), amount) balance = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccount.GetAddress(), coinSentFromBToC.Denom) @@ -106,14 +105,12 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { // send from chainC back to chainB msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, coinSentFromBToC, suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0) - - _, err = suite.chainC.SendMsgs(msg) + res, err = suite.chainC.SendMsgs(msg) suite.Require().NoError(err) // message committed - // relay send - // NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment - fungibleTokenPacket = types.NewFungibleTokenPacketData(fullDenomPath, coinSentFromBToC.Amount.String(), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String()) - packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, timeoutHeight, 0) + packet, err = ibctesting.ParsePacketFromEvents(res.GetEvents()) + suite.Require().NoError(err) + err = pathBtoC.RelayPacket(packet) suite.Require().NoError(err) // relay committed diff --git a/testing/events.go b/testing/events.go index 037a4c342e3..7828b42619f 100644 --- a/testing/events.go +++ b/testing/events.go @@ -2,6 +2,7 @@ package ibctesting import ( "fmt" + "strconv" sdk "github.com/cosmos/cosmos-sdk/types" @@ -56,6 +57,65 @@ func ParseChannelIDFromEvents(events sdk.Events) (string, error) { return "", fmt.Errorf("channel identifier event attribute not found") } +// ParsePacketFromEvents parses events emitted from a MsgRecvPacket and returns the +// acknowledgement. +func ParsePacketFromEvents(events sdk.Events) (channeltypes.Packet, error) { + for _, ev := range events { + if ev.Type == channeltypes.EventTypeSendPacket { + packet := channeltypes.Packet{} + for _, attr := range ev.Attributes { + + switch string(attr.Key) { + case channeltypes.AttributeKeyData: + packet.Data = attr.Value + + case channeltypes.AttributeKeySequence: + seq, err := strconv.ParseUint(string(attr.Value), 10, 64) + if err != nil { + return channeltypes.Packet{}, err + } + + packet.Sequence = seq + + case channeltypes.AttributeKeySrcPort: + packet.SourcePort = string(attr.Value) + + case channeltypes.AttributeKeySrcChannel: + packet.SourceChannel = string(attr.Value) + + case channeltypes.AttributeKeyDstPort: + packet.DestinationPort = string(attr.Value) + + case channeltypes.AttributeKeyDstChannel: + packet.DestinationChannel = string(attr.Value) + + case channeltypes.AttributeKeyTimeoutHeight: + height, err := clienttypes.ParseHeight(string(attr.Value)) + if err != nil { + return channeltypes.Packet{}, err + } + + packet.TimeoutHeight = height + + case channeltypes.AttributeKeyTimeoutTimestamp: + timestamp, err := strconv.ParseUint(string(attr.Value), 10, 64) + if err != nil { + return channeltypes.Packet{}, err + } + + packet.TimeoutTimestamp = timestamp + + default: + continue + } + } + + return packet, nil + } + } + return channeltypes.Packet{}, fmt.Errorf("acknowledgement event attribute not found") +} + // ParseAckFromEvents parses events emitted from a MsgRecvPacket and returns the // acknowledgement. func ParseAckFromEvents(events sdk.Events) ([]byte, error) { From afa2d904a1e47054d8013100bd97adde8dbd2a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 15 Feb 2022 13:27:05 +0100 Subject: [PATCH 005/275] fix: correctly claim capability for mock module, handle genesis exports (#921) ## Description This contains two fixes: - the capability being claimed by the scoped keeper was incorrect (mock.ModuleName -> port ID) - the mock module wasn't accounting for non empty genesis state in capabilities (after genesis export, capability will create the bound ports so rebinding doesn't need to happen) closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- testing/mock/mock.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/testing/mock/mock.go b/testing/mock/mock.go index a37536de37a..b621a05e9f7 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -43,6 +43,7 @@ var _ porttypes.IBCModule = IBCModule{} // PortKeeper defines the expected IBC port keeper type PortKeeper interface { BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability + IsBound(ctx sdk.Context, portID string) bool } // AppModuleBasic is the mock AppModuleBasic. @@ -123,10 +124,10 @@ func (am AppModule) RegisterServices(module.Configurator) {} // InitGenesis implements the AppModule interface. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { for _, ibcApp := range am.ibcApps { - if ibcApp.PortID != "" { + if ibcApp.PortID != "" && !am.portKeeper.IsBound(ctx, ibcApp.PortID) { // bind mock portID cap := am.portKeeper.BindPort(ctx, ibcApp.PortID) - ibcApp.ScopedKeeper.ClaimCapability(ctx, cap, host.PortPath(ModuleName)) + ibcApp.ScopedKeeper.ClaimCapability(ctx, cap, host.PortPath(ibcApp.PortID)) } } From d31f92d9bf709f5550b75db5c70a3b44314d9781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 15 Feb 2022 16:02:07 +0100 Subject: [PATCH 006/275] docs: update migration docs for upgrade proposal in relation to ICS27 (#920) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- docs/migrations/v2-to-v3.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index 710e273a954..9b7615974c0 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -28,6 +28,33 @@ The ICS4Wrapper should be the IBC Channel Keeper unless ICS 20 is being connecte ICS27 Interchain Accounts has been added as a supported IBC application of ibc-go. Please see the [ICS27 documentation](../app-modules/interchain-accounts/overview.md) for more information. +### Upgrade Proposal + +If the chain will adopt ICS27, it must set the appropriate params during the execution of the upgrade handler in `app.go`: +```go +app.UpgradeKeeper.SetUpgradeHandler("v3", + func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + // set ICS27 Host submodule params + app.ICAHostKeeper.SetParams(ctx, icahosttypes.Params{ + HostEnabled: true, + AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...], + }) + + // set ICS27 Controller submodule params + app.ICAControllerKeeper.SetParams(ctx, icacontrollertypes.Params{ + ControllerEnabled: true, + }) + + ... + + return app.mm.RunMigrations(ctx, app.configurator, fromVM) + }) + +``` + +The host and controller submodule params only need to be set if you integrate those submodules. +For example, if a chain chooses not to integrate a controller submodule, it does not need to set the controller params. + ## IBC Apps From f442721c7ea7ce69a4aadaf24808b2b250d89628 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 16 Feb 2022 15:54:14 +0100 Subject: [PATCH 007/275] chore(ica): add trail of bits audit report (#903) * chore(ica): add trail of bits audit report * relocate the audit report for ICA Co-authored-by: Carlos Rodriguez --- docs/.vuepress/config.js | 14 +++++++------- .../interchain-accounts/active-channels.md | 0 .../Trail of Bits audit - Final Report.pdf | Bin 0 -> 1147519 bytes .../interchain-accounts/auth-modules.md | 0 .../interchain-accounts/integration.md | 0 .../interchain-accounts/overview.md | 0 .../interchain-accounts/parameters.md | 0 .../interchain-accounts/transactions.md | 0 docs/migrations/v2-to-v3.md | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename docs/{app-modules => apps}/interchain-accounts/active-channels.md (100%) create mode 100644 docs/apps/interchain-accounts/audits/Trail of Bits audit - Final Report.pdf rename docs/{app-modules => apps}/interchain-accounts/auth-modules.md (100%) rename docs/{app-modules => apps}/interchain-accounts/integration.md (100%) rename docs/{app-modules => apps}/interchain-accounts/overview.md (100%) rename docs/{app-modules => apps}/interchain-accounts/parameters.md (100%) rename docs/{app-modules => apps}/interchain-accounts/transactions.md (100%) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 8a69e377fe3..8e83c7c7cd3 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -109,37 +109,37 @@ module.exports = { { title: "Interchain Accounts", directory: true, - path: "/app-modules", + path: "/apps", children: [ { title: "Overview", directory: false, - path: "/app-modules/interchain-accounts/overview.html" + path: "/apps/interchain-accounts/overview.html" }, { title: "Authentication Modules", directory: false, - path: "/app-modules/interchain-accounts/auth-modules.html" + path: "/apps/interchain-accounts/auth-modules.html" }, { title: "Active Channels", directory: false, - path: "/app-modules/interchain-accounts/active-channels.html" + path: "/apps/interchain-accounts/active-channels.html" }, { title: "Integration", directory: false, - path: "/app-modules/interchain-accounts/integration.html" + path: "/apps/interchain-accounts/integration.html" }, { title: "Parameters", directory: false, - path: "/app-modules/interchain-accounts/parameters.html" + path: "/apps/interchain-accounts/parameters.html" }, { title: "Transactions", directory: false, - path: "/app-modules/interchain-accounts/transactions.html" + path: "/apps/interchain-accounts/transactions.html" }, ] }, diff --git a/docs/app-modules/interchain-accounts/active-channels.md b/docs/apps/interchain-accounts/active-channels.md similarity index 100% rename from docs/app-modules/interchain-accounts/active-channels.md rename to docs/apps/interchain-accounts/active-channels.md diff --git a/docs/apps/interchain-accounts/audits/Trail of Bits audit - Final Report.pdf b/docs/apps/interchain-accounts/audits/Trail of Bits audit - Final Report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3f6182e4e98e6b4fc587a8e165f734299f69adba GIT binary patch literal 1147519 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�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

xh$O@^I@xjC#7m1LQC)skF5=yU4nn6U$G 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�X6!sB5Txc9+wd%hF!Y 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

%w0*B{*Mi>(Z_)U2LK*vwXZ~)m$HaAW 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,*g|kIB_4_KG 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 z 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�_;Vj2W1eDi6xnPe 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 ZpzUlaAG~ZCjn3+3&mdTI<_5Xa6~4 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 z

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 NuoW6XK{Y+~{{rUp!#Dr{ literal 0 HcmV?d00001 diff --git a/docs/app-modules/interchain-accounts/auth-modules.md b/docs/apps/interchain-accounts/auth-modules.md similarity index 100% rename from docs/app-modules/interchain-accounts/auth-modules.md rename to docs/apps/interchain-accounts/auth-modules.md diff --git a/docs/app-modules/interchain-accounts/integration.md b/docs/apps/interchain-accounts/integration.md similarity index 100% rename from docs/app-modules/interchain-accounts/integration.md rename to docs/apps/interchain-accounts/integration.md diff --git a/docs/app-modules/interchain-accounts/overview.md b/docs/apps/interchain-accounts/overview.md similarity index 100% rename from docs/app-modules/interchain-accounts/overview.md rename to docs/apps/interchain-accounts/overview.md diff --git a/docs/app-modules/interchain-accounts/parameters.md b/docs/apps/interchain-accounts/parameters.md similarity index 100% rename from docs/app-modules/interchain-accounts/parameters.md rename to docs/apps/interchain-accounts/parameters.md diff --git a/docs/app-modules/interchain-accounts/transactions.md b/docs/apps/interchain-accounts/transactions.md similarity index 100% rename from docs/app-modules/interchain-accounts/transactions.md rename to docs/apps/interchain-accounts/transactions.md diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index 9b7615974c0..fb47615d0f7 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -26,7 +26,7 @@ The ICS4Wrapper should be the IBC Channel Keeper unless ICS 20 is being connecte ### ICS27 ICS27 Interchain Accounts has been added as a supported IBC application of ibc-go. -Please see the [ICS27 documentation](../app-modules/interchain-accounts/overview.md) for more information. +Please see the [ICS27 documentation](../apps/interchain-accounts/overview.md) for more information. ### Upgrade Proposal From 20dd5cacc4cf983b5628b39908b59a90a4171e95 Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 17 Feb 2022 16:22:19 +0100 Subject: [PATCH 008/275] testing: adding multiple sender accounts for testing purposes (#935) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * fix: setting totalySupply to empty * nit: CamelCase not UPPERCASE Co-authored-by: Aditya Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- testing/app.go | 14 ++++------ testing/chain.go | 70 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/testing/app.go b/testing/app.go index 487e0569ba2..320bb0f00a7 100644 --- a/testing/app.go +++ b/testing/app.go @@ -91,22 +91,18 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec())) } - // set validators and delegations - stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) - genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis) - totalSupply := sdk.NewCoins() - for _, b := range balances { - // add genesis acc tokens and delegated tokens to total supply - totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))...) - } // add bonded amount to bonded pool module account balances = append(balances, banktypes.Balance{ Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), - Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)}, + Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt.Mul(sdk.NewInt(int64(len(valSet.Validators)))))}, }) + // set validators and delegations + stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) + genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis) + // update total supply bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}) genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) diff --git a/testing/chain.go b/testing/chain.go index 8dfe4b8fb27..86717501c6a 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -36,6 +36,15 @@ import ( "github.com/cosmos/ibc-go/v3/testing/simapp" ) +var ( + MaxAccounts = 10 +) + +type SenderAccount struct { + SenderPrivKey cryptotypes.PrivKey + SenderAccount authtypes.AccountI +} + // TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI // header and the validators of the TestChain. It also contains a field called ChainID. This // is the clientID that *other* chains use to refer to this TestChain. The SenderAccount @@ -59,6 +68,8 @@ type TestChain struct { // autogenerated sender private key SenderPrivKey cryptotypes.PrivKey SenderAccount authtypes.AccountI + + SenderAccounts []SenderAccount } // NewTestChain initializes a new TestChain instance with a single validator set using a @@ -84,18 +95,34 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) signers := []tmtypes.PrivValidator{privVal} - // generate genesis account - senderPrivKey := secp256k1.GenPrivKey() - acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) - amount, ok := sdk.NewIntFromString("10000000000000000000") - require.True(t, ok) + genAccs := []authtypes.GenesisAccount{} + genBals := []banktypes.Balance{} + senderAccs := []SenderAccount{} + + // generate genesis accounts + for i := 0; i < MaxAccounts; i++ { + senderPrivKey := secp256k1.GenPrivKey() + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), uint64(i), 0) + amount, ok := sdk.NewIntFromString("10000000000000000000") + require.True(t, ok) + + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), + } + + genAccs = append(genAccs, acc) + genBals = append(genBals, balance) + + senderAcc := SenderAccount{ + SenderAccount: acc, + SenderPrivKey: senderPrivKey, + } - balance := banktypes.Balance{ - Address: acc.GetAddress().String(), - Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), + senderAccs = append(senderAccs, senderAcc) } - app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, chainID, balance) + app := SetupWithGenesisValSet(t, valSet, genAccs, chainID, genBals...) // create current header and call begin block header := tmproto.Header{ @@ -108,18 +135,19 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { // create an account to send transactions from chain := &TestChain{ - t: t, - Coordinator: coord, - ChainID: chainID, - App: app, - CurrentHeader: header, - QueryServer: app.GetIBCKeeper(), - TxConfig: txConfig, - Codec: app.AppCodec(), - Vals: valSet, - Signers: signers, - SenderPrivKey: senderPrivKey, - SenderAccount: acc, + t: t, + Coordinator: coord, + ChainID: chainID, + App: app, + CurrentHeader: header, + QueryServer: app.GetIBCKeeper(), + TxConfig: txConfig, + Codec: app.AppCodec(), + Vals: valSet, + Signers: signers, + SenderPrivKey: senderAccs[0].SenderPrivKey, + SenderAccount: senderAccs[0].SenderAccount, + SenderAccounts: senderAccs, } coord.CommitBlock(chain) From 98f4d3af3d9ea8f345c03031deec3162d21d5c45 Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 17 Feb 2022 16:41:15 +0100 Subject: [PATCH 009/275] Create test chain with multiple validators (#942) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * multi validator commit taken from @saione * add function to pass custom valset * add changelog Co-authored-by: Sean King Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- CHANGELOG.md | 1 + testing/chain.go | 54 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e9a2790b7c..86cde220706 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (testing) [\#942](https://github.com/cosmos/ibc-go/pull/942) `NewTestChain` will create 4 validators in validator set by default. A new constructor function `NewTestChainWithValSet` is provided for test writers who want custom control over the validator set of test chains. * (testing) [\#904](https://github.com/cosmos/ibc-go/pull/904) Add `ParsePacketFromEvents` function to the testing package. Useful when sending/relaying packets via the testing package. * (testing) [\#893](https://github.com/cosmos/ibc-go/pull/893) Support custom private keys for testing. * (testing) [\#810](https://github.com/cosmos/ibc-go/pull/810) Additional testing function added to `Endpoint` type called `RecvPacketWithResult`. Performs the same functionality as the existing `RecvPacket` function but also returns the message result. `path.RelayPacket` no longer uses the provided acknowledgement argument and instead obtains the acknowledgement via MsgRecvPacket events. diff --git a/testing/chain.go b/testing/chain.go index 86717501c6a..89e5b5cb308 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -72,9 +72,9 @@ type TestChain struct { SenderAccounts []SenderAccount } -// NewTestChain initializes a new TestChain instance with a single validator set using a -// generated secp256k1 Tendermint private key. It also creates a sender BaseAccount to be used for -// delivering transactions. +// NewTestChainWithValSet initializes a new TestChain instance with the given validator set +// and signer array. It also initializes 10 Sender accounts with a balance of 10000000000000000000 coins of +// bond denom to use for tests. // // The first block height is committed to state in order to allow for client creations on // counterparty chains. The TestChain will return with a block height starting at 2. @@ -84,17 +84,11 @@ type TestChain struct { // // NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this // constructor function. -func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { - // generate validator private/public key - privVal := mock.NewPV() - pubKey, err := privVal.GetPubKey() - require.NoError(t, err) - - // create validator set with single validator - validator := tmtypes.NewValidator(pubKey, 1) - valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - signers := []tmtypes.PrivValidator{privVal} - +// +// CONTRACT: Validator and signer array must be provided in the order expected by Tendermint. +// i.e. sorted first by power and then lexicographically by address. +func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) *TestChain { + genAccs := []authtypes.GenesisAccount{} genBals := []banktypes.Balance{} senderAccs := []SenderAccount{} @@ -155,6 +149,38 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { return chain } +// NewTestChain initializes a new test chain with a default of 4 validators +// Use this function if the tests do not need custom control over the validator set +func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { + // generate validators private/public key + var ( + validatorsPerChain = 4 + validators []*tmtypes.Validator + signersByAddress = make(map[string]tmtypes.PrivValidator, validatorsPerChain) + ) + + for i := 0; i < validatorsPerChain; i++ { + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + require.NoError(t, err) + validators = append(validators, tmtypes.NewValidator(pubKey, 1)) + signersByAddress[pubKey.Address().String()] = privVal + } + + // construct validator set; + // Note that the validators are sorted by voting power + // or, if equal, by address lexical order + valSet := tmtypes.NewValidatorSet(validators) + + // create signers indexed by the valSet validators's order + signers := []tmtypes.PrivValidator{} + for _, val := range valSet.Validators { + signers = append(signers, signersByAddress[val.PubKey.Address().String()]) + } + + return NewTestChainWithValSet(t, coord, chainID, valSet, signers) +} + // GetContext returns the current context for the application. func (chain *TestChain) GetContext() sdk.Context { return chain.App.GetBaseApp().NewContext(false, chain.CurrentHeader) From 52e3ae5cedb695d52c686e0cca6c1d9b968b24b2 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 18 Feb 2022 09:45:20 +0100 Subject: [PATCH 010/275] add changelog entry for SDK bump --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86cde220706..cc1cf2a5972 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,12 +39,13 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies * [\#404](https://github.com/cosmos/ibc-go/pull/404) Bump Go version to 1.17 +* [\#851](https://github.com/cosmos/ibc-go/pull/851) Bump SDK version to v0.45.1 * (core) [\#709](https://github.com/cosmos/ibc-go/pull/709) Replace github.com/pkg/errors with stdlib errors ### API Breaking -* (channel( [\#848](https://github.com/cosmos/ibc-go/pull/848) Added `ChannelId` to MsgChannelOpenInitResponse -* (testing( [\#813](https://github.com/cosmos/ibc-go/pull/813) The `ack` argument to the testing function `RelayPacket` has been removed as it is no longer needed. +* (channel) [\#848](https://github.com/cosmos/ibc-go/pull/848) Added `ChannelId` to MsgChannelOpenInitResponse +* (testing) [\#813](https://github.com/cosmos/ibc-go/pull/813) The `ack` argument to the testing function `RelayPacket` has been removed as it is no longer needed. * (testing) [\#774](https://github.com/cosmos/ibc-go/pull/774) Added `ChainID` arg to `SetupWithGenesisValSet` on the testing app. `Coordinator` generated ChainIDs now starts at index 1 * (transfer) [\#675](https://github.com/cosmos/ibc-go/pull/675) Transfer `NewKeeper` now takes in an ICS4Wrapper. The ICS4Wrapper may be the IBC Channel Keeper when ICS20 is not used in a middleware stack. The ICS4Wrapper is required for applications wishing to connect middleware to ICS20. * (core) [\#650](https://github.com/cosmos/ibc-go/pull/650) Modify `OnChanOpenTry` IBC application module callback to return the negotiated app version. The version passed into the `MsgChanOpenTry` has been deprecated and will be ignored by core IBC. From d48f576a0b2fe752790339f9e6f99b99d9fe2486 Mon Sep 17 00:00:00 2001 From: Tim Lind Date: Tue, 22 Feb 2022 13:17:48 +0200 Subject: [PATCH 011/275] fix: classify client states without consensus states as expired (#941) ## Description closes: #850 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- modules/core/02-client/keeper/grpc_query_test.go | 2 +- modules/light-clients/07-tendermint/types/client_state.go | 4 +++- .../light-clients/07-tendermint/types/client_state_test.go | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index f4fa3c59322..5e393c33a97 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -452,7 +452,7 @@ func (suite *KeeperTestSuite) TestQueryClientStatus() { ClientId: path.EndpointA.ClientID, } }, - true, exported.Unknown.String(), + true, exported.Expired.String(), }, { "Frozen client status", diff --git a/modules/light-clients/07-tendermint/types/client_state.go b/modules/light-clients/07-tendermint/types/client_state.go index a0430337d0b..51f826979fd 100644 --- a/modules/light-clients/07-tendermint/types/client_state.go +++ b/modules/light-clients/07-tendermint/types/client_state.go @@ -78,7 +78,9 @@ func (cs ClientState) Status( // get latest consensus state from clientStore to check for expiry consState, err := GetConsensusState(clientStore, cdc, cs.GetLatestHeight()) if err != nil { - return exported.Unknown + // if the client state does not have an associated consensus state for its latest height + // then it must be expired + return exported.Expired } if cs.IsExpired(consState.Timestamp, ctx.BlockTime()) { diff --git a/modules/light-clients/07-tendermint/types/client_state_test.go b/modules/light-clients/07-tendermint/types/client_state_test.go index b0434579b76..cf52d2996b5 100644 --- a/modules/light-clients/07-tendermint/types/client_state_test.go +++ b/modules/light-clients/07-tendermint/types/client_state_test.go @@ -47,10 +47,10 @@ func (suite *TendermintTestSuite) TestStatus() { clientState.FrozenHeight = clienttypes.NewHeight(0, 1) path.EndpointA.SetClientState(clientState) }, exported.Frozen}, - {"client status is unknown", func() { + {"client status without consensus state", func() { clientState.LatestHeight = clientState.LatestHeight.Increment().(clienttypes.Height) path.EndpointA.SetClientState(clientState) - }, exported.Unknown}, + }, exported.Expired}, {"client status is expired", func() { suite.coordinator.IncrementTimeBy(clientState.TrustingPeriod) }, exported.Expired}, From 01cd4adf5cbaf5970ac3cdc989fe8d2d5817e357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 22 Feb 2022 16:58:40 +0100 Subject: [PATCH 012/275] chore: fix broken link (#972) --- docs/ibc/relayer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ibc/relayer.md b/docs/ibc/relayer.md index c846f2c7320..ce3fabe252d 100644 --- a/docs/ibc/relayer.md +++ b/docs/ibc/relayer.md @@ -27,7 +27,7 @@ a module event emission with the attribute value `ibc_` (02-clien ### Subscribing with Tendermint -Calling the Tendermint RPC method `Subscribe` via [Tendermint's Websocket](https://docs.tendermint.com/master/rpc/) will return events using +Calling the Tendermint RPC method `Subscribe` via [Tendermint's Websocket](https://docs.tendermint.com/v0.35/rpc/) will return events using Tendermint's internal representation of them. Instead of receiving back a list of events as they were emitted, Tendermint will return the type `map[string][]string` which maps a string in the form `.` to `attribute_value`. This causes extraction of the event From 9fcf2543b4af13af6b2941ff9a4bd6d0f9e4e44c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 22 Feb 2022 22:58:29 +0100 Subject: [PATCH 013/275] add backport actions for v1.3.x and v2.1.x (#958) --- .github/mergify.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/mergify.yml b/.github/mergify.yml index 83b6f2d771c..5d1dca08360 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -26,7 +26,7 @@ pull_request_rules: backport: branches: - release/v1.1.x - - name: backport patches to v1.2x branch + - name: backport patches to v1.2.x branch conditions: - base=main - label=backport-to-v1.2.x @@ -34,6 +34,14 @@ pull_request_rules: backport: branches: - release/v1.2.x + - name: backport patches to v1.3.x branch + conditions: + - base=main + - label=backport-to-v1.3.x + actions: + backport: + branches: + - release/v1.3.x - name: backport patches to v2.0.x branch conditions: - base=main @@ -42,6 +50,14 @@ pull_request_rules: backport: branches: - release/v2.0.x + - name: backport patches to v2.1.x branch + conditions: + - base=main + - label=backport-to-v2.1.x + actions: + backport: + branches: + - release/v2.1.x - name: backport patches to v3.0.x branch conditions: - base=main @@ -49,4 +65,4 @@ pull_request_rules: actions: backport: branches: - - release/v3.0.x \ No newline at end of file + - release/v3.0.x From 08d38d4df63ecf2a28e3686188fd2b43c7271ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 23 Feb 2022 13:57:33 +0100 Subject: [PATCH 014/275] Revert "feat: adding Pack/Unpack acknowledgement helper fns (#895)" (#973) This reverts commit 843b459635da8cedd92945141c4efe3a762f305d. Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- CHANGELOG.md | 2 - modules/core/04-channel/types/codec.go | 34 ------------ modules/core/04-channel/types/codec_test.go | 58 --------------------- 3 files changed, 94 deletions(-) delete mode 100644 modules/core/04-channel/types/codec_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index cc1cf2a5972..90f8e4b0af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,8 +80,6 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#432](https://github.com/cosmos/ibc-go/pull/432) Introduce `MockIBCApp` struct to the mock module. Allows the mock module to be reused to perform custom logic on each IBC App interface function. This might be useful when testing out IBC applications written as middleware. * [\#380](https://github.com/cosmos/ibc-go/pull/380) Adding the Interchain Accounts module v1 * [\#679](https://github.com/cosmos/ibc-go/pull/679) New CLI command `query ibc-transfer denom-hash ` to get the denom hash for a denom trace; this might be useful for debug -* (channel) [\#895](https://github.com/cosmos/ibc-go/pull/895) Adding UnpackAcknowledgement and PackAcknowledgement helper functions to pack or unpack an Acknowledgement to and from a proto Any type - ### Bug Fixes diff --git a/modules/core/04-channel/types/codec.go b/modules/core/04-channel/types/codec.go index f77cd90c051..8981417130b 100644 --- a/modules/core/04-channel/types/codec.go +++ b/modules/core/04-channel/types/codec.go @@ -4,9 +4,7 @@ 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/msgservice" - proto "github.com/gogo/protobuf/proto" "github.com/cosmos/ibc-go/v3/modules/core/exported" ) @@ -52,35 +50,3 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { // The actual codec used for serialization should be provided to x/ibc/core/04-channel and // defined at the application level. var SubModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) - -// UnpackAcknowledgement unpacks an Any into an Acknowledgement. It returns an error if the -// Any can't be unpacked into an Acknowledgement. -func UnpackAcknowledgement(any *codectypes.Any) (exported.Acknowledgement, error) { - if any == nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrUnpackAny, "protobuf Any message cannot be nil") - } - - ack, ok := any.GetCachedValue().(exported.Acknowledgement) - if !ok { - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnpackAny, "cannot unpack Any into Acknowledgement %T", any) - } - - return ack, nil -} - -// PackAcknowledgement constructs a new Any packed with the given acknowledgement value. It returns -// an error if the acknowledgement can't be casted to a protobuf message or if the concrete -// implemention is not registered to the protobuf codec. -func PackAcknowledgement(acknowledgement exported.Acknowledgement) (*codectypes.Any, error) { - msg, ok := acknowledgement.(proto.Message) - if !ok { - return nil, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "cannot proto marshal %T", acknowledgement) - } - - anyAcknowledgement, err := codectypes.NewAnyWithValue(msg) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, err.Error()) - } - - return anyAcknowledgement, nil -} diff --git a/modules/core/04-channel/types/codec_test.go b/modules/core/04-channel/types/codec_test.go deleted file mode 100644 index bb0c8b81ddb..00000000000 --- a/modules/core/04-channel/types/codec_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package types_test - -import ( - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" -) - -type caseAny struct { - name string - any *codectypes.Any - expPass bool -} - -func (suite *TypesTestSuite) TestPackAcknowledgement() { - - testCases := []struct { - name string - acknowledgement exported.Acknowledgement - expPass bool - }{ - { - "success", - &ibcmock.MockAcknowledgement, - true, - }, - { - "nil", - nil, - false, - }, - } - - testCasesAny := []caseAny{} - - for _, tc := range testCases { - ackAny, err := types.PackAcknowledgement(tc.acknowledgement) - if tc.expPass { - suite.Require().NoError(err, tc.name) - } else { - suite.Require().Error(err, tc.name) - } - - testCasesAny = append(testCasesAny, caseAny{tc.name, ackAny, tc.expPass}) - } - - for i, tc := range testCasesAny { - cs, err := types.UnpackAcknowledgement(tc.any) - if tc.expPass { - suite.Require().NoError(err, tc.name) - suite.Require().Equal(testCases[i].acknowledgement, cs, tc.name) - } else { - suite.Require().Error(err, tc.name) - } - } -} From ef34765e7010ec5f526a44587de4be0e2afbde12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 23 Feb 2022 15:54:01 +0100 Subject: [PATCH 015/275] chore: update migration docs (#985) * chore: update migration docs * Update docs/migrations/v2-to-v3.md Co-authored-by: Damian Nolan Co-authored-by: Damian Nolan --- docs/migrations/v2-to-v3.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index fb47615d0f7..f2352ce9b05 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -55,6 +55,32 @@ app.UpgradeKeeper.SetUpgradeHandler("v3", The host and controller submodule params only need to be set if you integrate those submodules. For example, if a chain chooses not to integrate a controller submodule, it does not need to set the controller params. +### Genesis migrations + +If the chain will adopt ICS27 and chooses to upgrade via a genesis export, then the ICS27 parameters must be set during genesis migration. + +The migration code required may look like: + +```go + controllerGenesisState := icatypes.DefaultControllerGenesis() + // overwrite parameters as desired + controllerGenesisState.Params = icacontrollertypes.Params{ + ControllerEnabled: true, + } + + hostGenesisState := icatypes.DefaultHostGenesis() + // overwrite parameters as desired + hostGenesisState.Params = icahosttypes.Params{ + HostEnabled: true, + AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...], + } + + icaGenesisState := icatypes.NewGenesisState(controllerGenesisState, hostGenesisState) + + // set new ics27 genesis state + appState[icatypes.ModuleName] = clientCtx.JSONCodec.MustMarshalJSON(icaGenesisState) +``` + ## IBC Apps @@ -91,6 +117,10 @@ As apart of this release, the mock module now supports middleware testing. Pleas Please review the [mock](../../testing/mock/ibc_module.go) and [transfer](../../modules/apps/transfer/ibc_module.go) modules as examples. Additionally, [simapp](../../testing/simapp/app.go) provides an example of how `IBCModule` types should now be added to the IBC router in favour of `AppModule`. +### IBC testing package + +`TestChain`s are now created with chainID's beginning from an index of 1. Any calls to `GetChainID(0)` will now fail. Please increment all calls to `GetChainID` by 1. + ## Relayers `AppVersion` gRPC has been removed. From 556cc01ad9516d8455e3abc06e2fc7f6d7533bff Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 24 Feb 2022 12:45:46 +0100 Subject: [PATCH 016/275] chore: fix mispelled words (#991) --- modules/apps/transfer/ibc_module.go | 2 +- modules/core/04-channel/keeper/keeper.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 26f1c533434..c784a91e933 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -162,7 +162,7 @@ func (im IBCModule) OnChanCloseConfirm( } // OnRecvPacket implements the IBCModule interface. A successful acknowledgement -// is returned if the packet data is succesfully decoded and the receive application +// is returned if the packet data is successfully decoded and the receive application // logic returns without error. func (im IBCModule) OnRecvPacket( ctx sdk.Context, diff --git a/modules/core/04-channel/keeper/keeper.go b/modules/core/04-channel/keeper/keeper.go index d1ea53ac180..65378039ad9 100644 --- a/modules/core/04-channel/keeper/keeper.go +++ b/modules/core/04-channel/keeper/keeper.go @@ -403,7 +403,7 @@ func (k Keeper) GetChannelClientState(ctx sdk.Context, portID, channelID string) return connection.ClientId, clientState, nil } -// GetConnection wraps the conenction keeper's GetConnection function. +// GetConnection wraps the connection keeper's GetConnection function. func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (exported.ConnectionI, error) { connection, found := k.connectionKeeper.GetConnection(ctx, connectionID) if !found { From 04ab3cb3316072e701e0ba078e12622fa71d9727 Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 24 Feb 2022 21:27:54 +0100 Subject: [PATCH 017/275] fix: remove go mod tidy from proto-gen script (#989) --- scripts/protocgen.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index 1015709e861..efcfb36b30a 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -32,8 +32,6 @@ buf protoc \ --doc_out=./docs/ibc \ --doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ $(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') -go mod tidy - # move proto files to the right places cp -r github.com/cosmos/ibc-go/v*/modules/* modules/ From 4545154cc60db44a26dadec2e2b2422bd138f5d1 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 28 Feb 2022 11:17:38 +0100 Subject: [PATCH 018/275] bug: support base denoms with slashes (#978) * bug: support base denoms with slashes * add changelog entry Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 1 + modules/apps/transfer/types/msgs_test.go | 2 +- modules/apps/transfer/types/trace.go | 18 +++++++++--------- modules/apps/transfer/types/trace_test.go | 5 +++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90f8e4b0af4..4508636a8c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,6 +84,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * (testing) [\#884](https://github.com/cosmos/ibc-go/pull/884) Add and use in simapp a custom ante handler that rejects redundant transactions +* (transfer) [\#978](https://github.com/cosmos/ibc-go/pull/978) Support base denoms with slashes in denom validation ## [v2.0.2](https://github.com/cosmos/ibc-go/releases/tag/v2.0.2) - 2021-12-15 diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index 5cf074a6d8d..00570ac15ed 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -32,7 +32,7 @@ var ( coin = sdk.NewCoin("atom", sdk.NewInt(100)) ibcCoin = sdk.NewCoin("ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(100)) - invalidIBCCoin = sdk.NewCoin("notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(100)) + invalidIBCCoin = sdk.NewCoin("ibc/7F1D3FCF4AE79E1554", sdk.NewInt(100)) invalidDenomCoin = sdk.Coin{Denom: "0atom", Amount: sdk.NewInt(100)} zeroCoin = sdk.Coin{Denom: "atoms", Amount: sdk.NewInt(0)} diff --git a/modules/apps/transfer/types/trace.go b/modules/apps/transfer/types/trace.go index 6bbbbadfc23..303ddd3769e 100644 --- a/modules/apps/transfer/types/trace.go +++ b/modules/apps/transfer/types/trace.go @@ -162,7 +162,7 @@ func ValidatePrefixedDenom(denom string) error { // ValidateIBCDenom validates that the given denomination is either: // -// - A valid base denomination (eg: 'uatom') +// - A valid base denomination (eg: 'uatom' or 'gamm/pool/1' as in https://github.com/cosmos/ibc-go/issues/894) // - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-001-coin-source-tracing.md func ValidateIBCDenom(denom string) error { if err := sdk.ValidateDenom(denom); err != nil { @@ -172,17 +172,17 @@ func ValidateIBCDenom(denom string) error { denomSplit := strings.SplitN(denom, "/", 2) switch { - case strings.TrimSpace(denom) == "", - len(denomSplit) == 1 && denomSplit[0] == DenomPrefix, - len(denomSplit) == 2 && (denomSplit[0] != DenomPrefix || strings.TrimSpace(denomSplit[1]) == ""): + case denom == DenomPrefix: return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) - case denomSplit[0] == denom && strings.TrimSpace(denom) != "": - return nil - } + case len(denomSplit) == 2 && denomSplit[0] == DenomPrefix: + if strings.TrimSpace(denomSplit[1]) == "" { + return sdkerrors.Wrapf(ErrInvalidDenomForTransfer, "denomination should be prefixed with the format 'ibc/{hash(trace + \"/\" + %s)}'", denom) + } - if _, err := ParseHexHash(denomSplit[1]); err != nil { - return sdkerrors.Wrapf(err, "invalid denom trace hash %s", denomSplit[1]) + if _, err := ParseHexHash(denomSplit[1]); err != nil { + return sdkerrors.Wrapf(err, "invalid denom trace hash %s", denomSplit[1]) + } } return nil diff --git a/modules/apps/transfer/types/trace_test.go b/modules/apps/transfer/types/trace_test.go index f0868d5680e..e35fd33317b 100644 --- a/modules/apps/transfer/types/trace_test.go +++ b/modules/apps/transfer/types/trace_test.go @@ -131,11 +131,12 @@ func TestValidateIBCDenom(t *testing.T) { }{ {"denom with trace hash", "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", false}, {"base denom", "uatom", false}, + {"base denom with single '/'s", "gamm/pool/1", false}, + {"base denom with double '/'s", "gamm//pool//1", false}, + {"non-ibc prefix with hash", "notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", false}, {"empty denom", "", true}, - {"invalid prefixed denom", "transfer/channelToA/uatom", true}, {"denom 'ibc'", "ibc", true}, {"denom 'ibc/'", "ibc/", true}, - {"invald prefix", "notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", true}, {"invald hash", "ibc/!@#$!@#", true}, } From 9d8be7cbab5cb1987449ff92fa2376c1ca44ac30 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 28 Feb 2022 13:40:23 +0100 Subject: [PATCH 019/275] upgrade ics23 to v0.7 (#948) * upgrade ics23 to v0.7-rc * add changelog entry * update ics23 to final 0.7 Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 1 + go.mod | 2 +- go.sum | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4508636a8c3..16334bd3c98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#404](https://github.com/cosmos/ibc-go/pull/404) Bump Go version to 1.17 * [\#851](https://github.com/cosmos/ibc-go/pull/851) Bump SDK version to v0.45.1 +* [\#948](https://github.com/cosmos/ibc-go/pull/948) Bump ics23/go to v0.7 * (core) [\#709](https://github.com/cosmos/ibc-go/pull/709) Replace github.com/pkg/errors with stdlib errors ### API Breaking diff --git a/go.mod b/go.mod index 639c5607ced..eb9dc1a9548 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alp require ( github.com/armon/go-metrics v0.3.10 - github.com/confio/ics23/go v0.6.6 + github.com/confio/ics23/go v0.7.0 github.com/cosmos/cosmos-sdk v0.45.1 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 diff --git a/go.sum b/go.sum index 25a2e5dd4c4..9caa6a21997 100644 --- a/go.sum +++ b/go.sum @@ -184,8 +184,9 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg= github.com/coinbase/rosetta-sdk-go v0.7.0/go.mod h1:7nD3oBPIiHqhRprqvMgPoGxe/nyq3yftRmpsy29coWE= -github.com/confio/ics23/go v0.6.6 h1:pkOy18YxxJ/r0XFDCnrl4Bjv6h4LkBSpLS6F38mrKL8= github.com/confio/ics23/go v0.6.6/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= +github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8= +github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 h1:NmTXa/uVnDyp0TY5MKi197+3HWcnYWfnHGyaFthlnGw= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= From 6d6888b9c5cffc6b9c0f09ec5f77a8932d0b7e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Mon, 28 Feb 2022 10:59:59 -0300 Subject: [PATCH 020/275] ibctesting: make `testing.T` public (#1020) --- testing/chain.go | 41 +++++++++++++++++++---------------------- testing/coordinator.go | 26 +++++++++++++------------- testing/endpoint.go | 31 ++++++++++++++----------------- 3 files changed, 46 insertions(+), 52 deletions(-) diff --git a/testing/chain.go b/testing/chain.go index 89e5b5cb308..4199595c1b9 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -36,9 +36,7 @@ import ( "github.com/cosmos/ibc-go/v3/testing/simapp" ) -var ( - MaxAccounts = 10 -) +var MaxAccounts = 10 type SenderAccount struct { SenderPrivKey cryptotypes.PrivKey @@ -51,7 +49,7 @@ type SenderAccount struct { // is used for delivering transactions through the application state. // NOTE: the actual application uses an empty chain-id for ease of testing. type TestChain struct { - t *testing.T + *testing.T Coordinator *Coordinator App TestingApp @@ -88,7 +86,6 @@ type TestChain struct { // CONTRACT: Validator and signer array must be provided in the order expected by Tendermint. // i.e. sorted first by power and then lexicographically by address. func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) *TestChain { - genAccs := []authtypes.GenesisAccount{} genBals := []banktypes.Balance{} senderAccs := []SenderAccount{} @@ -129,7 +126,7 @@ func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, va // create an account to send transactions from chain := &TestChain{ - t: t, + T: t, Coordinator: coord, ChainID: chainID, App: app, @@ -191,7 +188,7 @@ func (chain *TestChain) GetContext() sdk.Context { // their own SimApp. func (chain *TestChain) GetSimApp() *simapp.SimApp { app, ok := chain.App.(*simapp.SimApp) - require.True(chain.t, ok) + require.True(chain.T, ok) return app } @@ -213,10 +210,10 @@ func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, cl }) merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) - require.NoError(chain.t, err) + require.NoError(chain.T, err) proof, err := chain.App.AppCodec().Marshal(&merkleProof) - require.NoError(chain.t, err) + require.NoError(chain.T, err) revision := clienttypes.ParseChainID(chain.ChainID) @@ -237,10 +234,10 @@ func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, cl }) merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) - require.NoError(chain.t, err) + require.NoError(chain.T, err) proof, err := chain.App.AppCodec().Marshal(&merkleProof) - require.NoError(chain.t, err) + require.NoError(chain.T, err) revision := clienttypes.ParseChainID(chain.ChainID) @@ -300,7 +297,7 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) { chain.Coordinator.UpdateTimeForChain(chain) _, r, err := simapp.SignAndDeliver( - chain.t, + chain.T, chain.TxConfig, chain.App.GetBaseApp(), chain.GetContext().BlockHeader(), @@ -329,7 +326,7 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) { // expected to exist otherwise testing will fail. func (chain *TestChain) GetClientState(clientID string) exported.ClientState { clientState, found := chain.App.GetIBCKeeper().ClientKeeper.GetClientState(chain.GetContext(), clientID) - require.True(chain.t, found) + require.True(chain.T, found) return clientState } @@ -361,7 +358,7 @@ func (chain *TestChain) GetValsAtHeight(height int64) (*tmtypes.ValidatorSet, bo // acknowledgement does not exist then testing will fail. func (chain *TestChain) GetAcknowledgement(packet exported.PacketI) []byte { ack, found := chain.App.GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) - require.True(chain.t, found) + require.True(chain.T, found) return ack } @@ -436,7 +433,7 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, valSet *tmproto.ValidatorSet trustedVals *tmproto.ValidatorSet ) - require.NotNil(chain.t, tmValSet) + require.NotNil(chain.T, tmValSet) vsetHash := tmValSet.Hash() @@ -461,7 +458,7 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, voteSet := tmtypes.NewVoteSet(chainID, blockHeight, 1, tmproto.PrecommitType, tmValSet) commit, err := tmtypes.MakeCommit(blockID, blockHeight, 1, voteSet, signers, timestamp) - require.NoError(chain.t, err) + require.NoError(chain.T, err) signedHeader := &tmproto.SignedHeader{ Header: tmHeader.ToProto(), @@ -533,11 +530,11 @@ func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.Scope if !ok { // create capability using the IBC capability keeper cap, err := chain.App.GetScopedIBCKeeper().NewCapability(chain.GetContext(), host.PortPath(portID)) - require.NoError(chain.t, err) + require.NoError(chain.T, err) // claim capability using the scopedKeeper err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, host.PortPath(portID)) - require.NoError(chain.t, err) + require.NoError(chain.T, err) } chain.App.Commit() @@ -549,7 +546,7 @@ func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.Scope // exist, otherwise testing will fail. func (chain *TestChain) GetPortCapability(portID string) *capabilitytypes.Capability { cap, ok := chain.App.GetScopedIBCKeeper().GetCapability(chain.GetContext(), host.PortPath(portID)) - require.True(chain.t, ok) + require.True(chain.T, ok) return cap } @@ -563,9 +560,9 @@ func (chain *TestChain) CreateChannelCapability(scopedKeeper capabilitykeeper.Sc _, ok := chain.App.GetScopedIBCKeeper().GetCapability(chain.GetContext(), capName) if !ok { cap, err := chain.App.GetScopedIBCKeeper().NewCapability(chain.GetContext(), capName) - require.NoError(chain.t, err) + require.NoError(chain.T, err) err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, capName) - require.NoError(chain.t, err) + require.NoError(chain.T, err) } chain.App.Commit() @@ -577,7 +574,7 @@ func (chain *TestChain) CreateChannelCapability(scopedKeeper capabilitykeeper.Sc // The capability must exist, otherwise testing will fail. func (chain *TestChain) GetChannelCapability(portID, channelID string) *capabilitytypes.Capability { cap, ok := chain.App.GetScopedIBCKeeper().GetCapability(chain.GetContext(), host.ChannelCapabilityPath(portID, channelID)) - require.True(chain.t, ok) + require.True(chain.T, ok) return cap } diff --git a/testing/coordinator.go b/testing/coordinator.go index be308c790d5..5a7a91650fc 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -19,7 +19,7 @@ var ( // Coordinator is a testing struct which contains N TestChain's. It handles keeping all chains // in sync with regards to time. type Coordinator struct { - t *testing.T + *testing.T CurrentTime time.Time Chains map[string]*TestChain @@ -29,7 +29,7 @@ type Coordinator struct { func NewCoordinator(t *testing.T, n int) *Coordinator { chains := make(map[string]*TestChain) coord := &Coordinator{ - t: t, + T: t, CurrentTime: globalStartTime, } @@ -84,10 +84,10 @@ func (coord *Coordinator) Setup(path *Path) { // caller does not anticipate any errors. func (coord *Coordinator) SetupClients(path *Path) { err := path.EndpointA.CreateClient() - require.NoError(coord.t, err) + require.NoError(coord.T, err) err = path.EndpointB.CreateClient() - require.NoError(coord.t, err) + require.NoError(coord.T, err) } // SetupClientConnections is a helper function to create clients and the appropriate @@ -105,16 +105,16 @@ func (coord *Coordinator) SetupConnections(path *Path) { // successfully opened otherwise testing will fail. func (coord *Coordinator) CreateConnections(path *Path) { err := path.EndpointA.ConnOpenInit() - require.NoError(coord.t, err) + require.NoError(coord.T, err) err = path.EndpointB.ConnOpenTry() - require.NoError(coord.t, err) + require.NoError(coord.T, err) err = path.EndpointA.ConnOpenAck() - require.NoError(coord.t, err) + require.NoError(coord.T, err) err = path.EndpointB.ConnOpenConfirm() - require.NoError(coord.t, err) + require.NoError(coord.T, err) // ensure counterparty is up to date path.EndpointA.UpdateClient() @@ -146,16 +146,16 @@ func (coord *Coordinator) CreateTransferChannels(path *Path) { // opened otherwise testing will fail. func (coord *Coordinator) CreateChannels(path *Path) { err := path.EndpointA.ChanOpenInit() - require.NoError(coord.t, err) + require.NoError(coord.T, err) err = path.EndpointB.ChanOpenTry() - require.NoError(coord.t, err) + require.NoError(coord.T, err) err = path.EndpointA.ChanOpenAck() - require.NoError(coord.t, err) + require.NoError(coord.T, err) err = path.EndpointB.ChanOpenConfirm() - require.NoError(coord.t, err) + require.NoError(coord.T, err) // ensure counterparty is up to date path.EndpointA.UpdateClient() @@ -165,7 +165,7 @@ func (coord *Coordinator) CreateChannels(path *Path) { // not exist. func (coord *Coordinator) GetChain(chainID string) *TestChain { chain, found := coord.Chains[chainID] - require.True(coord.t, found, fmt.Sprintf("%s chain does not exist", chainID)) + require.True(coord.T, found, fmt.Sprintf("%s chain does not exist", chainID)) return chain } diff --git a/testing/endpoint.go b/testing/endpoint.go index 962ecf5ef35..5d496494afc 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -88,7 +88,7 @@ func (endpoint *Endpoint) CreateClient() (err error) { switch endpoint.ClientConfig.GetClientType() { case exported.Tendermint: tmConfig, ok := endpoint.ClientConfig.(*TendermintConfig) - require.True(endpoint.Chain.t, ok) + require.True(endpoint.Chain.T, ok) height := endpoint.Counterparty.Chain.LastHeader.GetHeight().(clienttypes.Height) clientState = ibctmtypes.NewClientState( @@ -98,7 +98,7 @@ func (endpoint *Endpoint) CreateClient() (err error) { consensusState = endpoint.Counterparty.Chain.LastHeader.ConsensusState() case exported.Solomachine: // TODO - // solo := NewSolomachine(chain.t, endpoint.Chain.Codec, clientID, "", 1) + // solo := NewSolomachine(Chain.T, endpoint.Chain.Codec, clientID, "", 1) // clientState = solo.ClientState() // consensusState = solo.ConsensusState() @@ -113,7 +113,7 @@ func (endpoint *Endpoint) CreateClient() (err error) { msg, err := clienttypes.NewMsgCreateClient( clientState, consensusState, endpoint.Chain.SenderAccount.GetAddress().String(), ) - require.NoError(endpoint.Chain.t, err) + require.NoError(endpoint.Chain.T, err) res, err := endpoint.Chain.SendMsgs(msg) if err != nil { @@ -121,7 +121,7 @@ func (endpoint *Endpoint) CreateClient() (err error) { } endpoint.ClientID, err = ParseClientIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.t, err) + require.NoError(endpoint.Chain.T, err) return nil } @@ -131,9 +131,7 @@ func (endpoint *Endpoint) UpdateClient() (err error) { // ensure counterparty has committed state endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) - var ( - header exported.Header - ) + var header exported.Header switch endpoint.ClientConfig.GetClientType() { case exported.Tendermint: @@ -151,10 +149,9 @@ func (endpoint *Endpoint) UpdateClient() (err error) { endpoint.ClientID, header, endpoint.Chain.SenderAccount.GetAddress().String(), ) - require.NoError(endpoint.Chain.t, err) + require.NoError(endpoint.Chain.T, err) return endpoint.Chain.sendMsgs(msg) - } // ConnOpenInit will construct and execute a MsgConnectionOpenInit on the associated endpoint. @@ -171,7 +168,7 @@ func (endpoint *Endpoint) ConnOpenInit() error { } endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.t, err) + require.NoError(endpoint.Chain.T, err) return nil } @@ -197,7 +194,7 @@ func (endpoint *Endpoint) ConnOpenTry() error { if endpoint.ConnectionID == "" { endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.t, err) + require.NoError(endpoint.Chain.T, err) } return nil @@ -277,7 +274,7 @@ func (endpoint *Endpoint) ChanOpenInit() error { } endpoint.ChannelID, err = ParseChannelIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.t, err) + require.NoError(endpoint.Chain.T, err) return nil } @@ -303,7 +300,7 @@ func (endpoint *Endpoint) ChanOpenTry() error { if endpoint.ChannelID == "" { endpoint.ChannelID, err = ParseChannelIDFromEvents(res.GetEvents()) - require.NoError(endpoint.Chain.t, err) + require.NoError(endpoint.Chain.T, err) } // update version to selected app version @@ -449,7 +446,7 @@ func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) - require.True(endpoint.Chain.t, found) + require.True(endpoint.Chain.T, found) timeoutMsg := channeltypes.NewMsgTimeout( packet, nextSeqRecv, @@ -486,7 +483,7 @@ func (endpoint *Endpoint) SetClientState(clientState exported.ClientState) { // The consensus state is expected to exist otherwise testing will fail. func (endpoint *Endpoint) GetConsensusState(height exported.Height) exported.ConsensusState { consensusState, found := endpoint.Chain.GetConsensusState(endpoint.ClientID, height) - require.True(endpoint.Chain.t, found) + require.True(endpoint.Chain.T, found) return consensusState } @@ -500,7 +497,7 @@ func (endpoint *Endpoint) SetConsensusState(consensusState exported.ConsensusSta // connection is expected to exist otherwise testing will fail. func (endpoint *Endpoint) GetConnection() connectiontypes.ConnectionEnd { connection, found := endpoint.Chain.App.GetIBCKeeper().ConnectionKeeper.GetConnection(endpoint.Chain.GetContext(), endpoint.ConnectionID) - require.True(endpoint.Chain.t, found) + require.True(endpoint.Chain.T, found) return connection } @@ -514,7 +511,7 @@ func (endpoint *Endpoint) SetConnection(connection connectiontypes.ConnectionEnd // is expected to exist otherwise testing will fail. func (endpoint *Endpoint) GetChannel() channeltypes.Channel { channel, found := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) - require.True(endpoint.Chain.t, found) + require.True(endpoint.Chain.T, found) return channel } From e1be19b44950de2de1de68e57d8890aa111f378d Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 1 Mar 2022 10:08:56 +0100 Subject: [PATCH 021/275] add changelog entry for #941 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16334bd3c98..c66af261da1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (testing) [\#884](https://github.com/cosmos/ibc-go/pull/884) Add and use in simapp a custom ante handler that rejects redundant transactions * (transfer) [\#978](https://github.com/cosmos/ibc-go/pull/978) Support base denoms with slashes in denom validation +* (client) [\#941](https://github.com/cosmos/ibc-go/pull/941) Classify client states without consensus states as expired ## [v2.0.2](https://github.com/cosmos/ibc-go/releases/tag/v2.0.2) - 2021-12-15 From f994d1e7aefa653c18b87f58099a7805b83946ef Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 1 Mar 2022 12:36:41 +0100 Subject: [PATCH 022/275] fix package import (#1007) --- modules/apps/transfer/types/ack_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/types/ack_test.go b/modules/apps/transfer/types/ack_test.go index bc4e2d07afc..4f4c3a874d7 100644 --- a/modules/apps/transfer/types/ack_test.go +++ b/modules/apps/transfer/types/ack_test.go @@ -9,7 +9,7 @@ import ( tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" tmstate "github.com/tendermint/tendermint/state" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" ) From 147e0f1954ede691bb977ff185b9d0500ec4bd0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 1 Mar 2022 16:16:35 +0100 Subject: [PATCH 023/275] feat: Add a function to initialize the ICS27 module via an upgrade proposal (#1037) ## Description closes: #1034 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- CHANGELOG.md | 1 + docs/migrations/v2-to-v3.md | 25 ++++--- modules/apps/27-interchain-accounts/module.go | 13 ++++ .../27-interchain-accounts/module_test.go | 74 +++++++++++++++++++ testing/simapp/app.go | 6 ++ 5 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/module_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index c66af261da1..3267e5fd78c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (interchain-accounts) [\#1037](https://github.com/cosmos/ibc-go/pull/1037) Add a function `InitModule` to the interchain accounts `AppModule`. This function should be called within the upgrade handler when adding the interchain accounts module to a chain. It should be called in place of InitGenesis (set the consensus version in the version map). * (testing) [\#942](https://github.com/cosmos/ibc-go/pull/942) `NewTestChain` will create 4 validators in validator set by default. A new constructor function `NewTestChainWithValSet` is provided for test writers who want custom control over the validator set of test chains. * (testing) [\#904](https://github.com/cosmos/ibc-go/pull/904) Add `ParsePacketFromEvents` function to the testing package. Useful when sending/relaying packets via the testing package. * (testing) [\#893](https://github.com/cosmos/ibc-go/pull/893) Support custom private keys for testing. diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index f2352ce9b05..434a6f435f6 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -33,17 +33,24 @@ Please see the [ICS27 documentation](../apps/interchain-accounts/overview.md) fo If the chain will adopt ICS27, it must set the appropriate params during the execution of the upgrade handler in `app.go`: ```go app.UpgradeKeeper.SetUpgradeHandler("v3", - func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - // set ICS27 Host submodule params - app.ICAHostKeeper.SetParams(ctx, icahosttypes.Params{ - HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...], - }) + func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + // set the ICS27 consensus version so InitGenesis is not run + fromVM[icatypes.ModuleName] = icamodule.ConsensusVersion() - // set ICS27 Controller submodule params - app.ICAControllerKeeper.SetParams(ctx, icacontrollertypes.Params{ + + // create ICS27 Controller submodule params + controllerParams := icacontrollertypes.Params{ ControllerEnabled: true, - }) + } + + // create ICS27 Host submodule params + hostParams := icahosttypes.Params{ + HostEnabled: true, + AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...], + } + + // initialize ICS27 module + icamodule.InitModule(ctx, controllerParams, hostParams) ... diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index b11c611e0c9..969c07caf9d 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -24,6 +24,7 @@ import ( hosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" ) var ( @@ -101,6 +102,18 @@ func NewAppModule(controllerKeeper *controllerkeeper.Keeper, hostKeeper *hostkee } } +// InitModule will initialize the interchain accounts moudule. It should only be +// called once and as an alternative to InitGenesis. +func (am AppModule) InitModule(ctx sdk.Context, controllerParams controllertypes.Params, hostParams hosttypes.Params) { + am.controllerKeeper.SetParams(ctx, controllerParams) + am.hostKeeper.SetParams(ctx, hostParams) + + cap := am.hostKeeper.BindPort(ctx, types.PortID) + if err := am.hostKeeper.ClaimCapability(ctx, cap, ibchost.PortPath(types.PortID)); err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } +} + // RegisterInvariants implements the AppModule interface func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { } diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go new file mode 100644 index 00000000000..de5f51ae921 --- /dev/null +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -0,0 +1,74 @@ +package ica_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" + + ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" + controllertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" + hosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v3/testing/simapp" +) + +type InterchainAccountsTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator +} + +func TestICATestSuite(t *testing.T) { + suite.Run(t, new(InterchainAccountsTestSuite)) +} + +func (suite *InterchainAccountsTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) +} + +func (suite *InterchainAccountsTestSuite) TestInitModule() { + app := simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) + icamodule, ok := app.GetModuleManager().Modules[types.ModuleName].(ica.AppModule) + suite.Require().True(ok) + + header := tmproto.Header{ + ChainID: "testchain", + Height: 1, + Time: suite.coordinator.CurrentTime.UTC(), + } + + ctx := app.GetBaseApp().NewContext(true, header) + + // ensure params are not set + suite.Require().Panics(func() { + app.ICAControllerKeeper.GetParams(ctx) + }) + suite.Require().Panics(func() { + app.ICAHostKeeper.GetParams(ctx) + }) + + controllerParams := controllertypes.DefaultParams() + controllerParams.ControllerEnabled = true + + hostParams := hosttypes.DefaultParams() + expAllowMessages := []string{"sdk.Msg"} + hostParams.HostEnabled = true + hostParams.AllowMessages = expAllowMessages + + suite.Require().False(app.IBCKeeper.PortKeeper.IsBound(ctx, types.PortID)) + + icamodule.InitModule(ctx, controllerParams, hostParams) + + controllerParams = app.ICAControllerKeeper.GetParams(ctx) + suite.Require().True(controllerParams.ControllerEnabled) + + hostParams = app.ICAHostKeeper.GetParams(ctx) + suite.Require().True(hostParams.HostEnabled) + suite.Require().Equal(expAllowMessages, hostParams.AllowMessages) + + suite.Require().True(app.IBCKeeper.PortKeeper.IsBound(ctx, types.PortID)) +} diff --git a/testing/simapp/app.go b/testing/simapp/app.go index a2b78e7d260..15add30faaf 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -571,6 +571,12 @@ func (app *SimApp) ModuleAccountAddrs() map[string]bool { return modAccAddrs } +// GetModuleManager returns the app module manager +// NOTE: used for testing purposes +func (app *SimApp) GetModuleManager() *module.Manager { + return app.mm +} + // LegacyAmino returns SimApp's amino codec. // // NOTE: This is solely to be used for testing purposes as it may be desirable From f71a50585375b2fc002699dee80b71a682bb1bd0 Mon Sep 17 00:00:00 2001 From: daeMOn Date: Thu, 3 Mar 2022 12:04:02 +0100 Subject: [PATCH 024/275] docs: add missing args to NewKeeper in integration docs (#1038) ## Description This add some missing arguments to `ibckeeper.NewKeeper` and `ibctransferkeeper.NewKeeper` in integration docs --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- docs/ibc/integration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ibc/integration.md b/docs/ibc/integration.md index f823ffe07e4..09c1d2d2de9 100644 --- a/docs/ibc/integration.md +++ b/docs/ibc/integration.md @@ -92,13 +92,13 @@ func NewApp(...args) *App { // Create IBC Keeper app.IBCKeeper = ibckeeper.NewKeeper( - appCodec, keys[ibchost.StoreKey], app.StakingKeeper, scopedIBCKeeper, + appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, ) // Create Transfer Keepers app.TransferKeeper = ibctransferkeeper.NewKeeper( - appCodec, keys[ibctransfertypes.StoreKey], - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), + app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, ) transferModule := transfer.NewAppModule(app.TransferKeeper) From a55ca886b322ad3f9589ee5f9b9acfe150a2471c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 4 Mar 2022 12:05:06 +0100 Subject: [PATCH 025/275] small fixes for v2 to v3 migration (#1016) * small fixes for v2 to v3 migration * review comment * Update v2-to-v3.md * add store upgrade documentation Co-authored-by: Carlos Rodriguez --- docs/migrations/v2-to-v3.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index 434a6f435f6..beab128a1fd 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -36,7 +36,6 @@ app.UpgradeKeeper.SetUpgradeHandler("v3", func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { // set the ICS27 consensus version so InitGenesis is not run fromVM[icatypes.ModuleName] = icamodule.ConsensusVersion() - // create ICS27 Controller submodule params controllerParams := icacontrollertypes.Params{ @@ -46,7 +45,7 @@ app.UpgradeKeeper.SetUpgradeHandler("v3", // create ICS27 Host submodule params hostParams := icahosttypes.Params{ HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...], + AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, } // initialize ICS27 module @@ -62,6 +61,22 @@ app.UpgradeKeeper.SetUpgradeHandler("v3", The host and controller submodule params only need to be set if you integrate those submodules. For example, if a chain chooses not to integrate a controller submodule, it does not need to set the controller params. +#### Add `StoreUpgrades` for ICS27 module + +For ICS27 it is also necessary to [manually add store upgrades](https://docs.cosmos.network/v0.44/core/upgrade.html#add-storeupgrades-for-new-modules) for the new ICS27 module and then configure the store loader to apply those upgrades in `app.go`: + +```go +if upgradeInfo.Name == "v3" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + storeUpgrades := store.StoreUpgrades{ + Added: []string{icatypes.ModuleName}, + } + + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) +} +``` + +This ensures that the new module's stores are added to the multistore before the migrations begin. + ### Genesis migrations If the chain will adopt ICS27 and chooses to upgrade via a genesis export, then the ICS27 parameters must be set during genesis migration. @@ -79,7 +94,7 @@ The migration code required may look like: // overwrite parameters as desired hostGenesisState.Params = icahosttypes.Params{ HostEnabled: true, - AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...], + AllowMessages: []string{"/cosmos.bank.v1beta1.MsgSend", ...}, } icaGenesisState := icatypes.NewGenesisState(controllerGenesisState, hostGenesisState) From 029c6e93364899b970275dd898e4150bde5fce59 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 4 Mar 2022 14:33:48 +0100 Subject: [PATCH 026/275] add missing slash --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3267e5fd78c..3644cbeb7f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,7 +74,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#383](https://github.com/cosmos/ibc-go/pull/383) Adds helper functions for merging and splitting middleware versions from the underlying app version. * (modules/core/05-port) [\#288](https://github.com/cosmos/ibc-go/issues/288) Making the 05-port keeper function IsBound public. The IsBound function checks if the provided portID is already binded to a module. * (channel) [\#644](https://github.com/cosmos/ibc-go/pull/644) Adds `GetChannelConnection` to the ChannelKeeper. This function returns the connectionID and connection state associated with a channel. -* (channel) [\647](https://github.com/cosmos/ibc-go/pull/647) Reorganizes channel handshake handling to set channel state after IBC application callbacks. +* (channel) [\#647](https://github.com/cosmos/ibc-go/pull/647) Reorganizes channel handshake handling to set channel state after IBC application callbacks. * (client) [\#724](https://github.com/cosmos/ibc-go/pull/724) `IsRevisionFormat` and `IsClientIDFormat` have been updated to disallow newlines before the dash used to separate the chainID and revision number, and the client type and client sequence. ### Features From 7ae90c27fa1864cecb39b2d1712c0fd91d4dbacd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Mar 2022 10:30:03 +0000 Subject: [PATCH 027/275] build(deps): bump actions/checkout from 2.4.0 to 3 (#1045) Bumps [actions/checkout](https://github.com/actions/checkout) from 2.4.0 to 3.

Release notes

Sourced from actions/checkout's releases.

v3.0.0

  • Update default runtime to node16
Changelog

Sourced from actions/checkout's changelog.

Changelog

v2.3.1

v2.3.0

v2.2.0

v2.1.1

  • Changes to support GHES (here and here)

v2.1.0

v2.0.0

v2 (beta)

  • Improved fetch performance
    • The default behavior now fetches only the SHA being checked-out
  • Script authenticated git commands
    • Persists with.token in the local git config
    • Enables your scripts to run authenticated git commands
    • Post-job cleanup removes the token
    • Coming soon: Opt out by setting with.persist-credentials to false
  • Creates a local branch
    • No longer detached HEAD when checking out a branch
    • A local branch is created with the corresponding upstream branch set
  • Improved layout

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=2.4.0&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/check-docs.yml | 2 +- .github/workflows/link-check.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/check-docs.yml b/.github/workflows/check-docs.yml index abcaa066e2d..0060623ba15 100644 --- a/.github/workflows/check-docs.yml +++ b/.github/workflows/check-docs.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout 🛎️ - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/link-check.yml b/.github/workflows/link-check.yml index d40882e4fde..fdf8b184259 100644 --- a/.github/workflows/link-check.yml +++ b/.github/workflows/link-check.yml @@ -4,7 +4,7 @@ jobs: markdown-link-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v3 - uses: gaurav-nelson/github-action-markdown-link-check@v1 with: config-file: '.github/workflows/link-check-config.json' \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a1a1da8a340..ffffe3a4dae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3 with: fetch-depth: 0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 585a3653270..fdcc086ae4f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: matrix: go-arch: ["amd64", "arm", "arm64"] steps: - - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v3 - uses: actions/setup-go@v2.1.5 with: go-version: 1.17 @@ -54,7 +54,7 @@ jobs: split-test-files: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v3 - name: Create a file with all the pkgs run: go list ./... > pkgs.txt - name: Split pkgs into 4 files @@ -85,7 +85,7 @@ jobs: matrix: part: ["00", "01", "02", "03"] steps: - - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v3 - uses: actions/setup-go@v2.1.5 with: go-version: 1.17 @@ -112,7 +112,7 @@ jobs: runs-on: ubuntu-latest needs: tests steps: - - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v3 - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | From fc452ac42d06a0119d0035a524fe90dc8e4cd466 Mon Sep 17 00:00:00 2001 From: Joe Bowman Date: Mon, 7 Mar 2022 13:23:01 +0000 Subject: [PATCH 028/275] call packet.GetSequence() rather than passing the func as argument (#995) --- CHANGELOG.md | 1 + modules/core/04-channel/keeper/packet.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3644cbeb7f7..f9d669650a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (testing) [\#884](https://github.com/cosmos/ibc-go/pull/884) Add and use in simapp a custom ante handler that rejects redundant transactions * (transfer) [\#978](https://github.com/cosmos/ibc-go/pull/978) Support base denoms with slashes in denom validation * (client) [\#941](https://github.com/cosmos/ibc-go/pull/941) Classify client states without consensus states as expired +* (modules/core/04-channel) [\#994](https://github.com/cosmos/ibc-go/pull/944) Call `packet.GetSequence()` rather than passing func in `AcknowledgePacket` log output ## [v2.0.2](https://github.com/cosmos/ibc-go/releases/tag/v2.0.2) - 2021-12-15 diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index 5879c9ecb08..b54926b85e9 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -494,7 +494,7 @@ func (k Keeper) AcknowledgePacket( // log that a packet has been acknowledged k.Logger(ctx).Info( "packet acknowledged", - "sequence", packet.GetSequence, + "sequence", packet.GetSequence(), "src_port", packet.GetSourcePort(), "src_channel", packet.GetSourceChannel(), "dst_port", packet.GetDestPort(), From 13df199d70c4e3bd55419182270413491ee8a6d1 Mon Sep 17 00:00:00 2001 From: khanh <50263489+catShaark@users.noreply.github.com> Date: Wed, 9 Mar 2022 17:17:18 +0700 Subject: [PATCH 029/275] Add counterpartyChannelID param to IBCModule.OnChanOpenAck (#1086) * add counterpartyChannelID param to IBCModule OnChanOpenAck() * change testing mock * change ica IBCModules ChannelOpenAck * change transfer IBCModules ChannelOpenAck * change core keeper ChannelOpenAck() * CHANGELOG.md * update v2-to-v3 migration doc * Update docs/migrations/v2-to-v3.md Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 1 + docs/migrations/v2-to-v3.md | 4 ++++ modules/apps/27-interchain-accounts/controller/ibc_module.go | 3 ++- .../apps/27-interchain-accounts/controller/ibc_module_test.go | 4 ++-- modules/apps/27-interchain-accounts/host/ibc_module.go | 1 + modules/apps/transfer/ibc_module.go | 1 + modules/apps/transfer/ibc_module_test.go | 2 +- modules/core/05-port/types/module.go | 1 + modules/core/keeper/msg_server.go | 2 +- testing/mock/ibc_app.go | 1 + testing/mock/ibc_module.go | 4 ++-- 11 files changed, 17 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9d669650a3..41f73929faf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (modules/core/05-port) [\#1086](https://github.com/cosmos/ibc-go/pull/1086) Added `counterpartyChannelID` argument to IBCModule.OnChanOpenAck * (channel) [\#848](https://github.com/cosmos/ibc-go/pull/848) Added `ChannelId` to MsgChannelOpenInitResponse * (testing) [\#813](https://github.com/cosmos/ibc-go/pull/813) The `ack` argument to the testing function `RelayPacket` has been removed as it is no longer needed. * (testing) [\#774](https://github.com/cosmos/ibc-go/pull/774) Added `ChainID` arg to `SetupWithGenesisValSet` on the testing app. `Coordinator` generated ChainIDs now starts at index 1 diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index beab128a1fd..98987e78395 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -114,6 +114,10 @@ IBC applications must perform application version negoitation in `OnChanOpenTry` The negotiated application version then must be returned in `OnChanOpenTry` to core IBC. Core IBC will set this version in the TRYOPEN channel. +### `OnChanOpenAck` will take additional `counterpartyChannelID` argument +The `OnChanOpenAck` application callback has been modified. +The arguments now include the counterparty channel id. + ### `NegotiateAppVersion` removed from `IBCModule` interface Previously this logic was handled by the `NegotiateAppVersion` function. diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module.go b/modules/apps/27-interchain-accounts/controller/ibc_module.go index 1aa362a4247..c00c9f5d1c2 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module.go @@ -80,6 +80,7 @@ func (im IBCModule) OnChanOpenAck( ctx sdk.Context, portID, channelID string, + counterpartyChannelID string, counterpartyVersion string, ) error { if !im.keeper.IsControllerEnabled(ctx) { @@ -91,7 +92,7 @@ func (im IBCModule) OnChanOpenAck( } // call underlying app's OnChanOpenAck callback with the counterparty app version. - return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion) + return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) } // OnChanOpenAck implements the IBCModule interface diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go index f2b5d36ac63..db4412d144e 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go @@ -285,7 +285,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { { "ICA auth module callback fails", func() { suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenAck = func( - ctx sdk.Context, portID, channelID string, counterpartyVersion string, + ctx sdk.Context, portID, channelID string, counterpartyChannelID string, counterpartyVersion string, ) error { return fmt.Errorf("mock ica auth fails") } @@ -316,7 +316,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.Version) + err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelID, path.EndpointB.ChannelConfig.Version) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 630c4d44fc1..fb403c71937 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -61,6 +61,7 @@ func (im IBCModule) OnChanOpenAck( ctx sdk.Context, portID, channelID string, + counterpartyChannelID string, counterpartyVersion string, ) error { return sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index c784a91e933..f5ed807d8b2 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -125,6 +125,7 @@ func (im IBCModule) OnChanOpenAck( ctx sdk.Context, portID, channelID string, + _ string, counterpartyVersion string, ) error { if counterpartyVersion != types.Version { diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index b5f834a3a8e..92d0f30d4c7 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -228,7 +228,7 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { tc.malleate() // explicitly change fields in channel and testChannel - err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyVersion) + err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointA.Counterparty.ChannelID, counterpartyVersion) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index dea418b7250..9f754fe0a3e 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -51,6 +51,7 @@ type IBCModule interface { ctx sdk.Context, portID, channelID string, + counterpartyChannelID string, counterpartyVersion string, ) error diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index b19041f636d..a380540614c 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -261,7 +261,7 @@ func (k Keeper) ChannelOpenAck(goCtx context.Context, msg *channeltypes.MsgChann } // Perform application logic callback - if err = cbs.OnChanOpenAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyVersion); err != nil { + if err = cbs.OnChanOpenAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannelId, msg.CounterpartyVersion); err != nil { return nil, sdkerrors.Wrap(err, "channel open ack callback failed") } diff --git a/testing/mock/ibc_app.go b/testing/mock/ibc_app.go index 15f77d02d5a..77eb17b8c6f 100644 --- a/testing/mock/ibc_app.go +++ b/testing/mock/ibc_app.go @@ -40,6 +40,7 @@ type MockIBCApp struct { ctx sdk.Context, portID, channelID string, + counterpartyChannelID string, counterpartyVersion string, ) error diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 1ea1d3850ad..e58f6ae7156 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -64,9 +64,9 @@ func (im IBCModule) OnChanOpenTry( } // OnChanOpenAck implements the IBCModule interface. -func (im IBCModule) OnChanOpenAck(ctx sdk.Context, portID string, channelID string, counterpartyVersion string) error { +func (im IBCModule) OnChanOpenAck(ctx sdk.Context, portID string, channelID string, counterpartyChannelID string, counterpartyVersion string) error { if im.IBCApp.OnChanOpenAck != nil { - return im.IBCApp.OnChanOpenAck(ctx, portID, channelID, counterpartyVersion) + return im.IBCApp.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) } return nil From 90a7e5fbdd8f1951fd7f787d0f74449bf7c21831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 9 Mar 2022 13:55:23 +0100 Subject: [PATCH 030/275] fix mirgation docs (#1091) --- docs/migrations/v2-to-v3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index 98987e78395..2a7be3dde22 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -68,7 +68,7 @@ For ICS27 it is also necessary to [manually add store upgrades](https://docs.cos ```go if upgradeInfo.Name == "v3" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { storeUpgrades := store.StoreUpgrades{ - Added: []string{icatypes.ModuleName}, + Added: []string{icacontrollertypes.StoreKey, icahosttypes.StoreKey}, } app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) From a7563c9bc03080706788fafcecdf948849187d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Wed, 9 Mar 2022 20:29:45 +0100 Subject: [PATCH 031/275] fix: handle testing update client errors (#1094) --- testing/coordinator.go | 6 ++++-- testing/endpoint.go | 18 ++++++++++++------ testing/path.go | 10 +++++++--- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/testing/coordinator.go b/testing/coordinator.go index 5a7a91650fc..65bf5a4f1f3 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -117,7 +117,8 @@ func (coord *Coordinator) CreateConnections(path *Path) { require.NoError(coord.T, err) // ensure counterparty is up to date - path.EndpointA.UpdateClient() + err = path.EndpointA.UpdateClient() + require.NoError(coord.T, err) } // CreateMockChannels constructs and executes channel handshake messages to create OPEN @@ -158,7 +159,8 @@ func (coord *Coordinator) CreateChannels(path *Path) { require.NoError(coord.T, err) // ensure counterparty is up to date - path.EndpointA.UpdateClient() + err = path.EndpointA.UpdateClient() + require.NoError(coord.T, err) } // GetChain returns the TestChain using the given chainID and returns an error if it does diff --git a/testing/endpoint.go b/testing/endpoint.go index 5d496494afc..5c2e2e33f4f 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -175,7 +175,8 @@ func (endpoint *Endpoint) ConnOpenInit() error { // ConnOpenTry will construct and execute a MsgConnectionOpenTry on the associated endpoint. func (endpoint *Endpoint) ConnOpenTry() error { - endpoint.UpdateClient() + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.T, err) counterpartyClient, proofClient, proofConsensus, consensusHeight, proofInit, proofHeight := endpoint.QueryConnectionHandshakeProof() @@ -202,7 +203,8 @@ func (endpoint *Endpoint) ConnOpenTry() error { // ConnOpenAck will construct and execute a MsgConnectionOpenAck on the associated endpoint. func (endpoint *Endpoint) ConnOpenAck() error { - endpoint.UpdateClient() + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.T, err) counterpartyClient, proofClient, proofConsensus, consensusHeight, proofTry, proofHeight := endpoint.QueryConnectionHandshakeProof() @@ -218,7 +220,8 @@ func (endpoint *Endpoint) ConnOpenAck() error { // ConnOpenConfirm will construct and execute a MsgConnectionOpenConfirm on the associated endpoint. func (endpoint *Endpoint) ConnOpenConfirm() error { - endpoint.UpdateClient() + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.T, err) connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID) proof, height := endpoint.Counterparty.Chain.QueryProof(connectionKey) @@ -281,7 +284,8 @@ func (endpoint *Endpoint) ChanOpenInit() error { // ChanOpenTry will construct and execute a MsgChannelOpenTry on the associated endpoint. func (endpoint *Endpoint) ChanOpenTry() error { - endpoint.UpdateClient() + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.T, err) channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) @@ -312,7 +316,8 @@ func (endpoint *Endpoint) ChanOpenTry() error { // ChanOpenAck will construct and execute a MsgChannelOpenAck on the associated endpoint. func (endpoint *Endpoint) ChanOpenAck() error { - endpoint.UpdateClient() + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.T, err) channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) @@ -328,7 +333,8 @@ func (endpoint *Endpoint) ChanOpenAck() error { // ChanOpenConfirm will construct and execute a MsgChannelOpenConfirm on the associated endpoint. func (endpoint *Endpoint) ChanOpenConfirm() error { - endpoint.UpdateClient() + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.T, err) channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) diff --git a/testing/path.go b/testing/path.go index d447102c7b9..731d3cd5e1b 100644 --- a/testing/path.go +++ b/testing/path.go @@ -43,7 +43,9 @@ func (path *Path) RelayPacket(packet channeltypes.Packet) error { if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointA.Chain.App.AppCodec(), packet)) { // packet found, relay from A to B - path.EndpointB.UpdateClient() + if err := path.EndpointB.UpdateClient(); err != nil { + return err + } res, err := path.EndpointB.RecvPacketWithResult(packet) if err != nil { @@ -58,15 +60,17 @@ func (path *Path) RelayPacket(packet channeltypes.Packet) error { if err := path.EndpointA.AcknowledgePacket(packet, ack); err != nil { return err } - return nil + return nil } pc = path.EndpointB.Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(path.EndpointB.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointB.Chain.App.AppCodec(), packet)) { // packet found, relay B to A - path.EndpointA.UpdateClient() + if err := path.EndpointA.UpdateClient(); err != nil { + return err + } res, err := path.EndpointA.RecvPacketWithResult(packet) if err != nil { From f0b94dfa992d0baf777d9fb3d5ac896d543a8a4e Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 10 Mar 2022 12:15:11 +0100 Subject: [PATCH 032/275] replace channel keeper with IBC keeper in AnteDecorator (#950) * replace channel keeper with IBC keeper in AnteDecorator and pass message to rpc handler * fix error checking condition * fix for proper way of getting go context * refactor tests for ante handler * review comment * review comments and some fixes * review comments * execute message for update client as well * add migration Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 1 + docs/ibc/proto-docs.md | 35 ++ docs/migrations/v2-to-v3.md | 16 + modules/core/04-channel/types/tx.pb.go | 299 ++++++++++--- modules/core/ante/ante.go | 45 +- modules/core/ante/ante_test.go | 595 +++++++++++++------------ modules/core/keeper/msg_server.go | 16 +- proto/ibc/core/channel/v1/tx.proto | 36 +- testing/endpoint.go | 30 ++ testing/simapp/ante_handler.go | 9 +- testing/simapp/app.go | 2 +- 11 files changed, 683 insertions(+), 401 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41f73929faf..7091c758777 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (testing) [\#776](https://github.com/cosmos/ibc-go/pull/776) Adding helper fn to generate capability name for testing callbacks * (testing) [\#892](https://github.com/cosmos/ibc-go/pull/892) IBC Mock modules store the scoped keeper and portID within the IBCMockApp. They also maintain reference to the AppModule to update the AppModule's list of IBC applications it references. Allows for the mock module to be reused as a base application in middleware stacks. * (channel) [\#882](https://github.com/cosmos/ibc-go/pull/882) The `WriteAcknowledgement` API now takes `exported.Acknowledgement` instead of a byte array +* (modules/core/ante) [\#950](https://github.com/cosmos/ibc-go/pull/950) Replaces the channel keeper with the IBC keeper in the IBC `AnteDecorator` in order to execute the entire message and be able to reject redundant messages that are in the same block as the non-redundant messages. ### State Machine Breaking diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 79d56a6a541..80b2df196d3 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -127,6 +127,8 @@ - [MsgTimeoutOnCloseResponse](#ibc.core.channel.v1.MsgTimeoutOnCloseResponse) - [MsgTimeoutResponse](#ibc.core.channel.v1.MsgTimeoutResponse) + - [ResponseResultType](#ibc.core.channel.v1.ResponseResultType) + - [Msg](#ibc.core.channel.v1.Msg) - [ibc/core/client/v1/genesis.proto](#ibc/core/client/v1/genesis.proto) @@ -1738,6 +1740,11 @@ MsgAcknowledgement receives incoming IBC acknowledgement MsgAcknowledgementResponse defines the Msg/Acknowledgement response type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `result` | [ResponseResultType](#ibc.core.channel.v1.ResponseResultType) | | | + + @@ -1954,6 +1961,11 @@ MsgRecvPacket receives incoming IBC packet MsgRecvPacketResponse defines the Msg/RecvPacket response type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `result` | [ResponseResultType](#ibc.core.channel.v1.ResponseResultType) | | | + + @@ -2003,6 +2015,11 @@ MsgTimeoutOnClose timed-out packet upon counterparty channel closure. MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `result` | [ResponseResultType](#ibc.core.channel.v1.ResponseResultType) | | | + + @@ -2013,11 +2030,29 @@ MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type. MsgTimeoutResponse defines the Msg/Timeout response type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `result` | [ResponseResultType](#ibc.core.channel.v1.ResponseResultType) | | | + + + + + +### ResponseResultType +ResponseResultType defines the possible outcomes of the execution of a message + +| Name | Number | Description | +| ---- | ------ | ----------- | +| RESPONSE_RESULT_UNSPECIFIED | 0 | Default zero value enumeration | +| RESPONSE_RESULT_NOOP | 1 | The message did not call the IBC application callbacks (because, for example, the packet had already been relayed) | +| RESPONSE_RESULT_SUCCESS | 2 | The message was executed successfully | + + diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index 2a7be3dde22..6b1c61735fc 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -103,6 +103,22 @@ The migration code required may look like: appState[icatypes.ModuleName] = clientCtx.JSONCodec.MustMarshalJSON(icaGenesisState) ``` +### Ante decorator + +The field of type `channelkeeper.Keeper` in the `AnteDecorator` structure has been replaced with a field of type `*keeper.Keeper`: + +```diff +type AnteDecorator struct { +- k channelkeeper.Keeper ++ k *keeper.Keeper +} + +- func NewAnteDecorator(k channelkeeper.Keeper) AnteDecorator { ++ func NewAnteDecorator(k *keeper.Keeper) AnteDecorator { + return AnteDecorator{k: k} +} +``` + ## IBC Apps diff --git a/modules/core/04-channel/types/tx.pb.go b/modules/core/04-channel/types/tx.pb.go index 6fcc1a44276..e497cf802b1 100644 --- a/modules/core/04-channel/types/tx.pb.go +++ b/modules/core/04-channel/types/tx.pb.go @@ -29,6 +29,38 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// ResponseResultType defines the possible outcomes of the execution of a message +type ResponseResultType int32 + +const ( + // Default zero value enumeration + UNSPECIFIED ResponseResultType = 0 + // The message did not call the IBC application callbacks (because, for example, the packet had already been relayed) + NOOP ResponseResultType = 1 + // The message was executed successfully + SUCCESS ResponseResultType = 2 +) + +var ResponseResultType_name = map[int32]string{ + 0: "RESPONSE_RESULT_UNSPECIFIED", + 1: "RESPONSE_RESULT_NOOP", + 2: "RESPONSE_RESULT_SUCCESS", +} + +var ResponseResultType_value = map[string]int32{ + "RESPONSE_RESULT_UNSPECIFIED": 0, + "RESPONSE_RESULT_NOOP": 1, + "RESPONSE_RESULT_SUCCESS": 2, +} + +func (x ResponseResultType) String() string { + return proto.EnumName(ResponseResultType_name, int32(x)) +} + +func (ResponseResultType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{0} +} + // MsgChannelOpenInit defines an sdk.Msg to initialize a channel handshake. It // is called by a relayer on Chain A. type MsgChannelOpenInit struct { @@ -566,6 +598,7 @@ var xxx_messageInfo_MsgRecvPacket proto.InternalMessageInfo // MsgRecvPacketResponse defines the Msg/RecvPacket response type. type MsgRecvPacketResponse struct { + Result ResponseResultType `protobuf:"varint,1,opt,name=result,proto3,enum=ibc.core.channel.v1.ResponseResultType" json:"result,omitempty"` } func (m *MsgRecvPacketResponse) Reset() { *m = MsgRecvPacketResponse{} } @@ -645,6 +678,7 @@ var xxx_messageInfo_MsgTimeout proto.InternalMessageInfo // MsgTimeoutResponse defines the Msg/Timeout response type. type MsgTimeoutResponse struct { + Result ResponseResultType `protobuf:"varint,1,opt,name=result,proto3,enum=ibc.core.channel.v1.ResponseResultType" json:"result,omitempty"` } func (m *MsgTimeoutResponse) Reset() { *m = MsgTimeoutResponse{} } @@ -725,6 +759,7 @@ var xxx_messageInfo_MsgTimeoutOnClose proto.InternalMessageInfo // MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type. type MsgTimeoutOnCloseResponse struct { + Result ResponseResultType `protobuf:"varint,1,opt,name=result,proto3,enum=ibc.core.channel.v1.ResponseResultType" json:"result,omitempty"` } func (m *MsgTimeoutOnCloseResponse) Reset() { *m = MsgTimeoutOnCloseResponse{} } @@ -804,6 +839,7 @@ var xxx_messageInfo_MsgAcknowledgement proto.InternalMessageInfo // MsgAcknowledgementResponse defines the Msg/Acknowledgement response type. type MsgAcknowledgementResponse struct { + Result ResponseResultType `protobuf:"varint,1,opt,name=result,proto3,enum=ibc.core.channel.v1.ResponseResultType" json:"result,omitempty"` } func (m *MsgAcknowledgementResponse) Reset() { *m = MsgAcknowledgementResponse{} } @@ -840,6 +876,7 @@ func (m *MsgAcknowledgementResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAcknowledgementResponse proto.InternalMessageInfo func init() { + proto.RegisterEnum("ibc.core.channel.v1.ResponseResultType", ResponseResultType_name, ResponseResultType_value) proto.RegisterType((*MsgChannelOpenInit)(nil), "ibc.core.channel.v1.MsgChannelOpenInit") proto.RegisterType((*MsgChannelOpenInitResponse)(nil), "ibc.core.channel.v1.MsgChannelOpenInitResponse") proto.RegisterType((*MsgChannelOpenTry)(nil), "ibc.core.channel.v1.MsgChannelOpenTry") @@ -865,79 +902,87 @@ func init() { func init() { proto.RegisterFile("ibc/core/channel/v1/tx.proto", fileDescriptor_bc4637e0ac3fc7b7) } var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ - // 1138 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4d, 0x6f, 0xdb, 0x46, - 0x13, 0xd6, 0x87, 0x2d, 0xdb, 0x63, 0xbf, 0xb1, 0x4d, 0xf9, 0x43, 0xa1, 0x6c, 0xd1, 0x2f, 0x0f, - 0x89, 0x91, 0x22, 0x62, 0x6c, 0x07, 0x28, 0x12, 0xf4, 0x62, 0x09, 0x28, 0x6a, 0x14, 0x6e, 0x0a, - 0xda, 0xed, 0xc1, 0x28, 0x20, 0x48, 0xab, 0x0d, 0x45, 0x48, 0xe2, 0xaa, 0x24, 0xa5, 0x44, 0xff, - 0xa0, 0xc7, 0x9c, 0x7b, 0x4a, 0xcf, 0x3d, 0xa4, 0x3f, 0x23, 0xc7, 0x9c, 0xda, 0xa2, 0x07, 0xa2, - 0xb0, 0x2f, 0x3d, 0xf3, 0x17, 0x14, 0x5c, 0x2e, 0x3f, 0x24, 0x91, 0x15, 0x95, 0x54, 0x6e, 0x6e, - 0xe4, 0xcc, 0xb3, 0xb3, 0xb3, 0xcf, 0x33, 0x9c, 0xdd, 0x25, 0xec, 0xa9, 0x0d, 0x24, 0x21, 0xa2, - 0x63, 0x09, 0xb5, 0xea, 0x9a, 0x86, 0x3b, 0xd2, 0xe0, 0x48, 0x32, 0x5f, 0x96, 0x7b, 0x3a, 0x31, - 0x09, 0x97, 0x57, 0x1b, 0xa8, 0xec, 0x78, 0xcb, 0xcc, 0x5b, 0x1e, 0x1c, 0xf1, 0x5b, 0x0a, 0x51, - 0x08, 0xf5, 0x4b, 0xce, 0x93, 0x0b, 0xe5, 0x85, 0x20, 0x50, 0x47, 0xc5, 0x9a, 0xe9, 0xc4, 0x71, - 0x9f, 0x18, 0xe0, 0xff, 0x51, 0x33, 0x79, 0x61, 0x29, 0x44, 0xfc, 0x29, 0x0d, 0xdc, 0xb9, 0xa1, - 0x54, 0x5d, 0xe3, 0xb3, 0x1e, 0xd6, 0xce, 0x34, 0xd5, 0xe4, 0x3e, 0x81, 0xa5, 0x1e, 0xd1, 0xcd, - 0x9a, 0xda, 0x2c, 0xa4, 0x0f, 0xd2, 0x87, 0x2b, 0x15, 0xce, 0xb6, 0x84, 0x3b, 0xc3, 0x7a, 0xb7, - 0xf3, 0x54, 0x64, 0x0e, 0x51, 0xce, 0x39, 0x4f, 0x67, 0x4d, 0xee, 0x33, 0x58, 0x62, 0x41, 0x0b, - 0x99, 0x83, 0xf4, 0xe1, 0xea, 0xf1, 0x5e, 0x39, 0x62, 0x11, 0x65, 0x36, 0x47, 0x65, 0xe1, 0xad, - 0x25, 0xa4, 0x64, 0x6f, 0x08, 0xb7, 0x03, 0x39, 0x43, 0x55, 0x34, 0xac, 0x17, 0xb2, 0xce, 0x4c, - 0x32, 0x7b, 0x7b, 0xba, 0xfc, 0xc3, 0x6b, 0x21, 0xf5, 0xd7, 0x6b, 0x21, 0x25, 0xca, 0xc0, 0x4f, - 0xa6, 0x28, 0x63, 0xa3, 0x47, 0x34, 0x03, 0x73, 0x8f, 0x01, 0x58, 0xa8, 0x20, 0xdb, 0x6d, 0xdb, - 0x12, 0x36, 0xdd, 0x6c, 0x03, 0x9f, 0x28, 0xaf, 0xb0, 0x97, 0xb3, 0xa6, 0xf8, 0x6b, 0x16, 0x36, - 0x47, 0x83, 0x5e, 0xea, 0xc3, 0xd9, 0x96, 0xfd, 0x15, 0xe4, 0x7b, 0x3a, 0x1e, 0xa8, 0xa4, 0x6f, - 0xd4, 0x42, 0x19, 0x64, 0xe8, 0xc0, 0x92, 0x6d, 0x09, 0x3c, 0x1b, 0x38, 0x09, 0x12, 0xe5, 0x4d, - 0xcf, 0x5a, 0xf5, 0x52, 0x0a, 0xd3, 0x98, 0x9d, 0x9d, 0x46, 0x19, 0xb6, 0x10, 0xe9, 0x6b, 0x26, - 0xd6, 0x7b, 0x75, 0xdd, 0x1c, 0xd6, 0x06, 0x58, 0x37, 0x54, 0xa2, 0x15, 0x16, 0x68, 0x3a, 0x82, - 0x6d, 0x09, 0x45, 0x46, 0x48, 0x04, 0x4a, 0x94, 0xf3, 0x61, 0xf3, 0xb7, 0xae, 0xd5, 0xa1, 0xb6, - 0xa7, 0x13, 0xf2, 0xbc, 0xa6, 0x6a, 0xaa, 0x59, 0x58, 0x3c, 0x48, 0x1f, 0xae, 0x85, 0xa9, 0x0d, - 0x7c, 0xa2, 0xbc, 0x42, 0x5f, 0x68, 0xed, 0x5c, 0xc1, 0x9a, 0xeb, 0x69, 0x61, 0x55, 0x69, 0x99, - 0x85, 0x1c, 0x5d, 0x0c, 0x1f, 0x5a, 0x8c, 0x5b, 0xa3, 0x83, 0xa3, 0xf2, 0x17, 0x14, 0x51, 0x29, - 0x3a, 0x4b, 0xb1, 0x2d, 0x21, 0x1f, 0x8e, 0xeb, 0x8e, 0x16, 0xe5, 0x55, 0xfa, 0xea, 0x22, 0x43, - 0xc5, 0xb2, 0x14, 0x53, 0x2c, 0x45, 0xb8, 0x3b, 0xa1, 0xab, 0x57, 0x2b, 0xe2, 0x6f, 0x13, 0xaa, - 0x9f, 0xa2, 0xf6, 0x6c, 0xaa, 0x8f, 0x96, 0x5b, 0x26, 0x59, 0xb9, 0x71, 0x57, 0xb0, 0x3b, 0xc2, - 0x7b, 0x28, 0x04, 0xad, 0xfa, 0x8a, 0x68, 0x5b, 0x42, 0x29, 0x42, 0xa0, 0x70, 0xbc, 0xed, 0xb0, - 0x27, 0xa8, 0x9b, 0x79, 0x28, 0x7f, 0x04, 0xae, 0xa0, 0x35, 0x53, 0x1f, 0x32, 0xe1, 0xb7, 0x6c, - 0x4b, 0xd8, 0x08, 0x0b, 0x64, 0xea, 0x43, 0x51, 0x5e, 0xa6, 0xcf, 0xce, 0xb7, 0xf3, 0x91, 0xc9, - 0x7e, 0x8a, 0xda, 0xbe, 0xec, 0x3f, 0x67, 0x60, 0x7b, 0xd4, 0x5b, 0x25, 0xda, 0x73, 0x55, 0xef, - 0xde, 0x86, 0xf4, 0x3e, 0x95, 0x75, 0xd4, 0xa6, 0x62, 0x47, 0x50, 0x59, 0x47, 0x6d, 0x8f, 0x4a, - 0xa7, 0x20, 0xc7, 0xa9, 0x5c, 0x98, 0x0b, 0x95, 0x8b, 0x31, 0x54, 0x0a, 0xb0, 0x1f, 0x49, 0x96, - 0x4f, 0xe7, 0x8f, 0x69, 0xc8, 0x07, 0x88, 0x6a, 0x87, 0x18, 0x78, 0xf6, 0x4d, 0xe3, 0xfd, 0xc8, - 0x9c, 0xbe, 0x59, 0xec, 0x43, 0x31, 0x22, 0x37, 0x3f, 0xf7, 0x37, 0x19, 0xd8, 0x19, 0xf3, 0xdf, - 0x62, 0x2d, 0x8c, 0x36, 0xd4, 0xec, 0x7b, 0x36, 0xd4, 0xdb, 0x2d, 0x87, 0x03, 0x28, 0x45, 0x13, - 0xe6, 0x73, 0xfa, 0x2a, 0x03, 0xff, 0x3b, 0x37, 0x14, 0x19, 0xa3, 0xc1, 0xd7, 0x75, 0xd4, 0xc6, - 0x26, 0xf7, 0x04, 0x72, 0x3d, 0xfa, 0x44, 0x99, 0x5c, 0x3d, 0x2e, 0x46, 0xee, 0x64, 0x2e, 0x98, - 0x6d, 0x64, 0x6c, 0x00, 0xf7, 0x39, 0x6c, 0xb8, 0xe9, 0x22, 0xd2, 0xed, 0xaa, 0x66, 0x17, 0x6b, - 0x26, 0xa5, 0x77, 0xad, 0x52, 0xb4, 0x2d, 0x61, 0x37, 0xbc, 0xa0, 0x00, 0x21, 0xca, 0xeb, 0xd4, - 0x54, 0xf5, 0x2d, 0x13, 0xa4, 0x65, 0xe7, 0x42, 0xda, 0x42, 0x0c, 0x69, 0xbb, 0xb4, 0xe1, 0x04, - 0x8c, 0xf8, 0x5c, 0xfd, 0x91, 0x01, 0x38, 0x37, 0x94, 0x4b, 0xb5, 0x8b, 0x49, 0xff, 0xdf, 0x21, - 0xaa, 0xaf, 0xe9, 0x18, 0x61, 0x75, 0x80, 0x9b, 0x71, 0x44, 0x05, 0x08, 0x8f, 0xa8, 0x6f, 0x7c, - 0xcb, 0x5c, 0x89, 0xfa, 0x12, 0x38, 0x0d, 0xbf, 0x34, 0x6b, 0x06, 0xfe, 0xbe, 0x8f, 0x35, 0x84, - 0x6b, 0x3a, 0x46, 0x03, 0x4a, 0xda, 0x42, 0x65, 0xdf, 0xb6, 0x84, 0xbb, 0x6e, 0x84, 0x49, 0x8c, - 0x28, 0x6f, 0x38, 0xc6, 0x0b, 0x66, 0x73, 0x88, 0x4c, 0x50, 0xaa, 0x5b, 0xf4, 0x2c, 0xcb, 0xb8, - 0x0d, 0xda, 0x95, 0xbb, 0xe9, 0x33, 0xf3, 0x33, 0x8d, 0xd6, 0xf0, 0xc7, 0xc0, 0xfc, 0xa7, 0xb0, - 0xca, 0x0a, 0xd9, 0xc9, 0x88, 0xb5, 0x83, 0x1d, 0xdb, 0x12, 0xb8, 0x91, 0x2a, 0x77, 0x9c, 0xa2, - 0xec, 0x36, 0x0e, 0x37, 0xf7, 0x79, 0x36, 0x84, 0x68, 0xc9, 0x16, 0x3f, 0x54, 0xb2, 0xdc, 0x3f, - 0xee, 0xdb, 0xa3, 0xda, 0xf8, 0xca, 0xfd, 0x92, 0xa1, 0x82, 0x9e, 0xa2, 0xb6, 0x46, 0x5e, 0x74, - 0x70, 0x53, 0xc1, 0xf4, 0xd3, 0xfe, 0x00, 0xe9, 0x0e, 0x61, 0xbd, 0x3e, 0x1a, 0xcd, 0x55, 0x4e, - 0x1e, 0x37, 0x07, 0xe2, 0x38, 0x03, 0x9b, 0x71, 0xe2, 0x50, 0xa7, 0x27, 0xce, 0xa9, 0xf3, 0xf2, - 0x1f, 0x77, 0xeb, 0x3d, 0x7a, 0x57, 0x1a, 0x63, 0xcc, 0x23, 0xf4, 0xf8, 0xcd, 0x32, 0x64, 0xcf, - 0x0d, 0x85, 0x6b, 0xc3, 0xfa, 0xf8, 0x8d, 0xef, 0x7e, 0x24, 0x89, 0x93, 0xf7, 0x2e, 0x5e, 0x4a, - 0x08, 0xf4, 0x2f, 0x68, 0x2d, 0xb8, 0x33, 0x76, 0xcd, 0xba, 0x97, 0x20, 0xc4, 0xa5, 0x3e, 0xe4, - 0xcb, 0xc9, 0x70, 0x31, 0x33, 0x39, 0x27, 0xa9, 0x24, 0x33, 0x9d, 0xa2, 0x76, 0xa2, 0x99, 0x42, - 0x27, 0x4a, 0xce, 0x04, 0x2e, 0xe2, 0x34, 0xf9, 0x20, 0x41, 0x14, 0x86, 0xe5, 0x8f, 0x93, 0x63, - 0xfd, 0x59, 0x35, 0xd8, 0x98, 0x38, 0x74, 0x1d, 0x4e, 0x89, 0xe3, 0x23, 0xf9, 0x47, 0x49, 0x91, - 0xfe, 0x7c, 0x2f, 0x20, 0x1f, 0x79, 0x50, 0x4a, 0x12, 0xc8, 0x5b, 0xe7, 0xc9, 0x0c, 0x60, 0x7f, - 0xe2, 0xef, 0x00, 0x42, 0xa7, 0x09, 0x31, 0x2e, 0x44, 0x80, 0xe1, 0x1f, 0x4c, 0xc7, 0xf8, 0xd1, - 0x2f, 0x60, 0xc9, 0xdb, 0x7f, 0x85, 0xb8, 0x61, 0x0c, 0xc0, 0xdf, 0x9f, 0x02, 0x08, 0xd7, 0xde, - 0xd8, 0x0e, 0x73, 0x6f, 0xca, 0x50, 0x86, 0x8b, 0xaf, 0xbd, 0xe8, 0xae, 0xe8, 0x7c, 0xbc, 0xe3, - 0x1d, 0x31, 0x36, 0xcb, 0x31, 0x60, 0xfc, 0xc7, 0x1b, 0xd3, 0x31, 0x2a, 0x17, 0x6f, 0xaf, 0x4b, - 0xe9, 0x77, 0xd7, 0xa5, 0xf4, 0x9f, 0xd7, 0xa5, 0xf4, 0xab, 0x9b, 0x52, 0xea, 0xdd, 0x4d, 0x29, - 0xf5, 0xfb, 0x4d, 0x29, 0x75, 0xf5, 0x44, 0x51, 0xcd, 0x56, 0xbf, 0x51, 0x46, 0xa4, 0x2b, 0x21, - 0x62, 0x74, 0x89, 0x21, 0xa9, 0x0d, 0xf4, 0x50, 0x21, 0xd2, 0xe0, 0x44, 0xea, 0x92, 0x66, 0xbf, - 0x83, 0x0d, 0xf7, 0xe7, 0xd3, 0xa3, 0xc7, 0x0f, 0xbd, 0xff, 0x4f, 0xe6, 0xb0, 0x87, 0x8d, 0x46, - 0x8e, 0xfe, 0x7b, 0x3a, 0xf9, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xc5, 0x64, 0xa7, 0xfd, 0x0a, 0x13, - 0x00, 0x00, + // 1267 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4b, 0x6f, 0xdb, 0x46, + 0x10, 0xd6, 0xcb, 0xb2, 0x3d, 0x72, 0x6d, 0x99, 0xf2, 0x43, 0xa1, 0x62, 0x51, 0xe5, 0x21, 0x11, + 0x5c, 0x44, 0xf2, 0x23, 0x40, 0x11, 0xa3, 0x40, 0x61, 0xa9, 0x0a, 0x6a, 0xb4, 0x7e, 0x80, 0xb2, + 0x7b, 0x70, 0x8b, 0x0a, 0x12, 0xb5, 0x91, 0x09, 0x49, 0x5c, 0x95, 0xa4, 0x94, 0xe8, 0x1f, 0x04, + 0x3e, 0xe5, 0x6c, 0xc0, 0x40, 0x8a, 0x1e, 0x7b, 0x48, 0x7f, 0x46, 0x8e, 0x39, 0xb5, 0x45, 0x0f, + 0x42, 0x61, 0x5f, 0x7a, 0xd6, 0x2f, 0x28, 0xb8, 0x5c, 0x52, 0x94, 0x44, 0xc2, 0x74, 0x62, 0x3b, + 0xb9, 0xed, 0xce, 0x7c, 0x3b, 0x3b, 0xfb, 0x7d, 0xc3, 0x7d, 0x10, 0xee, 0x4b, 0x15, 0x31, 0x2b, + 0x62, 0x05, 0x65, 0xc5, 0x93, 0xb2, 0x2c, 0xa3, 0x46, 0xb6, 0xb3, 0x9e, 0xd5, 0x5e, 0x64, 0x5a, + 0x0a, 0xd6, 0x30, 0x13, 0x93, 0x2a, 0x62, 0x46, 0xf7, 0x66, 0xa8, 0x37, 0xd3, 0x59, 0x67, 0x17, + 0x6a, 0xb8, 0x86, 0x89, 0x3f, 0xab, 0xb7, 0x0c, 0x28, 0xcb, 0x0d, 0x02, 0x35, 0x24, 0x24, 0x6b, + 0x7a, 0x1c, 0xa3, 0x45, 0x01, 0x9f, 0x3b, 0xcd, 0x64, 0x86, 0x25, 0x10, 0xfe, 0x57, 0x3f, 0x30, + 0xbb, 0x6a, 0x2d, 0x6f, 0x18, 0xf7, 0x5b, 0x48, 0xde, 0x91, 0x25, 0x8d, 0xf9, 0x02, 0x26, 0x5b, + 0x58, 0xd1, 0x4a, 0x52, 0x35, 0xee, 0x4f, 0xf9, 0xd3, 0xd3, 0x39, 0xa6, 0xdf, 0xe3, 0x66, 0xbb, + 0xe5, 0x66, 0x63, 0x8b, 0xa7, 0x0e, 0x5e, 0x08, 0xeb, 0xad, 0x9d, 0x2a, 0xf3, 0x15, 0x4c, 0xd2, + 0xa0, 0xf1, 0x40, 0xca, 0x9f, 0x8e, 0x6c, 0xdc, 0xcf, 0x38, 0x2c, 0x22, 0x43, 0xe7, 0xc8, 0x85, + 0xde, 0xf6, 0x38, 0x9f, 0x60, 0x0e, 0x61, 0x96, 0x20, 0xac, 0x4a, 0x35, 0x19, 0x29, 0xf1, 0xa0, + 0x3e, 0x93, 0x40, 0x7b, 0x5b, 0x53, 0x2f, 0x5f, 0x73, 0xbe, 0xff, 0x5e, 0x73, 0x3e, 0x5e, 0x00, + 0x76, 0x3c, 0x45, 0x01, 0xa9, 0x2d, 0x2c, 0xab, 0x88, 0x79, 0x0c, 0x40, 0x43, 0x0d, 0xb2, 0x5d, + 0xec, 0xf7, 0xb8, 0x79, 0x23, 0xdb, 0x81, 0x8f, 0x17, 0xa6, 0x69, 0x67, 0xa7, 0xca, 0xff, 0x19, + 0x84, 0xf9, 0xe1, 0xa0, 0x87, 0x4a, 0xf7, 0x7a, 0xcb, 0xde, 0x83, 0x58, 0x4b, 0x41, 0x1d, 0x09, + 0xb7, 0xd5, 0x92, 0x2d, 0x83, 0x00, 0x19, 0x98, 0xec, 0xf7, 0x38, 0x96, 0x0e, 0x1c, 0x07, 0xf1, + 0xc2, 0xbc, 0x69, 0xcd, 0x9b, 0x29, 0xd9, 0x69, 0x0c, 0x5e, 0x9f, 0x46, 0x01, 0x16, 0x44, 0xdc, + 0x96, 0x35, 0xa4, 0xb4, 0xca, 0x8a, 0xd6, 0x2d, 0x75, 0x90, 0xa2, 0x4a, 0x58, 0x8e, 0x87, 0x48, + 0x3a, 0x5c, 0xbf, 0xc7, 0x25, 0x28, 0x21, 0x0e, 0x28, 0x5e, 0x88, 0xd9, 0xcd, 0x3f, 0x18, 0x56, + 0x9d, 0xda, 0x96, 0x82, 0xf1, 0xb3, 0x92, 0x24, 0x4b, 0x5a, 0x7c, 0x22, 0xe5, 0x4f, 0xcf, 0xd8, + 0xa9, 0x1d, 0xf8, 0x78, 0x61, 0x9a, 0x74, 0x48, 0xed, 0x1c, 0xc3, 0x8c, 0xe1, 0x39, 0x41, 0x52, + 0xed, 0x44, 0x8b, 0x87, 0xc9, 0x62, 0x58, 0xdb, 0x62, 0x8c, 0x1a, 0xed, 0xac, 0x67, 0xbe, 0x25, + 0x88, 0x5c, 0x42, 0x5f, 0x4a, 0xbf, 0xc7, 0xc5, 0xec, 0x71, 0x8d, 0xd1, 0xbc, 0x10, 0x21, 0x5d, + 0x03, 0x69, 0x2b, 0x96, 0x49, 0x97, 0x62, 0x49, 0xc0, 0xbd, 0x31, 0x5d, 0xcd, 0x5a, 0xe1, 0xff, + 0x1a, 0x53, 0x7d, 0x5b, 0xac, 0x5f, 0x4f, 0xf5, 0xe1, 0x72, 0x0b, 0x78, 0x2b, 0x37, 0xe6, 0x18, + 0x96, 0x87, 0x78, 0xb7, 0x85, 0x20, 0x55, 0x9f, 0xe3, 0xfb, 0x3d, 0x2e, 0xe9, 0x20, 0x90, 0x3d, + 0xde, 0xa2, 0xdd, 0x33, 0xa8, 0x9b, 0xdb, 0x50, 0x7e, 0x1d, 0x0c, 0x41, 0x4b, 0x9a, 0xd2, 0xa5, + 0xc2, 0x2f, 0xf4, 0x7b, 0x5c, 0xd4, 0x2e, 0x90, 0xa6, 0x74, 0x79, 0x61, 0x8a, 0xb4, 0xf5, 0x6f, + 0xe7, 0x13, 0x93, 0x7d, 0x5b, 0xac, 0x5b, 0xb2, 0xff, 0x1e, 0x80, 0xc5, 0x61, 0x6f, 0x1e, 0xcb, + 0xcf, 0x24, 0xa5, 0x79, 0x17, 0xd2, 0x5b, 0x54, 0x96, 0xc5, 0x3a, 0x11, 0xdb, 0x81, 0xca, 0xb2, + 0x58, 0x37, 0xa9, 0xd4, 0x0b, 0x72, 0x94, 0xca, 0xd0, 0xad, 0x50, 0x39, 0xe1, 0x42, 0x25, 0x07, + 0x2b, 0x8e, 0x64, 0x59, 0x74, 0x9e, 0xf9, 0x21, 0x36, 0x40, 0xe4, 0x1b, 0x58, 0x45, 0xd7, 0x3f, + 0x34, 0xde, 0x8f, 0xcc, 0xab, 0x0f, 0x8b, 0x15, 0x48, 0x38, 0xe4, 0x66, 0xe5, 0xfe, 0x26, 0x00, + 0x4b, 0x23, 0xfe, 0x3b, 0xac, 0x85, 0xe1, 0x0d, 0x35, 0xf8, 0x9e, 0x1b, 0xea, 0xdd, 0x96, 0x43, + 0x0a, 0x92, 0xce, 0x84, 0x59, 0x9c, 0xbe, 0x0a, 0xc0, 0x67, 0xbb, 0x6a, 0x4d, 0x40, 0x62, 0xe7, + 0xa0, 0x2c, 0xd6, 0x91, 0xc6, 0x3c, 0x81, 0x70, 0x8b, 0xb4, 0x08, 0x93, 0x91, 0x8d, 0x84, 0xe3, + 0x49, 0x66, 0x80, 0xe9, 0x41, 0x46, 0x07, 0x30, 0x4f, 0x21, 0x6a, 0xa4, 0x2b, 0xe2, 0x66, 0x53, + 0xd2, 0x9a, 0x48, 0xd6, 0x08, 0xbd, 0x33, 0xb9, 0x44, 0xbf, 0xc7, 0x2d, 0xdb, 0x17, 0x34, 0x40, + 0xf0, 0xc2, 0x1c, 0x31, 0xe5, 0x2d, 0xcb, 0x18, 0x69, 0xc1, 0x5b, 0x21, 0x2d, 0xe4, 0x42, 0xda, + 0xcf, 0x64, 0xc3, 0x19, 0x30, 0x62, 0xdd, 0x56, 0xbe, 0x86, 0xb0, 0x82, 0xd4, 0x76, 0xc3, 0x60, + 0x66, 0x76, 0xe3, 0xa1, 0x23, 0x33, 0x26, 0x5c, 0x20, 0xd0, 0xc3, 0x6e, 0x0b, 0x09, 0x74, 0xd8, + 0x56, 0x48, 0x9f, 0x83, 0xff, 0x27, 0x00, 0xb0, 0xab, 0xd6, 0x0e, 0xa5, 0x26, 0xc2, 0xed, 0x9b, + 0xe1, 0xbb, 0x2d, 0x2b, 0x48, 0x44, 0x52, 0x07, 0x55, 0xdd, 0xf8, 0x1e, 0x20, 0x4c, 0xbe, 0x8f, + 0x2c, 0xcb, 0xad, 0xf2, 0xfd, 0x1d, 0x30, 0x32, 0x7a, 0xa1, 0x95, 0x54, 0xf4, 0x4b, 0x1b, 0xc9, + 0x22, 0x2a, 0x29, 0x48, 0xec, 0x10, 0xee, 0x43, 0xb9, 0x95, 0x7e, 0x8f, 0xbb, 0x67, 0x44, 0x18, + 0xc7, 0xf0, 0x42, 0x54, 0x37, 0x16, 0xa9, 0x4d, 0xd7, 0xc3, 0x43, 0xc5, 0xff, 0x48, 0xae, 0xc4, + 0x94, 0xdb, 0x9b, 0x56, 0xee, 0xcc, 0xb8, 0x82, 0xd0, 0xe8, 0xfb, 0x32, 0xf9, 0xa2, 0x3e, 0x05, + 0x01, 0xbf, 0x84, 0x08, 0xfd, 0xac, 0xf4, 0x8c, 0xe8, 0xe6, 0xb4, 0xd4, 0xef, 0x71, 0xcc, 0xd0, + 0x37, 0xa7, 0x3b, 0x79, 0xc1, 0xd8, 0xc6, 0x8c, 0xdc, 0x6f, 0x73, 0x7b, 0x72, 0x56, 0x7e, 0xe2, + 0x43, 0x95, 0x0f, 0xbb, 0x28, 0x5f, 0x21, 0xb7, 0x88, 0x61, 0x6d, 0x6e, 0xba, 0x00, 0xfe, 0x08, + 0x90, 0xf2, 0xda, 0x16, 0xeb, 0x32, 0x7e, 0xde, 0x40, 0xd5, 0x1a, 0x22, 0xfb, 0xd5, 0x07, 0x54, + 0x40, 0x1a, 0xe6, 0xca, 0xc3, 0xd1, 0x8c, 0x02, 0x10, 0x46, 0xcd, 0x03, 0x8d, 0xf5, 0x81, 0x55, + 0x37, 0x8d, 0x89, 0xd3, 0xd4, 0x78, 0x5b, 0xef, 0x7c, 0xe4, 0x23, 0x48, 0x24, 0x0f, 0xc0, 0x11, + 0xc6, 0x6e, 0x58, 0x97, 0xd5, 0x33, 0x3f, 0x30, 0xe3, 0x20, 0x66, 0x0d, 0x12, 0x42, 0xa1, 0x78, + 0xb0, 0xbf, 0x57, 0x2c, 0x94, 0x84, 0x42, 0xf1, 0xe8, 0xfb, 0xc3, 0xd2, 0xd1, 0x5e, 0xf1, 0xa0, + 0x90, 0xdf, 0x79, 0xba, 0x53, 0xf8, 0x26, 0xea, 0x63, 0xe7, 0x4e, 0xcf, 0x53, 0x11, 0x9b, 0x89, + 0xe1, 0x61, 0x61, 0x74, 0xc4, 0xde, 0xfe, 0xfe, 0x41, 0xd4, 0xcf, 0x4e, 0x9d, 0x9e, 0xa7, 0x42, + 0x7a, 0x9b, 0x49, 0xc3, 0xf2, 0x28, 0xa6, 0x78, 0x94, 0xcf, 0x17, 0x8a, 0xc5, 0x68, 0x80, 0x8d, + 0x9c, 0x9e, 0xa7, 0x26, 0x69, 0x97, 0x0d, 0xbd, 0xfc, 0x2d, 0xe9, 0xdb, 0x78, 0x33, 0x05, 0xc1, + 0x5d, 0xb5, 0xc6, 0xd4, 0x61, 0x6e, 0xf4, 0xa9, 0xee, 0xbc, 0xdc, 0xf1, 0x07, 0x33, 0x9b, 0xf5, + 0x08, 0xb4, 0x88, 0x3d, 0x81, 0xd9, 0x91, 0xf7, 0xf1, 0x03, 0x0f, 0x21, 0x0e, 0x95, 0x2e, 0x9b, + 0xf1, 0x86, 0x73, 0x99, 0x49, 0xbf, 0x02, 0x7b, 0x99, 0x69, 0x5b, 0xac, 0x7b, 0x9a, 0xc9, 0xf6, + 0x14, 0x60, 0x34, 0x60, 0x1c, 0x9e, 0x01, 0xab, 0x1e, 0xa2, 0x50, 0x2c, 0xbb, 0xe1, 0x1d, 0x6b, + 0xcd, 0x2a, 0x43, 0x74, 0xec, 0xb6, 0x9c, 0xbe, 0x22, 0x8e, 0x85, 0x64, 0xd7, 0xbc, 0x22, 0xad, + 0xf9, 0x9e, 0x43, 0xcc, 0xf1, 0x86, 0xeb, 0x25, 0x90, 0xb9, 0xce, 0xcd, 0x6b, 0x80, 0xad, 0x89, + 0x7f, 0x02, 0xb0, 0x5d, 0x03, 0x79, 0xb7, 0x10, 0x03, 0x0c, 0xbb, 0x7a, 0x35, 0xc6, 0x8a, 0x5e, + 0x84, 0x49, 0xf3, 0xc6, 0xc3, 0xb9, 0x0d, 0xa3, 0x00, 0xf6, 0xe1, 0x15, 0x00, 0x7b, 0xed, 0x8d, + 0x1c, 0xc6, 0x0f, 0xae, 0x18, 0x4a, 0x71, 0xee, 0xb5, 0xe7, 0x72, 0x80, 0xd4, 0x61, 0x6e, 0x74, + 0xd7, 0x77, 0xcd, 0x72, 0x04, 0xe8, 0xfe, 0xf1, 0xba, 0xec, 0x8a, 0xb9, 0xe2, 0xdb, 0x8b, 0xa4, + 0xff, 0xdd, 0x45, 0xd2, 0xff, 0xef, 0x45, 0xd2, 0xff, 0xea, 0x32, 0xe9, 0x7b, 0x77, 0x99, 0xf4, + 0xfd, 0x7d, 0x99, 0xf4, 0x1d, 0x3f, 0xa9, 0x49, 0xda, 0x49, 0xbb, 0x92, 0x11, 0x71, 0x33, 0x2b, + 0x62, 0xb5, 0x89, 0xd5, 0xac, 0x54, 0x11, 0x1f, 0xd5, 0x70, 0xb6, 0xb3, 0x99, 0x6d, 0xe2, 0x6a, + 0xbb, 0x81, 0x54, 0xe3, 0xaf, 0xe1, 0xda, 0xe3, 0x47, 0xe6, 0x8f, 0x43, 0xad, 0xdb, 0x42, 0x6a, + 0x25, 0x4c, 0x7e, 0x1a, 0x6e, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xd5, 0x99, 0xe1, 0x0c, 0xc3, + 0x14, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1954,6 +1999,11 @@ func (m *MsgRecvPacketResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -2039,6 +2089,11 @@ func (m *MsgTimeoutResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -2131,6 +2186,11 @@ func (m *MsgTimeoutOnCloseResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -2218,6 +2278,11 @@ func (m *MsgAcknowledgementResponse) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l + if m.Result != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -2479,6 +2544,9 @@ func (m *MsgRecvPacketResponse) Size() (n int) { } var l int _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } return n } @@ -2512,6 +2580,9 @@ func (m *MsgTimeoutResponse) Size() (n int) { } var l int _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } return n } @@ -2549,6 +2620,9 @@ func (m *MsgTimeoutOnCloseResponse) Size() (n int) { } var l int _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } return n } @@ -2583,6 +2657,9 @@ func (m *MsgAcknowledgementResponse) Size() (n int) { } var l int _ = l + if m.Result != 0 { + n += 1 + sovTx(uint64(m.Result)) + } return n } @@ -4409,6 +4486,25 @@ func (m *MsgRecvPacketResponse) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: MsgRecvPacketResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4660,6 +4756,25 @@ func (m *MsgTimeoutResponse) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: MsgTimeoutResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4945,6 +5060,25 @@ func (m *MsgTimeoutOnCloseResponse) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: MsgTimeoutOnCloseResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -5211,6 +5345,25 @@ func (m *MsgAcknowledgementResponse) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: MsgAcknowledgementResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= ResponseResultType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/modules/core/ante/ante.go b/modules/core/ante/ante.go index 42e392905ec..e9218ea4b94 100644 --- a/modules/core/ante/ante.go +++ b/modules/core/ante/ante.go @@ -4,22 +4,23 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channelkeeper "github.com/cosmos/ibc-go/v3/modules/core/04-channel/keeper" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v3/modules/core/keeper" ) type AnteDecorator struct { - k channelkeeper.Keeper + k *keeper.Keeper } -func NewAnteDecorator(k channelkeeper.Keeper) AnteDecorator { +func NewAnteDecorator(k *keeper.Keeper) AnteDecorator { return AnteDecorator{k: k} } -// AnteDecorator returns an error if a multiMsg tx only contains packet messages (Recv, Ack, Timeout) and additional update messages and all packet messages -// are redundant. If the transaction is just a single UpdateClient message, or the multimsg transaction contains some other message type, then the antedecorator returns no error -// and continues processing to ensure these transactions are included. -// This will ensure that relayers do not waste fees on multiMsg transactions when another relayer has already submitted all packets, by rejecting the tx at the mempool layer. +// AnteDecorator returns an error if a multiMsg tx only contains packet messages (Recv, Ack, Timeout) and additional update messages +// and all packet messages are redundant. If the transaction is just a single UpdateClient message, or the multimsg transaction +// contains some other message type, then the antedecorator returns no error and continues processing to ensure these transactions +// are included. This will ensure that relayers do not waste fees on multiMsg transactions when another relayer has already submitted +// all packets, by rejecting the tx at the mempool layer. func (ad AnteDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { // do not run redundancy check on DeliverTx or simulate if (ctx.IsCheckTx() || ctx.IsReCheckTx()) && !simulate { @@ -29,31 +30,50 @@ func (ad AnteDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne for _, m := range tx.GetMsgs() { switch msg := m.(type) { case *channeltypes.MsgRecvPacket: - if _, found := ad.k.GetPacketReceipt(ctx, msg.Packet.GetDestPort(), msg.Packet.GetDestChannel(), msg.Packet.GetSequence()); found { + response, err := ad.k.RecvPacket(sdk.WrapSDKContext(ctx), msg) + if err != nil { + return ctx, err + } + if response.Result == channeltypes.NOOP { redundancies += 1 } packetMsgs += 1 case *channeltypes.MsgAcknowledgement: - if commitment := ad.k.GetPacketCommitment(ctx, msg.Packet.GetSourcePort(), msg.Packet.GetSourceChannel(), msg.Packet.GetSequence()); len(commitment) == 0 { + response, err := ad.k.Acknowledgement(sdk.WrapSDKContext(ctx), msg) + if err != nil { + return ctx, err + } + if response.Result == channeltypes.NOOP { redundancies += 1 } packetMsgs += 1 case *channeltypes.MsgTimeout: - if commitment := ad.k.GetPacketCommitment(ctx, msg.Packet.GetSourcePort(), msg.Packet.GetSourceChannel(), msg.Packet.GetSequence()); len(commitment) == 0 { + response, err := ad.k.Timeout(sdk.WrapSDKContext(ctx), msg) + if err != nil { + return ctx, err + } + if response.Result == channeltypes.NOOP { redundancies += 1 } packetMsgs += 1 case *channeltypes.MsgTimeoutOnClose: - if commitment := ad.k.GetPacketCommitment(ctx, msg.Packet.GetSourcePort(), msg.Packet.GetSourceChannel(), msg.Packet.GetSequence()); len(commitment) == 0 { + response, err := ad.k.TimeoutOnClose(sdk.WrapSDKContext(ctx), msg) + if err != nil { + return ctx, err + } + if response.Result == channeltypes.NOOP { redundancies += 1 } packetMsgs += 1 case *clienttypes.MsgUpdateClient: - // do nothing here, as we want to avoid updating clients if it is batched with only redundant messages + _, err := ad.k.UpdateClient(sdk.WrapSDKContext(ctx), msg) + if err != nil { + return ctx, err + } default: // if the multiMsg tx has a msg that is not a packet msg or update msg, then we will not return error @@ -61,7 +81,6 @@ func (ad AnteDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne // even if they get batched with redundant packet messages. return next(ctx, tx, simulate) } - } // only return error if all packet messages are redundant diff --git a/modules/core/ante/ante_test.go b/modules/core/ante/ante_test.go index 0336e07a3ae..c04f6483f74 100644 --- a/modules/core/ante/ante_test.go +++ b/modules/core/ante/ante_test.go @@ -4,13 +4,15 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" "github.com/cosmos/ibc-go/v3/modules/core/ante" + "github.com/cosmos/ibc-go/v3/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v3/testing" - "github.com/cosmos/ibc-go/v3/testing/mock" ) type AnteTestSuite struct { @@ -42,6 +44,133 @@ func TestAnteTestSuite(t *testing.T) { suite.Run(t, new(AnteTestSuite)) } +// createRecvPacketMessage creates a RecvPacket message for a packet sent from chain A to chain B. +func (suite *AnteTestSuite) createRecvPacketMessage(sequenceNumber uint64, isRedundant bool) sdk.Msg { + packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequenceNumber, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + err := suite.path.EndpointA.SendPacket(packet) + suite.Require().NoError(err) + + if isRedundant { + err = suite.path.EndpointB.RecvPacket(packet) + suite.Require().NoError(err) + } + + err = suite.path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + proof, proofHeight := suite.chainA.QueryProof(packetKey) + + return channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String()) +} + +// createAcknowledgementMessage creates an Acknowledgement message for a packet sent from chain B to chain A. +func (suite *AnteTestSuite) createAcknowledgementMessage(sequenceNumber uint64, isRedundant bool) sdk.Msg { + packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequenceNumber, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + err = suite.path.EndpointA.RecvPacket(packet) + suite.Require().NoError(err) + + if isRedundant { + err = suite.path.EndpointB.AcknowledgePacket(packet, ibctesting.MockAcknowledgement) + suite.Require().NoError(err) + } + + packetKey := host.PacketAcknowledgementKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + proof, proofHeight := suite.chainA.QueryProof(packetKey) + + return channeltypes.NewMsgAcknowledgement(packet, ibctesting.MockAcknowledgement, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String()) +} + +// createTimeoutMessage creates an Timeout message for a packet sent from chain B to chain A. +func (suite *AnteTestSuite) createTimeoutMessage(sequenceNumber uint64, isRedundant bool) sdk.Msg { + height := suite.chainA.LastHeader.GetHeight() + timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) + packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequenceNumber, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + timeoutHeight, 0) + + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + + suite.coordinator.CommitNBlocks(suite.chainA, 3) + + err = suite.path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + if isRedundant { + err = suite.path.EndpointB.TimeoutPacket(packet) + suite.Require().NoError(err) + } + + packetKey := host.PacketReceiptKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + proof, proofHeight := suite.chainA.QueryProof(packetKey) + + return channeltypes.NewMsgTimeout(packet, sequenceNumber, proof, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String()) +} + +// createTimeoutOnCloseMessage creates an TimeoutOnClose message for a packet sent from chain B to chain A. +func (suite *AnteTestSuite) createTimeoutOnCloseMessage(sequenceNumber uint64, isRedundant bool) sdk.Msg { + height := suite.chainA.LastHeader.GetHeight() + timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) + packet := channeltypes.NewPacket(ibctesting.MockPacketData, sequenceNumber, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + timeoutHeight, 0) + + err := suite.path.EndpointB.SendPacket(packet) + suite.Require().NoError(err) + err = suite.path.EndpointA.SetChannelClosed() + suite.Require().NoError(err) + + if isRedundant { + err = suite.path.EndpointB.TimeoutOnClose(packet) + suite.Require().NoError(err) + } + + packetKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + proof, proofHeight := suite.chainA.QueryProof(packetKey) + + channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel()) + proofClosed, _ := suite.chainA.QueryProof(channelKey) + + return channeltypes.NewMsgTimeoutOnClose(packet, 1, proof, proofClosed, proofHeight, suite.path.EndpointA.Chain.SenderAccount.GetAddress().String()) +} + +func (suite *AnteTestSuite) createUpdateClientMessage() sdk.Msg { + endpoint := suite.path.EndpointB + + // ensure counterparty has committed state + endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) + + var header exported.Header + + switch endpoint.ClientConfig.GetClientType() { + case exported.Tendermint: + header, _ = endpoint.Chain.ConstructUpdateTMClientHeader(endpoint.Counterparty.Chain, endpoint.ClientID) + + default: + } + + msg, err := clienttypes.NewMsgUpdateClient( + endpoint.ClientID, header, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + require.NoError(endpoint.Chain.T, err) + + return msg +} + func (suite *AnteTestSuite) TestAnteDecorator() { testCases := []struct { name string @@ -49,404 +178,276 @@ func (suite *AnteTestSuite) TestAnteDecorator() { expPass bool }{ { - "success on single msg", + "success on one new RecvPacket message", func(suite *AnteTestSuite) []sdk.Msg { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), 1, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - return []sdk.Msg{channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")} + // the RecvPacket message has not been submitted to the chain yet, so it will succeed + return []sdk.Msg{suite.createRecvPacketMessage(1, false)} }, true, }, { - "success on multiple msgs", + "success on one new Acknowledgement message", func(suite *AnteTestSuite) []sdk.Msg { - var msgs []sdk.Msg - - for i := 1; i <= 5; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) - } - return msgs + // the Acknowledgement message has not been submitted to the chain yet, so it will succeed + return []sdk.Msg{suite.createAcknowledgementMessage(1, false)} }, true, }, { - "success on multiple msgs: 1 fresh recv packet", + "success on one new Timeout message", func(suite *AnteTestSuite) []sdk.Msg { - var msgs []sdk.Msg - - for i := 1; i <= 5; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - err := suite.path.EndpointA.SendPacket(packet) - suite.Require().NoError(err) - - // receive all sequences except packet 3 - if i != 3 { - err = suite.path.EndpointB.RecvPacket(packet) - suite.Require().NoError(err) - } - - msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) - } - - return msgs + // the Timeout message has not been submitted to the chain yet, so it will succeed + return []sdk.Msg{suite.createTimeoutMessage(1, false)} }, true, }, { - "success on multiple mixed msgs", + "success on one new TimeoutOnClose message", + func(suite *AnteTestSuite) []sdk.Msg { + // the TimeoutOnClose message has not been submitted to the chain yet, so it will succeed + return []sdk.Msg{suite.createTimeoutOnCloseMessage(uint64(1), false)} + }, + true, + }, + { + "success on three new messages of each type", func(suite *AnteTestSuite) []sdk.Msg { var msgs []sdk.Msg + // none of the messages of each type has been submitted to the chain yet, + // the first message is succeed and the next two of each type will be rejected + // because they are redundant. + + // from A to B for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - err := suite.path.EndpointA.SendPacket(packet) - suite.Require().NoError(err) - - msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) - } - for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) - err := suite.path.EndpointB.SendPacket(packet) - suite.Require().NoError(err) - - msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + msgs = append(msgs, suite.createRecvPacketMessage(uint64(i), false)) } - for i := 4; i <= 6; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) - err := suite.path.EndpointB.SendPacket(packet) - suite.Require().NoError(err) - - msgs = append(msgs, channeltypes.NewMsgTimeout(packet, uint64(i), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + + // from B to A + for i := 1; i <= 9; i++ { + switch { + case i >= 1 && i <= 3: + msgs = append(msgs, suite.createAcknowledgementMessage(uint64(i), false)) + case i >= 4 && i <= 6: + msgs = append(msgs, suite.createTimeoutMessage(uint64(i), false)) + case i >= 7 && i <= 9: + msgs = append(msgs, suite.createTimeoutOnCloseMessage(uint64(i), false)) + } } return msgs }, true, }, { - "success on multiple mixed msgs: 1 fresh packet of each type", + "success on three redundant messages of RecvPacket, Acknowledgement and TimeoutOnClose, and one new Timeout message", func(suite *AnteTestSuite) []sdk.Msg { var msgs []sdk.Msg - for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - err := suite.path.EndpointA.SendPacket(packet) - suite.Require().NoError(err) - - // receive all sequences except packet 3 - if i != 3 { - - err := suite.path.EndpointB.RecvPacket(packet) - suite.Require().NoError(err) - } + // we pass three messages of RecvPacket, Acknowledgement and TimeoutOnClose that + // are all redundant (i.e. those messages have already been submitted and + // processed by the chain). But these messages will not be rejected because the + // Timeout message is new. - msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) - } + // from A to B for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) - err := suite.path.EndpointB.SendPacket(packet) - suite.Require().NoError(err) - - // receive all acks except ack 2 - if i != 2 { - err = suite.path.EndpointA.RecvPacket(packet) - suite.Require().NoError(err) - err = suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) - suite.Require().NoError(err) - } - - msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + msgs = append(msgs, suite.createRecvPacketMessage(uint64(i), true)) } - for i := 4; i <= 6; i++ { - height := suite.chainA.LastHeader.GetHeight() - timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - timeoutHeight, 0) - err := suite.path.EndpointB.SendPacket(packet) - suite.Require().NoError(err) - - // timeout packet - suite.coordinator.CommitNBlocks(suite.chainA, 3) - - // timeout packets except sequence 5 - if i != 5 { - suite.path.EndpointB.UpdateClient() - err = suite.path.EndpointB.TimeoutPacket(packet) - suite.Require().NoError(err) - } - msgs = append(msgs, channeltypes.NewMsgTimeout(packet, uint64(i), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + // from B to A + for i := 1; i <= 7; i++ { + switch { + case i >= 1 && i <= 3: + msgs = append(msgs, suite.createAcknowledgementMessage(uint64(i), true)) + case i == 4: + msgs = append(msgs, suite.createTimeoutMessage(uint64(i), false)) + case i >= 5 && i <= 7: + msgs = append(msgs, suite.createTimeoutOnCloseMessage(uint64(i), true)) + } } return msgs }, true, }, { - "success on multiple mixed msgs: only 1 fresh msg in total", + "success on one new message and two redundant messages of each type", func(suite *AnteTestSuite) []sdk.Msg { var msgs []sdk.Msg - for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - // receive all packets - suite.path.EndpointA.SendPacket(packet) - suite.path.EndpointB.RecvPacket(packet) + // For each type there is a new message and two messages that are redundant + // (i.e. they have been already submitted and processed by the chain). But all + // the redundant messages will not be rejected because there is a new message + // of each type. - msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) - } + // from A to B for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - // receive all acks - suite.path.EndpointB.SendPacket(packet) - suite.path.EndpointA.RecvPacket(packet) - suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) - - msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + msgs = append(msgs, suite.createRecvPacketMessage(uint64(i), i != 2)) } - for i := 4; i < 5; i++ { - height := suite.chainA.LastHeader.GetHeight() - timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - timeoutHeight, 0) - - // do not timeout packet, timeout msg is fresh - suite.path.EndpointB.SendPacket(packet) - - msgs = append(msgs, channeltypes.NewMsgTimeout(packet, uint64(i), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + + // from B to A + for i := 1; i <= 9; i++ { + switch { + case i >= 1 && i <= 3: + msgs = append(msgs, suite.createAcknowledgementMessage(uint64(i), i != 2)) + case i >= 4 && i <= 6: + msgs = append(msgs, suite.createTimeoutMessage(uint64(i), i != 5)) + case i >= 7 && i <= 9: + msgs = append(msgs, suite.createTimeoutOnCloseMessage(uint64(i), i != 8)) + } } return msgs }, true, }, { - "success on single update client msg", + "success on one new UpdateClient message", func(suite *AnteTestSuite) []sdk.Msg { - return []sdk.Msg{&clienttypes.MsgUpdateClient{}} + return []sdk.Msg{suite.createUpdateClientMessage()} }, true, }, { - "success on multiple update clients", + "success on three new UpdateClient messages", func(suite *AnteTestSuite) []sdk.Msg { - return []sdk.Msg{&clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}} + return []sdk.Msg{suite.createUpdateClientMessage(), suite.createUpdateClientMessage(), suite.createUpdateClientMessage()} }, true, }, { - "success on multiple update clients and fresh packet message", + "success on three new Updateclient messages and one new RecvPacket message", func(suite *AnteTestSuite) []sdk.Msg { - msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}} - - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), 1, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - return append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + return []sdk.Msg{ + suite.createUpdateClientMessage(), + suite.createUpdateClientMessage(), + suite.createUpdateClientMessage(), + suite.createRecvPacketMessage(uint64(1), false), + } }, true, }, { - "success of tx with different msg type even if all packet messages are redundant", + "success on three redundant RecvPacket messages and one SubmitMisbehaviour message", func(suite *AnteTestSuite) []sdk.Msg { - msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{}} + msgs := []sdk.Msg{suite.createUpdateClientMessage()} for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - // receive all packets - suite.path.EndpointA.SendPacket(packet) - suite.path.EndpointB.RecvPacket(packet) - - msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) - } - for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - // receive all acks - suite.path.EndpointB.SendPacket(packet) - suite.path.EndpointA.RecvPacket(packet) - suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) - - msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) - } - for i := 4; i < 6; i++ { - height := suite.chainA.LastHeader.GetHeight() - timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - timeoutHeight, 0) - - err := suite.path.EndpointB.SendPacket(packet) - suite.Require().NoError(err) - - // timeout packet - suite.coordinator.CommitNBlocks(suite.chainA, 3) - - suite.path.EndpointB.UpdateClient() - suite.path.EndpointB.TimeoutPacket(packet) - - msgs = append(msgs, channeltypes.NewMsgTimeoutOnClose(packet, uint64(i), []byte("proof"), []byte("channelProof"), clienttypes.NewHeight(0, 1), "signer")) + msgs = append(msgs, suite.createRecvPacketMessage(uint64(i), true)) } // append non packet and update message to msgs to ensure multimsg tx should pass msgs = append(msgs, &clienttypes.MsgSubmitMisbehaviour{}) - return msgs }, true, }, { - "no success on multiple mixed message: all are redundant", + "no success on one redundant RecvPacket message", + func(suite *AnteTestSuite) []sdk.Msg { + return []sdk.Msg{suite.createRecvPacketMessage(uint64(1), true)} + }, + false, + }, + { + "no success on three redundant messages of each type", func(suite *AnteTestSuite) []sdk.Msg { var msgs []sdk.Msg + // from A to B for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - // receive all packets - suite.path.EndpointA.SendPacket(packet) - suite.path.EndpointB.RecvPacket(packet) - - msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + msgs = append(msgs, suite.createRecvPacketMessage(uint64(i), true)) } - for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) - // receive all acks - suite.path.EndpointB.SendPacket(packet) - suite.path.EndpointA.RecvPacket(packet) - suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) - - msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) - } - for i := 4; i < 6; i++ { - height := suite.chainA.LastHeader.GetHeight() - timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - timeoutHeight, 0) - - err := suite.path.EndpointB.SendPacket(packet) - suite.Require().NoError(err) - - // timeout packet - suite.coordinator.CommitNBlocks(suite.chainA, 3) - - suite.path.EndpointB.UpdateClient() - suite.path.EndpointB.TimeoutPacket(packet) - - msgs = append(msgs, channeltypes.NewMsgTimeoutOnClose(packet, uint64(i), []byte("proof"), []byte("channelProof"), clienttypes.NewHeight(0, 1), "signer")) + // from B to A + for i := 1; i <= 9; i++ { + switch { + case i >= 1 && i <= 3: + msgs = append(msgs, suite.createAcknowledgementMessage(uint64(i), true)) + case i >= 4 && i <= 6: + msgs = append(msgs, suite.createTimeoutMessage(uint64(i), true)) + case i >= 7 && i <= 9: + msgs = append(msgs, suite.createTimeoutOnCloseMessage(uint64(i), true)) + } } return msgs }, false, }, { - "no success if msgs contain update clients and redundant packet messages", + "no success on one new UpdateClient message and three redundant RecvPacket messages", func(suite *AnteTestSuite) []sdk.Msg { - msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}, &clienttypes.MsgUpdateClient{}} + msgs := []sdk.Msg{&clienttypes.MsgUpdateClient{}} for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - clienttypes.NewHeight(1, 0), 0) - - // receive all packets - suite.path.EndpointA.SendPacket(packet) - suite.path.EndpointB.RecvPacket(packet) - - msgs = append(msgs, channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + msgs = append(msgs, suite.createRecvPacketMessage(uint64(i), true)) } - for i := 1; i <= 3; i++ { - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) - // receive all acks - suite.path.EndpointB.SendPacket(packet) - suite.path.EndpointA.RecvPacket(packet) - suite.path.EndpointB.AcknowledgePacket(packet, mock.MockAcknowledgement.Acknowledgement()) + return msgs + }, + false, + }, + { + "no success on three new UpdateClient messages and three redundant messages of each type", + func(suite *AnteTestSuite) []sdk.Msg { + msgs := []sdk.Msg{suite.createUpdateClientMessage(), suite.createUpdateClientMessage(), suite.createUpdateClientMessage()} - msgs = append(msgs, channeltypes.NewMsgAcknowledgement(packet, []byte("ack"), []byte("proof"), clienttypes.NewHeight(0, 1), "signer")) + // from A to B + for i := 1; i <= 3; i++ { + msgs = append(msgs, suite.createRecvPacketMessage(uint64(i), true)) } - for i := 4; i < 6; i++ { - height := suite.chainA.LastHeader.GetHeight() - timeoutHeight := clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+1) - packet := channeltypes.NewPacket([]byte(mock.MockPacketData), uint64(i), - suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, - timeoutHeight, 0) - - err := suite.path.EndpointB.SendPacket(packet) - suite.Require().NoError(err) - - // timeout packet - suite.coordinator.CommitNBlocks(suite.chainA, 3) - suite.path.EndpointB.UpdateClient() - suite.path.EndpointB.TimeoutPacket(packet) - - msgs = append(msgs, channeltypes.NewMsgTimeoutOnClose(packet, uint64(i), []byte("proof"), []byte("channelProof"), clienttypes.NewHeight(0, 1), "signer")) + // from B to A + for i := 1; i <= 9; i++ { + switch { + case i >= 1 && i <= 3: + msgs = append(msgs, suite.createAcknowledgementMessage(uint64(i), true)) + case i >= 4 && i <= 6: + msgs = append(msgs, suite.createTimeoutMessage(uint64(i), true)) + case i >= 7 && i <= 9: + msgs = append(msgs, suite.createTimeoutOnCloseMessage(uint64(i), true)) + } } return msgs }, false, }, + { + "no success on one new message and one invalid message", + func(suite *AnteTestSuite) []sdk.Msg { + packet := channeltypes.NewPacket(ibctesting.MockPacketData, 2, + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(1, 0), 0) + + return []sdk.Msg{ + suite.createRecvPacketMessage(uint64(1), false), + channeltypes.NewMsgRecvPacket(packet, []byte("proof"), clienttypes.NewHeight(0, 1), "signer"), + } + }, + false, + }, + { + "no success on one new message and one redundant message in the same block", + func(suite *AnteTestSuite) []sdk.Msg { + msg := suite.createRecvPacketMessage(uint64(1), false) + + // We want to be able to run check tx with the non-redundant message without + // commiting it to a block, so that the when check tx runs with the redundant + // message they are both in the same block + k := suite.chainB.App.GetIBCKeeper() + decorator := ante.NewAnteDecorator(k) + checkCtx := suite.chainB.GetContext().WithIsCheckTx(true) + next := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil } + txBuilder := suite.chainB.TxConfig.NewTxBuilder() + err := txBuilder.SetMsgs([]sdk.Msg{msg}...) + suite.Require().NoError(err) + tx := txBuilder.GetTx() + + _, err = decorator.AnteHandle(checkCtx, tx, false, next) + suite.Require().NoError(err) + + return []sdk.Msg{msg} + }, + false, + }, } for _, tc := range testCases { @@ -456,7 +457,7 @@ func (suite *AnteTestSuite) TestAnteDecorator() { // reset suite suite.SetupTest() - k := suite.chainB.App.GetIBCKeeper().ChannelKeeper + k := suite.chainB.App.GetIBCKeeper() decorator := ante.NewAnteDecorator(k) msgs := tc.malleate(suite) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index a380540614c..be18391c698 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -395,7 +395,7 @@ func (k Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPacke case nil: writeFn() case channeltypes.ErrNoOpMsg: - return &channeltypes.MsgRecvPacketResponse{}, nil // no-op + return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.NOOP}, nil default: return nil, sdkerrors.Wrap(err, "receive packet verification failed") } @@ -435,7 +435,7 @@ func (k Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPacke ) }() - return &channeltypes.MsgRecvPacketResponse{}, nil + return &channeltypes.MsgRecvPacketResponse{Result: channeltypes.SUCCESS}, nil } // Timeout defines a rpc handler method for MsgTimeout. @@ -473,7 +473,7 @@ func (k Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (*c case nil: writeFn() case channeltypes.ErrNoOpMsg: - return &channeltypes.MsgTimeoutResponse{}, nil // no-op + return &channeltypes.MsgTimeoutResponse{Result: channeltypes.NOOP}, nil default: return nil, sdkerrors.Wrap(err, "timeout packet verification failed") } @@ -503,7 +503,7 @@ func (k Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (*c ) }() - return &channeltypes.MsgTimeoutResponse{}, nil + return &channeltypes.MsgTimeoutResponse{Result: channeltypes.SUCCESS}, nil } // TimeoutOnClose defines a rpc handler method for MsgTimeoutOnClose. @@ -541,7 +541,7 @@ func (k Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTimeo case nil: writeFn() case channeltypes.ErrNoOpMsg: - return &channeltypes.MsgTimeoutOnCloseResponse{}, nil // no-op + return &channeltypes.MsgTimeoutOnCloseResponse{Result: channeltypes.NOOP}, nil default: return nil, sdkerrors.Wrap(err, "timeout on close packet verification failed") } @@ -574,7 +574,7 @@ func (k Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTimeo ) }() - return &channeltypes.MsgTimeoutOnCloseResponse{}, nil + return &channeltypes.MsgTimeoutOnCloseResponse{Result: channeltypes.SUCCESS}, nil } // Acknowledgement defines a rpc handler method for MsgAcknowledgement. @@ -612,7 +612,7 @@ func (k Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAckn case nil: writeFn() case channeltypes.ErrNoOpMsg: - return &channeltypes.MsgAcknowledgementResponse{}, nil // no-op + return &channeltypes.MsgAcknowledgementResponse{Result: channeltypes.NOOP}, nil default: return nil, sdkerrors.Wrap(err, "acknowledge packet verification failed") } @@ -636,5 +636,5 @@ func (k Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAckn ) }() - return &channeltypes.MsgAcknowledgementResponse{}, nil + return &channeltypes.MsgAcknowledgementResponse{Result: channeltypes.SUCCESS}, nil } diff --git a/proto/ibc/core/channel/v1/tx.proto b/proto/ibc/core/channel/v1/tx.proto index 7fc8f730e33..d4d6df1d5e9 100644 --- a/proto/ibc/core/channel/v1/tx.proto +++ b/proto/ibc/core/channel/v1/tx.proto @@ -42,6 +42,18 @@ service Msg { rpc Acknowledgement(MsgAcknowledgement) returns (MsgAcknowledgementResponse); } +// ResponseResultType defines the possible outcomes of the execution of a message +enum ResponseResultType { + option (gogoproto.goproto_enum_prefix) = false; + + // Default zero value enumeration + RESPONSE_RESULT_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; + // The message did not call the IBC application callbacks (because, for example, the packet had already been relayed) + RESPONSE_RESULT_NOOP = 1 [(gogoproto.enumvalue_customname) = "NOOP"]; + // The message was executed successfully + RESPONSE_RESULT_SUCCESS = 2 [(gogoproto.enumvalue_customname) = "SUCCESS"]; +} + // MsgChannelOpenInit defines an sdk.Msg to initialize a channel handshake. It // is called by a relayer on Chain A. message MsgChannelOpenInit { @@ -163,7 +175,11 @@ message MsgRecvPacket { } // MsgRecvPacketResponse defines the Msg/RecvPacket response type. -message MsgRecvPacketResponse {} +message MsgRecvPacketResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} // MsgTimeout receives timed-out packet message MsgTimeout { @@ -179,7 +195,11 @@ message MsgTimeout { } // MsgTimeoutResponse defines the Msg/Timeout response type. -message MsgTimeoutResponse {} +message MsgTimeoutResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} // MsgTimeoutOnClose timed-out packet upon counterparty channel closure. message MsgTimeoutOnClose { @@ -196,7 +216,11 @@ message MsgTimeoutOnClose { } // MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type. -message MsgTimeoutOnCloseResponse {} +message MsgTimeoutOnCloseResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} // MsgAcknowledgement receives incoming IBC acknowledgement message MsgAcknowledgement { @@ -212,4 +236,8 @@ message MsgAcknowledgement { } // MsgAcknowledgementResponse defines the Msg/Acknowledgement response type. -message MsgAcknowledgementResponse {} +message MsgAcknowledgementResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} diff --git a/testing/endpoint.go b/testing/endpoint.go index 5c2e2e33f4f..513fc8923cf 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -462,6 +462,36 @@ func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { return endpoint.Chain.sendMsgs(timeoutMsg) } +// TimeoutOnClose sends a MsgTimeoutOnClose to the channel associated with the endpoint. +func (endpoint *Endpoint) TimeoutOnClose(packet channeltypes.Packet) error { + // get proof for timeout based on channel order + var packetKey []byte + + switch endpoint.ChannelConfig.Order { + case channeltypes.ORDERED: + packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) + case channeltypes.UNORDERED: + packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + default: + return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) + } + + proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) + + channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel()) + proofClosed, _ := endpoint.Counterparty.QueryProof(channelKey) + + nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + require.True(endpoint.Chain.T, found) + + timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnClose( + packet, nextSeqRecv, + proof, proofClosed, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(timeoutOnCloseMsg) +} + // SetChannelClosed sets a channel state to CLOSED. func (endpoint *Endpoint) SetChannelClosed() error { channel := endpoint.GetChannel() diff --git a/testing/simapp/ante_handler.go b/testing/simapp/ante_handler.go index 8e3e1f069ec..04ffad13e2a 100644 --- a/testing/simapp/ante_handler.go +++ b/testing/simapp/ante_handler.go @@ -5,16 +5,15 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - channelkeeper "github.com/cosmos/ibc-go/v3/modules/core/04-channel/keeper" ibcante "github.com/cosmos/ibc-go/v3/modules/core/ante" + "github.com/cosmos/ibc-go/v3/modules/core/keeper" ) -// HandlerOptions extend the SDK's AnteHandler options by requiring the IBC -// channel keeper. +// HandlerOptions extend the SDK's AnteHandler options by requiring the IBC keeper. type HandlerOptions struct { ante.HandlerOptions - IBCChannelkeeper channelkeeper.Keeper + IBCKeeper *keeper.Keeper } // NewAnteHandler creates a new ante handler @@ -49,7 +48,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), - ibcante.NewAnteDecorator(options.IBCChannelkeeper), + ibcante.NewAnteDecorator(options.IBCKeeper), } return sdk.ChainAnteDecorators(anteDecorators...), nil diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 15add30faaf..ee148806852 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -503,7 +503,7 @@ func NewSimApp( FeegrantKeeper: app.FeeGrantKeeper, SigGasConsumer: ante.DefaultSigVerificationGasConsumer, }, - IBCChannelkeeper: app.IBCKeeper.ChannelKeeper, + IBCKeeper: app.IBCKeeper, }, ) if err != nil { From d40f1da72649ad720c7926069cd0b0454997a19d Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 10 Mar 2022 21:13:14 +0100 Subject: [PATCH 033/275] add backport rules for v1.4.x and v2.2.x (#1085) --- .github/mergify.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/mergify.yml b/.github/mergify.yml index 5d1dca08360..70c3828d03f 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -42,6 +42,14 @@ pull_request_rules: backport: branches: - release/v1.3.x + - name: backport patches to v1.4.x branch + conditions: + - base=main + - label=backport-to-v1.4.x + actions: + backport: + branches: + - release/v1.4.x - name: backport patches to v2.0.x branch conditions: - base=main @@ -57,7 +65,15 @@ pull_request_rules: actions: backport: branches: - - release/v2.1.x + - release/v2.1.x + - name: backport patches to v2.2.x branch + conditions: + - base=main + - label=backport-to-v2.2.x + actions: + backport: + branches: + - release/v2.2.x - name: backport patches to v3.0.x branch conditions: - base=main From c32e4bea2500bee1d2fab4b2ad4908563f7f8a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Fri, 11 Mar 2022 11:58:22 +0100 Subject: [PATCH 034/275] ibctesting: custom voting power reduction for testing (#939) * ibctesting: custom voting power reduction for testing * changelog * fix * make T public * fix * revert changes * fix test --- CHANGELOG.md | 3 ++- go.sum | 4 ---- testing/app.go | 18 +++++++++++++----- testing/chain.go | 15 ++++++--------- testing/coordinator.go | 12 ++---------- testing/endpoint.go | 4 ++-- 6 files changed, 25 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7091c758777..d000d053a89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (core) [\#709](https://github.com/cosmos/ibc-go/pull/709) Replace github.com/pkg/errors with stdlib errors ### API Breaking - + +* (testing) [\#939](https://github.com/cosmos/ibc-go/pull/939) Support custom power reduction for testing. * (modules/core/05-port) [\#1086](https://github.com/cosmos/ibc-go/pull/1086) Added `counterpartyChannelID` argument to IBCModule.OnChanOpenAck * (channel) [\#848](https://github.com/cosmos/ibc-go/pull/848) Added `ChannelId` to MsgChannelOpenInitResponse * (testing) [\#813](https://github.com/cosmos/ibc-go/pull/813) The `ack` argument to the testing function `RelayPacket` has been removed as it is no longer needed. diff --git a/go.sum b/go.sum index 9caa6a21997..5544d71eb5f 100644 --- a/go.sum +++ b/go.sum @@ -466,7 +466,6 @@ github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIv github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= @@ -801,7 +800,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= -github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= @@ -1313,7 +1311,6 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1426,7 +1423,6 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= diff --git a/testing/app.go b/testing/app.go index 320bb0f00a7..3c6a14ed453 100644 --- a/testing/app.go +++ b/testing/app.go @@ -58,8 +58,9 @@ func SetupTestingApp() (TestingApp, map[string]json.RawMessage) { // that also act as delegators. For simplicity, each validator is bonded with a delegation // of one consensus engine unit (10^6) in the default token of the simapp from first genesis // account. A Nop logger is set in SimApp. -func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, balances ...banktypes.Balance) TestingApp { +func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, powerReduction sdk.Int, balances ...banktypes.Balance) TestingApp { app, genesisState := DefaultTestingAppInit() + // set genesis accounts authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) @@ -67,7 +68,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) - bondAmt := sdk.NewInt(1000000) + bondAmt := sdk.TokensFromConsensusPower(1, powerReduction) for _, val := range valSet.Validators { pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) @@ -87,21 +88,28 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), MinSelfDelegation: sdk.ZeroInt(), } + validators = append(validators, validator) delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec())) } + // set validators and delegations + var stakingGenesis stakingtypes.GenesisState + app.AppCodec().MustUnmarshalJSON(genesisState[stakingtypes.ModuleName], &stakingGenesis) + + bondDenom := stakingGenesis.Params.BondDenom + totalSupply := sdk.NewCoins() // add bonded amount to bonded pool module account balances = append(balances, banktypes.Balance{ Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), - Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt.Mul(sdk.NewInt(int64(len(valSet.Validators)))))}, + Coins: sdk.Coins{sdk.NewCoin(bondDenom, bondAmt.Mul(sdk.NewInt(int64(len(valSet.Validators)))))}, }) // set validators and delegations - stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) - genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis) + stakingGenesis = *stakingtypes.NewGenesisState(stakingGenesis.Params, validators, delegations) + genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&stakingGenesis) // update total supply bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}) diff --git a/testing/chain.go b/testing/chain.go index 4199595c1b9..28382a6c463 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -113,7 +113,7 @@ func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, va senderAccs = append(senderAccs, senderAcc) } - app := SetupWithGenesisValSet(t, valSet, genAccs, chainID, genBals...) + app := SetupWithGenesisValSet(t, valSet, genAccs, chainID, sdk.DefaultPowerReduction, genBals...) // create current header and call begin block header := tmproto.Header{ @@ -453,6 +453,7 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, EvidenceHash: tmhash.Sum([]byte("evidence_hash")), ProposerAddress: tmValSet.Proposer.Address, //nolint:staticcheck } + hhash := tmHeader.Hash() blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set"))) voteSet := tmtypes.NewVoteSet(chainID, blockHeight, 1, tmproto.PrecommitType, tmValSet) @@ -467,16 +468,12 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, if tmValSet != nil { valSet, err = tmValSet.ToProto() - if err != nil { - panic(err) - } + require.NoError(chain.T, err) } if tmTrustedVals != nil { trustedVals, err = tmTrustedVals.ToProto() - if err != nil { - panic(err) - } + require.NoError(chain.T, err) } // The trusted fields may be nil. They may be filled before relaying messages to a client. @@ -505,8 +502,8 @@ func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) tmtypes.Bl // sorting of ValidatorSet. // The sorting is first by .VotingPower (descending), with secondary index of .Address (ascending). func CreateSortedSignerArray(altPrivVal, suitePrivVal tmtypes.PrivValidator, - altVal, suiteVal *tmtypes.Validator) []tmtypes.PrivValidator { - + altVal, suiteVal *tmtypes.Validator, +) []tmtypes.PrivValidator { switch { case altVal.VotingPower > suiteVal.VotingPower: return []tmtypes.PrivValidator{altPrivVal, suitePrivVal} diff --git a/testing/coordinator.go b/testing/coordinator.go index 65bf5a4f1f3..217c257473a 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -212,11 +212,7 @@ func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error { return err } - if err := path.EndpointB.UpdateClient(); err != nil { - return err - } - - return nil + return path.EndpointB.UpdateClient() } // ChanOpenInitOnBothChains initializes a channel on the source chain and counterparty chain @@ -237,9 +233,5 @@ func (coord *Coordinator) ChanOpenInitOnBothChains(path *Path) error { return err } - if err := path.EndpointB.UpdateClient(); err != nil { - return err - } - - return nil + return path.EndpointB.UpdateClient() } diff --git a/testing/endpoint.go b/testing/endpoint.go index 513fc8923cf..607f7a16843 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -67,7 +67,7 @@ func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) { } // QueryProofAtHeight queries proof associated with this endpoint using the proof height -// providied +// provided func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, clienttypes.Height) { // query proof on the counterparty using the latest height of the IBC client return endpoint.Chain.QueryProofAtHeight(key, int64(height)) @@ -98,7 +98,7 @@ func (endpoint *Endpoint) CreateClient() (err error) { consensusState = endpoint.Counterparty.Chain.LastHeader.ConsensusState() case exported.Solomachine: // TODO - // solo := NewSolomachine(Chain.T, endpoint.Chain.Codec, clientID, "", 1) + // solo := NewSolomachine(endpoint.Chain.T, endpoint.Chain.Codec, clientID, "", 1) // clientState = solo.ClientState() // consensusState = solo.ConsensusState() From 3f8858a1ff3615c2e1da2e2cc75ee8021fddfb3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Mar 2022 10:23:45 +0100 Subject: [PATCH 035/275] build(deps): bump github.com/spf13/cobra from 1.3.0 to 1.4.0 (#1105) --- go.mod | 2 +- go.sum | 19 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index eb9dc1a9548..3c94237d3a9 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.3.1 github.com/spf13/cast v1.4.1 - github.com/spf13/cobra v1.3.0 + github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.10.1 github.com/stretchr/testify v1.7.0 github.com/tendermint/tendermint v0.34.14 diff --git a/go.sum b/go.sum index 5544d71eb5f..636d4902fd1 100644 --- a/go.sum +++ b/go.sum @@ -25,7 +25,6 @@ cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aD cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= @@ -465,7 +464,7 @@ github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uM github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= @@ -499,13 +498,10 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87/go.mod h1:XGsKKeXxeRr95aEOgipvluMPlgjr7dGlk9ZTWOjcUcg= @@ -799,7 +795,7 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= +github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= @@ -835,8 +831,8 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= -github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= +github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -848,7 +844,6 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= @@ -1188,7 +1183,6 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1310,7 +1304,7 @@ google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1384,8 +1378,6 @@ google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= @@ -1423,6 +1415,7 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= From e0ae0cd84433113a1016f12f2d478e128b244fa2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Mar 2022 11:18:02 +0100 Subject: [PATCH 036/275] build(deps): bump google.golang.org/grpc from 1.44.0 to 1.45.0 (#1098) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.44.0 to 1.45.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.44.0...v1.45.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3c94237d3a9..02190cf20ac 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/tendermint/tendermint v0.34.14 github.com/tendermint/tm-db v0.6.4 google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa - google.golang.org/grpc v1.44.0 + google.golang.org/grpc v1.45.0 google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 636d4902fd1..2e25c13e01f 100644 --- a/go.sum +++ b/go.sum @@ -1416,8 +1416,8 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 0a81a52adc8482aab8467b19023c2233e6cca968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 15 Mar 2022 12:49:48 +0100 Subject: [PATCH 037/275] fix: adjust InitModule to account for empty controller and host keepers (#1120) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [x] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [x] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [x] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [x] Review `Codecov Report` in the comment section below once CI passes --- docs/migrations/v2-to-v3.md | 7 +- modules/apps/27-interchain-accounts/module.go | 15 ++-- .../27-interchain-accounts/module_test.go | 76 ++++++++++++++++--- 3 files changed, 82 insertions(+), 16 deletions(-) diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index 6b1c61735fc..a37f74cf420 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -58,8 +58,8 @@ app.UpgradeKeeper.SetUpgradeHandler("v3", ``` -The host and controller submodule params only need to be set if you integrate those submodules. -For example, if a chain chooses not to integrate a controller submodule, it does not need to set the controller params. +The host and controller submodule params only need to be set if the chain integrates those submodules. +For example, if a chain chooses not to integrate a controller submodule, it may pass empty params into `InitModule`. #### Add `StoreUpgrades` for ICS27 module @@ -76,6 +76,9 @@ if upgradeInfo.Name == "v3" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Heigh ``` This ensures that the new module's stores are added to the multistore before the migrations begin. +The host and controller submodule keys only need to be added if the chain integrates those submodules. +For example, if a chain chooses not to integrate a controller submodule, it does not need to add the controller key to the `Added` field. + ### Genesis migrations diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 969c07caf9d..1bb870fca5d 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -105,12 +105,17 @@ func NewAppModule(controllerKeeper *controllerkeeper.Keeper, hostKeeper *hostkee // InitModule will initialize the interchain accounts moudule. It should only be // called once and as an alternative to InitGenesis. func (am AppModule) InitModule(ctx sdk.Context, controllerParams controllertypes.Params, hostParams hosttypes.Params) { - am.controllerKeeper.SetParams(ctx, controllerParams) - am.hostKeeper.SetParams(ctx, hostParams) + if am.controllerKeeper != nil { + am.controllerKeeper.SetParams(ctx, controllerParams) + } + + if am.hostKeeper != nil { + am.hostKeeper.SetParams(ctx, hostParams) - cap := am.hostKeeper.BindPort(ctx, types.PortID) - if err := am.hostKeeper.ClaimCapability(ctx, cap, ibchost.PortPath(types.PortID)); err != nil { - panic(fmt.Sprintf("could not claim port capability: %v", err)) + cap := am.hostKeeper.BindPort(ctx, types.PortID) + if err := am.hostKeeper.ClaimCapability(ctx, cap, ibchost.PortPath(types.PortID)); err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } } } diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go index de5f51ae921..59517ab40e4 100644 --- a/modules/apps/27-interchain-accounts/module_test.go +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -31,8 +31,9 @@ func (suite *InterchainAccountsTestSuite) SetupTest() { } func (suite *InterchainAccountsTestSuite) TestInitModule() { + // setup and basic testing app := simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) - icamodule, ok := app.GetModuleManager().Modules[types.ModuleName].(ica.AppModule) + appModule, ok := app.GetModuleManager().Modules[types.ModuleName].(ica.AppModule) suite.Require().True(ok) header := tmproto.Header{ @@ -58,17 +59,74 @@ func (suite *InterchainAccountsTestSuite) TestInitModule() { expAllowMessages := []string{"sdk.Msg"} hostParams.HostEnabled = true hostParams.AllowMessages = expAllowMessages - suite.Require().False(app.IBCKeeper.PortKeeper.IsBound(ctx, types.PortID)) - icamodule.InitModule(ctx, controllerParams, hostParams) + testCases := []struct { + name string + malleate func() + expControllerPass bool + expHostPass bool + }{ + { + "both controller and host set", func() { + var ok bool + appModule, ok = app.GetModuleManager().Modules[types.ModuleName].(ica.AppModule) + suite.Require().True(ok) + }, true, true, + }, + { + "neither controller or host is set", func() { + appModule = ica.NewAppModule(nil, nil) + }, false, false, + }, + { + "only controller is set", func() { + appModule = ica.NewAppModule(&app.ICAControllerKeeper, nil) + }, true, false, + }, + { + "only host is set", func() { + appModule = ica.NewAppModule(nil, &app.ICAHostKeeper) + }, false, true, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + // reset app state + app = simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) + header := tmproto.Header{ + ChainID: "testchain", + Height: 1, + Time: suite.coordinator.CurrentTime.UTC(), + } + + ctx := app.GetBaseApp().NewContext(true, header) - controllerParams = app.ICAControllerKeeper.GetParams(ctx) - suite.Require().True(controllerParams.ControllerEnabled) + tc.malleate() - hostParams = app.ICAHostKeeper.GetParams(ctx) - suite.Require().True(hostParams.HostEnabled) - suite.Require().Equal(expAllowMessages, hostParams.AllowMessages) + suite.Require().NotPanics(func() { + appModule.InitModule(ctx, controllerParams, hostParams) + }) + + if tc.expControllerPass { + controllerParams = app.ICAControllerKeeper.GetParams(ctx) + suite.Require().True(controllerParams.ControllerEnabled) + } + + if tc.expHostPass { + hostParams = app.ICAHostKeeper.GetParams(ctx) + suite.Require().True(hostParams.HostEnabled) + suite.Require().Equal(expAllowMessages, hostParams.AllowMessages) + + suite.Require().True(app.IBCKeeper.PortKeeper.IsBound(ctx, types.PortID)) + } + + }) + } - suite.Require().True(app.IBCKeeper.PortKeeper.IsBound(ctx, types.PortID)) } From 13bc4a06aff8f48e12dff2dba6f84206fa429c96 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 15 Mar 2022 14:11:53 +0100 Subject: [PATCH 038/275] Merge pull request from GHSA-j658-c98j-fww4 Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/keeper/relay.go | 4 ++++ modules/apps/transfer/keeper/relay_test.go | 10 ++++++++++ modules/apps/transfer/types/expected_keepers.go | 1 + 3 files changed, 15 insertions(+) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index ab7f3751588..3c3a5aa6690 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -239,6 +239,10 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t } token := sdk.NewCoin(denom, transferAmount) + if k.bankKeeper.BlockedAddr(receiver) { + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) + } + // unescrow tokens escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) if err := k.bankKeeper.SendCoins(ctx, escrowAddress, receiver, sdk.NewCoins(token)); err != nil { diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 9d03bbde962..ce34f316669 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -167,6 +167,16 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { {"tries to unescrow more tokens than allowed", func() { amount = sdk.NewInt(1000000) }, true, false}, + + // - coin being sent to module address on chainA + {"failure: receive on module account", func() { + receiver = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName).String() + }, false, false}, + + // - coin being sent back to original chain (chainB) to module address + {"failure: receive on module account on source chain", func() { + receiver = suite.chainB.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName).String() + }, true, false}, } for _, tc := range testCases { diff --git a/modules/apps/transfer/types/expected_keepers.go b/modules/apps/transfer/types/expected_keepers.go index 8ae670d27b2..22ad54b9e62 100644 --- a/modules/apps/transfer/types/expected_keepers.go +++ b/modules/apps/transfer/types/expected_keepers.go @@ -23,6 +23,7 @@ type BankKeeper interface { BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + BlockedAddr(addr sdk.AccAddress) bool } // ICS4Wrapper defines the expected ICS4Wrapper for middleware From 4fe874eb45519b6697948f29c3a48d327b9c3d06 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 15 Mar 2022 15:55:59 +0100 Subject: [PATCH 039/275] fixes for the documentation about handling ack for SDK <= 0.45 (#1122) * fixes for documentation * review comment Co-authored-by: Carlos Rodriguez --- docs/apps/interchain-accounts/auth-modules.md | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/apps/interchain-accounts/auth-modules.md b/docs/apps/interchain-accounts/auth-modules.md index b87265d4e28..0e8738f50c0 100644 --- a/docs/apps/interchain-accounts/auth-modules.md +++ b/docs/apps/interchain-accounts/auth-modules.md @@ -220,8 +220,13 @@ If the controller chain is connected to a host chain using the host module on ib Begin by unmarshaling the acknowledgement into sdk.TxMsgData: ```go +var ack channeltypes.Acknowledgement +if err := channeltypes.SubModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + return err +} + txMsgData := &sdk.TxMsgData{} -if err := proto.Unmarshal(ack.Acknowledgement(), txMsgData); err != nil { +if err := proto.Unmarshal(ack.GetResult(), txMsgData); err != nil { return err } ``` @@ -232,6 +237,8 @@ The auth module should interpret the txMsgData.Data as follows: ```go switch len(txMsgData.Data) { case 0: + // see documentation below for SDK 0.46.x or greater +default: for _, msgData := range txMsgData.Data { if err := handler(msgData); err != nil { return err @@ -246,8 +253,8 @@ A router could be used, or more simply a switch statement. ```go func handler(msgData sdk.MsgData) error { -switch msgData.TypeURL { -case banktypes.MsgSend: +switch msgData.MsgType { +case sdk.MsgTypeURL(&banktypes.MsgSend{}): msgResponse := &banktypes.MsgSendResponse{} if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { return err @@ -255,7 +262,7 @@ case banktypes.MsgSend: handleBankSendMsg(msgResponse) -case stakingtypes.MsgDelegate: +case sdk.MsgTypeURL(&stakingtypes.MsgDelegate{}): msgResponse := &stakingtypes.MsgDelegateResponse{} if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { return err @@ -263,7 +270,7 @@ case stakingtypes.MsgDelegate: handleStakingDelegateMsg(msgResponse) -case transfertypes.MsgTransfer: +case sdk.MsgTypeURL(&transfertypes.MsgTransfer{}): msgResponse := &transfertypes.MsgTransferResponse{} if err := proto.Unmarshal(msgData.Data, msgResponse}; err != nil { return err @@ -281,8 +288,8 @@ The auth module should interpret the txMsgData.Responses as follows: ```go ... -// switch statement from above continued -default: +// switch statement from above +case 0: for _, any := range txMsgData.MsgResponses { if err := handleAny(any); err != nil { return err From 9e2cbc246b4b9db9ea773c7055f53e8a89cf7afb Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 16 Mar 2022 12:14:48 +0100 Subject: [PATCH 040/275] Allow testing to update ValidatorSet (#1003) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * testing: adding multiple sender accounts for testing puproses * fix genesis setup (#936) * Update testing/chain.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: code hygiene * Update testing/chain.go Co-authored-by: Aditya * multi validator commit taken from @saione * add function to pass custom valset * create simplest failing test * progress * fix changevalset test * fix errors in tendermint package * fix client types test * fix client keeper * fix cap functions * fix genesis core tests * fix ica tests * fix doc * CHANGELOG * replace signer array with signer map * add documentation * fix merge * documentation * ordered signer array doc * add new delegation and comment to change valset test Co-authored-by: Sean King Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 4 + .../controller/ibc_module_test.go | 2 - .../controller/keeper/keeper_test.go | 1 - .../host/ibc_module_test.go | 2 - .../host/keeper/keeper_test.go | 1 - modules/core/02-client/keeper/client_test.go | 45 ++++---- modules/core/02-client/keeper/keeper_test.go | 10 +- modules/core/02-client/types/genesis_test.go | 5 +- modules/core/02-client/types/msgs_test.go | 8 +- modules/core/genesis_test.go | 4 +- .../types/misbehaviour_handle_test.go | 101 +++++++++--------- .../07-tendermint/types/misbehaviour_test.go | 42 ++++---- .../07-tendermint/types/tendermint_test.go | 16 ++- .../07-tendermint/types/update_test.go | 54 +++++----- testing/app.go | 4 +- testing/chain.go | 85 +++++++-------- testing/chain_test.go | 51 ++++----- testing/coordinator.go | 3 +- testing/simapp/test_helpers.go | 8 +- testing/utils.go | 23 ++++ 20 files changed, 237 insertions(+), 232 deletions(-) create mode 100644 testing/utils.go diff --git a/CHANGELOG.md b/CHANGELOG.md index d000d053a89..35c7eb43f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (testing) [\#1003](https://github.com/cosmos/ibc-go/pull/1003) `CreateTMClientHeader` takes an additional `nextVals *tmtypes.ValidatorSet` as an argument * (testing) [\#939](https://github.com/cosmos/ibc-go/pull/939) Support custom power reduction for testing. * (modules/core/05-port) [\#1086](https://github.com/cosmos/ibc-go/pull/1086) Added `counterpartyChannelID` argument to IBCModule.OnChanOpenAck * (channel) [\#848](https://github.com/cosmos/ibc-go/pull/848) Added `ChannelId` to MsgChannelOpenInitResponse @@ -68,6 +69,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements * (interchain-accounts) [\#1037](https://github.com/cosmos/ibc-go/pull/1037) Add a function `InitModule` to the interchain accounts `AppModule`. This function should be called within the upgrade handler when adding the interchain accounts module to a chain. It should be called in place of InitGenesis (set the consensus version in the version map). +* (testing) [\#1003](https://github.com/cosmos/ibc-go/pull/1003) Testing chain's `Signer` fields has changed from `[]tmtypes.PrivValidator` to `map[string]tmtypes.PrivValidator` to accomodate valset updates changing the order of the ValidatorSet. +* (testing) [\#1003](https://github.com/cosmos/ibc-go/pull/1003) `SignAndDeliver` will now just deliver the transaction without creating and committing a block. Thus, it requires that `BeginBlock` MUST be called before `SignAndDeliver` +* (testing) [\#1003](https://github.com/cosmos/ibc-go/pull/1003) `NextBlock` will now call `EndBlock` and `Commit` internally and apply validator updates to the `NextVals` of `TestChain` and the `NextValsHash` of the current header. Test writers can now make changes to validator set and have them reflected in the `TestChain` and handled appropriately in `UpdateClient` * (testing) [\#942](https://github.com/cosmos/ibc-go/pull/942) `NewTestChain` will create 4 validators in validator set by default. A new constructor function `NewTestChainWithValSet` is provided for test writers who want custom control over the validator set of test chains. * (testing) [\#904](https://github.com/cosmos/ibc-go/pull/904) Add `ParsePacketFromEvents` function to the testing package. Useful when sending/relaying packets via the testing package. * (testing) [\#893](https://github.com/cosmos/ibc-go/pull/893) Support custom private keys for testing. diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go index db4412d144e..c0163e954e1 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go @@ -87,7 +87,6 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro } // commit state changes for proof verification - endpoint.Chain.App.Commit() endpoint.Chain.NextBlock() // update port/channel ids @@ -350,7 +349,6 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenConfirm() { suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel) // commit state changes so proof can be created - suite.chainB.App.Commit() suite.chainB.NextBlock() path.EndpointA.UpdateClient() diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go index c3e1a48ee0c..a0772f1e648 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -100,7 +100,6 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro } // commit state changes for proof verification - endpoint.Chain.App.Commit() endpoint.Chain.NextBlock() // update port/channel ids diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 56baa70e847..3fa45384104 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -91,7 +91,6 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro } // commit state changes for proof verification - endpoint.Chain.App.Commit() endpoint.Chain.NextBlock() // update port/channel ids @@ -247,7 +246,6 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenAck() { suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) // commit state changes so proof can be created - suite.chainA.App.Commit() suite.chainA.NextBlock() path.EndpointB.UpdateClient() diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go index 96c80c45f99..609fb06884d 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go @@ -100,7 +100,6 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro } // commit state changes for proof verification - endpoint.Chain.App.Commit() endpoint.Chain.NextBlock() // update port/channel ids diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 4ca764620bf..cc36b8a4edb 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -58,7 +58,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { suite.Require().True(found) return suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(fillHeight.RevisionHeight), trustedHeight, consState.(*ibctmtypes.ConsensusState).Timestamp.Add(time.Second*5), - suite.chainB.Vals, suite.chainB.Vals, suite.chainB.Signers) + suite.chainB.Vals, suite.chainB.Vals, suite.chainB.Vals, suite.chainB.Signers) } cases := []struct { @@ -444,9 +444,12 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { // Create signer array and ensure it is in same order as bothValSet _, suiteVal := suite.valSet.GetByIndex(0) - bothSigners := ibctesting.CreateSortedSignerArray(altPrivVal, suite.privVal, altVal, suiteVal) + bothSigners := make(map[string]tmtypes.PrivValidator, 2) + bothSigners[suiteVal.Address.String()] = suite.privVal + bothSigners[altVal.Address.String()] = altPrivVal - altSigners := []tmtypes.PrivValidator{altPrivVal} + altSigners := make(map[string]tmtypes.PrivValidator, 1) + altSigners[altVal.Address.String()] = altPrivVal // Create valid Misbehaviour by making a duplicate header that signs over different block time altTime := suite.ctx.BlockTime().Add(time.Minute) @@ -463,8 +466,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "trusting period misbehavior should pass", &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: clientID, }, func() error { @@ -479,8 +482,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "time misbehavior should pass", &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+5), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+5), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), ClientId: clientID, }, func() error { @@ -495,8 +498,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "misbehavior at later height should pass", &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, valSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, valSet, bothSigners), ClientId: clientID, }, func() error { @@ -521,8 +524,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "misbehavior at later height with different trusted heights should pass", &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, valSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: clientID, }, func() error { @@ -547,8 +550,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "misbehavior ValidateBasic fails: misbehaviour height is at same height as trusted height", &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: clientID, }, func() error { @@ -563,8 +566,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "trusted ConsensusState1 not found", &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, altTime, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, altTime, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, valSet, bothSigners), ClientId: clientID, }, func() error { @@ -579,8 +582,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "trusted ConsensusState2 not found", &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, valSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: clientID, }, func() error { @@ -601,8 +604,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "client already is not active - client is frozen", &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: clientID, }, func() error { @@ -620,8 +623,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { { "misbehaviour check failed", &ibctmtypes.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners), + Header1: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), altValSet, altValSet, bothValSet, altSigners), ClientId: clientID, }, func() error { diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index e3dfb4d2e3b..bbcc6dafde9 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -66,6 +66,8 @@ type KeeperTestSuite struct { now time.Time past time.Time + signers map[string]tmtypes.PrivValidator + // TODO: deprecate queryClient types.QueryClient } @@ -95,7 +97,11 @@ func (suite *KeeperTestSuite) SetupTest() { validator := tmtypes.NewValidator(pubKey, 1) suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) suite.valSetHash = suite.valSet.Hash() - suite.header = suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeightMinus1, now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + + suite.signers = make(map[string]tmtypes.PrivValidator, 1) + suite.signers[validator.Address.String()] = suite.privVal + + suite.header = suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeightMinus1, now2, suite.valSet, suite.valSet, suite.valSet, suite.signers) suite.consensusState = ibctmtypes.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot([]byte("hash")), suite.valSetHash) var validators stakingtypes.Validators @@ -329,7 +335,7 @@ func (suite KeeperTestSuite) TestConsensusStateHelpers() { testClientHeightPlus5 := types.NewHeight(0, height+5) header := suite.chainA.CreateTMClientHeader(testClientID, int64(testClientHeightPlus5.RevisionHeight), testClientHeight, suite.header.Header.Time.Add(time.Minute), - suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + suite.valSet, suite.valSet, suite.valSet, suite.signers) // mock update functionality clientState.LatestHeight = header.GetHeight().(types.Height) diff --git a/modules/core/02-client/types/genesis_test.go b/modules/core/02-client/types/genesis_test.go index 6972a8d5983..6fc37070b31 100644 --- a/modules/core/02-client/types/genesis_test.go +++ b/modules/core/02-client/types/genesis_test.go @@ -55,8 +55,11 @@ func (suite *TypesTestSuite) TestValidateGenesis() { val := tmtypes.NewValidator(pubKey, 10) valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{val}) + signers := make(map[string]tmtypes.PrivValidator) + signers[val.Address.String()] = privVal + heightMinus1 := types.NewHeight(0, height-1) - header := suite.chainA.CreateTMClientHeader(chainID, int64(clientHeight.RevisionHeight), heightMinus1, now, valSet, valSet, []tmtypes.PrivValidator{privVal}) + header := suite.chainA.CreateTMClientHeader(chainID, int64(clientHeight.RevisionHeight), heightMinus1, now, valSet, valSet, valSet, signers) testCases := []struct { name string diff --git a/modules/core/02-client/types/msgs_test.go b/modules/core/02-client/types/msgs_test.go index 35dd08aedba..ce5ecd159cb 100644 --- a/modules/core/02-client/types/msgs_test.go +++ b/modules/core/02-client/types/msgs_test.go @@ -490,8 +490,8 @@ func (suite *TypesTestSuite) TestMarshalMsgSubmitMisbehaviour() { "tendermint client", func() { height := types.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height)) heightMinus1 := types.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height)-1) - header1 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) - header2 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) + header1 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) + header2 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) misbehaviour := ibctmtypes.NewMisbehaviour("tendermint", header1, header2) msg, err = types.NewMsgSubmitMisbehaviour("tendermint", misbehaviour, suite.chainA.SenderAccount.GetAddress().String()) @@ -548,8 +548,8 @@ func (suite *TypesTestSuite) TestMsgSubmitMisbehaviour_ValidateBasic() { func() { height := types.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height)) heightMinus1 := types.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height)-1) - header1 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) - header2 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) + header1 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) + header2 := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, int64(height.RevisionHeight), heightMinus1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) misbehaviour := ibctmtypes.NewMisbehaviour("tendermint", header1, header2) msg, err = types.NewMsgSubmitMisbehaviour("tendermint", misbehaviour, suite.chainA.SenderAccount.GetAddress().String()) diff --git a/modules/core/genesis_test.go b/modules/core/genesis_test.go index 00b9a0c3b84..aa921f7c19e 100644 --- a/modules/core/genesis_test.go +++ b/modules/core/genesis_test.go @@ -59,7 +59,7 @@ func TestIBCTestSuite(t *testing.T) { } func (suite *IBCTestSuite) TestValidateGenesis() { - header := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, suite.chainA.CurrentHeader.Height, clienttypes.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height-1)), suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) + header := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, suite.chainA.CurrentHeader.Height, clienttypes.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height-1)), suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) testCases := []struct { name string @@ -225,7 +225,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() { } func (suite *IBCTestSuite) TestInitGenesis() { - header := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, suite.chainA.CurrentHeader.Height, clienttypes.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height-1)), suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) + header := suite.chainA.CreateTMClientHeader(suite.chainA.ChainID, suite.chainA.CurrentHeader.Height, clienttypes.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height-1)), suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers) testCases := []struct { name string diff --git a/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go b/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go index da1efc665da..483e097435f 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go +++ b/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go @@ -11,7 +11,6 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v3/modules/core/exported" "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" ibctestingmock "github.com/cosmos/ibc-go/v3/testing/mock" ) @@ -22,18 +21,14 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { altVal := tmtypes.NewValidator(altPubKey, 4) - // Create bothValSet with both suite validator and altVal - bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) - bothValsHash := bothValSet.Hash() // Create alternative validator set with only altVal altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) - _, suiteVal := suite.valSet.GetByIndex(0) - - // Create signer array and ensure it is in same order as bothValSet - bothSigners := ibctesting.CreateSortedSignerArray(altPrivVal, suite.privVal, altVal, suiteVal) + // Create bothValSet with both suite validator and altVal + bothValSet, bothSigners := getBothSigners(suite, altVal, altPrivVal) + bothValsHash := bothValSet.Hash() - altSigners := []tmtypes.PrivValidator{altPrivVal} + altSigners := getAltSigners(altVal, altPrivVal) heightMinus1 := clienttypes.NewHeight(height.RevisionNumber, height.RevisionHeight-1) heightMinus3 := clienttypes.NewHeight(height.RevisionNumber, height.RevisionHeight-3) @@ -57,8 +52,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -72,8 +67,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+3), height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+3), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -87,8 +82,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+3), height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Hour), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+3), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Hour), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -102,8 +97,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), heightMinus1, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -117,8 +112,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), heightMinus3, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: chainID, }, suite.now, @@ -132,8 +127,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), heightMinus3, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainIDRevision0, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainIDRevision0, int64(height.RevisionHeight+1), heightMinus3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainIDRevision0, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainIDRevision0, int64(height.RevisionHeight+1), heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: chainID, }, suite.now, @@ -147,8 +142,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), heightMinus3, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainIDRevision0, 3, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainIDRevision0, 3, heightMinus3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainIDRevision0, 3, heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainIDRevision0, 3, heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: chainID, }, suite.now, @@ -162,8 +157,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), heightMinus3, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainIDRevision1, 1, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainIDRevision1, 1, heightMinus3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainIDRevision1, 1, heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainIDRevision1, 1, heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: chainID, }, suite.now, @@ -177,8 +172,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, suite.valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: chainID, }, suite.now, @@ -192,8 +187,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -207,8 +202,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+3), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+3), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -222,8 +217,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader("ethermint", int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader("ethermint", int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader("ethermint", int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader("ethermint", int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -237,8 +232,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), heightMinus3, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: chainID, }, suite.now, @@ -252,8 +247,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash), heightMinus3, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -267,8 +262,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -282,8 +277,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -308,8 +303,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -323,8 +318,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), heightMinus1, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now.Add(trustingPeriod), @@ -338,8 +333,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, suite.valSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: chainID, }, suite.now, @@ -353,8 +348,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, altValSet, bothValSet, altSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, altValSet, altValSet, bothValSet, altSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothValSet, bothSigners), ClientId: chainID, }, suite.now, @@ -368,8 +363,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, bothValSet, bothValSet, bothValSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), altValSet, altValSet, bothValSet, altSigners), ClientId: chainID, }, suite.now, @@ -383,8 +378,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash), height, &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, altValSet, bothValSet, altSigners), - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now, altValSet, altValSet, bothValSet, altSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+1), height, suite.now.Add(time.Minute), altValSet, altValSet, bothValSet, altSigners), ClientId: chainID, }, suite.now, diff --git a/modules/light-clients/07-tendermint/types/misbehaviour_test.go b/modules/light-clients/07-tendermint/types/misbehaviour_test.go index bba616bc5e4..0ad5db5a7a5 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour_test.go +++ b/modules/light-clients/07-tendermint/types/misbehaviour_test.go @@ -15,12 +15,11 @@ import ( ) func (suite *TendermintTestSuite) TestMisbehaviour() { - signers := []tmtypes.PrivValidator{suite.privVal} heightMinus1 := clienttypes.NewHeight(0, height.RevisionHeight-1) misbehaviour := &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, signers), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, } @@ -37,18 +36,13 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { altVal := tmtypes.NewValidator(altPubKey, revisionHeight) - // Create bothValSet with both suite validator and altVal - bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) // Create alternative validator set with only altVal altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) - signers := []tmtypes.PrivValidator{suite.privVal} - // Create signer array and ensure it is in same order as bothValSet - _, suiteVal := suite.valSet.GetByIndex(0) - bothSigners := ibctesting.CreateSortedSignerArray(altPrivVal, suite.privVal, altVal, suiteVal) + bothValSet, bothSigners := getBothSigners(suite, altVal, altPrivVal) - altSigners := []tmtypes.PrivValidator{altPrivVal} + altSignerArr := []tmtypes.PrivValidator{altPrivVal} heightMinus1 := clienttypes.NewHeight(0, height.RevisionHeight-1) @@ -62,7 +56,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { "valid fork misbehaviour, two headers at same height have different time", &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, }, func(misbehaviour *types.Misbehaviour) error { return nil }, @@ -71,7 +65,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { { "valid time misbehaviour, both headers at different heights are at same time", &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+5), heightMinus1, suite.now, suite.valSet, suite.valSet, signers), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight+5), heightMinus1, suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), Header2: suite.header, ClientId: clientID, }, @@ -94,7 +88,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { "valid misbehaviour with different trusted headers", &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), clienttypes.NewHeight(0, height.RevisionHeight-3), suite.now.Add(time.Minute), suite.valSet, bothValSet, signers), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), clienttypes.NewHeight(0, height.RevisionHeight-3), suite.now.Add(time.Minute), suite.valSet, suite.valSet, bothValSet, suite.signers), ClientId: clientID, }, func(misbehaviour *types.Misbehaviour) error { return nil }, @@ -103,7 +97,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { { "trusted height is 0 in Header1", &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), clienttypes.ZeroHeight(), suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), clienttypes.ZeroHeight(), suite.now.Add(time.Minute), suite.valSet, suite.valSet, suite.valSet, suite.signers), Header2: suite.header, ClientId: clientID, }, @@ -114,7 +108,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { "trusted height is 0 in Header2", &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), clienttypes.ZeroHeight(), suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), clienttypes.ZeroHeight(), suite.now.Add(time.Minute), suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, }, func(misbehaviour *types.Misbehaviour) error { return nil }, @@ -123,7 +117,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { { "trusted valset is nil in Header1", &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now.Add(time.Minute), suite.valSet, nil, signers), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, nil, suite.signers), Header2: suite.header, ClientId: clientID, }, @@ -134,7 +128,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { "trusted valset is nil in Header2", &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now.Add(time.Minute), suite.valSet, nil, signers), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, nil, suite.signers), ClientId: clientID, }, func(misbehaviour *types.Misbehaviour) error { return nil }, @@ -144,7 +138,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { "invalid client ID ", &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, signers), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: "GAIA", }, func(misbehaviour *types.Misbehaviour) error { return nil }, @@ -154,7 +148,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { "chainIDs do not match", &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader("ethermint", int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, signers), + Header2: suite.chainA.CreateTMClientHeader("ethermint", int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, }, func(misbehaviour *types.Misbehaviour) error { return nil }, @@ -164,7 +158,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { "header2 height is greater", &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader(chainID, 6, clienttypes.NewHeight(0, height.RevisionHeight+1), suite.now, suite.valSet, suite.valSet, signers), + Header2: suite.chainA.CreateTMClientHeader(chainID, 6, clienttypes.NewHeight(0, height.RevisionHeight+1), suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers), ClientId: clientID, }, func(misbehaviour *types.Misbehaviour) error { return nil }, @@ -173,7 +167,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { { "header 1 doesn't have 2/3 majority", &types.Misbehaviour{ - Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, bothValSet, suite.valSet, bothSigners), + Header1: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), Header2: suite.header, ClientId: clientID, }, @@ -185,7 +179,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { return err } - tmCommit, err := tmtypes.MakeCommit(*blockID, int64(misbehaviour.Header2.GetHeight().GetRevisionHeight()), misbehaviour.Header1.Commit.Round, wrongVoteSet, altSigners, suite.now) + tmCommit, err := tmtypes.MakeCommit(*blockID, int64(misbehaviour.Header2.GetHeight().GetRevisionHeight()), misbehaviour.Header1.Commit.Round, wrongVoteSet, altSignerArr, suite.now) misbehaviour.Header1.Commit = tmCommit.ToProto() return err }, @@ -195,7 +189,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { "header 2 doesn't have 2/3 majority", &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, bothValSet, suite.valSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: clientID, }, func(misbehaviour *types.Misbehaviour) error { @@ -206,7 +200,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { return err } - tmCommit, err := tmtypes.MakeCommit(*blockID, int64(misbehaviour.Header2.GetHeight().GetRevisionHeight()), misbehaviour.Header2.Commit.Round, wrongVoteSet, altSigners, suite.now) + tmCommit, err := tmtypes.MakeCommit(*blockID, int64(misbehaviour.Header2.GetHeight().GetRevisionHeight()), misbehaviour.Header2.Commit.Round, wrongVoteSet, altSignerArr, suite.now) misbehaviour.Header2.Commit = tmCommit.ToProto() return err }, @@ -216,7 +210,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() { "validators sign off on wrong commit", &types.Misbehaviour{ Header1: suite.header, - Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, bothValSet, suite.valSet, bothSigners), + Header2: suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, bothValSet, bothValSet, suite.valSet, bothSigners), ClientId: clientID, }, func(misbehaviour *types.Misbehaviour) error { diff --git a/modules/light-clients/07-tendermint/types/tendermint_test.go b/modules/light-clients/07-tendermint/types/tendermint_test.go index 7c1996abfa8..898a48efe72 100644 --- a/modules/light-clients/07-tendermint/types/tendermint_test.go +++ b/modules/light-clients/07-tendermint/types/tendermint_test.go @@ -48,6 +48,7 @@ type TendermintTestSuite struct { cdc codec.Codec privVal tmtypes.PrivValidator valSet *tmtypes.ValidatorSet + signers map[string]tmtypes.PrivValidator valsHash tmbytes.HexBytes header *ibctmtypes.Header now time.Time @@ -84,22 +85,27 @@ func (suite *TendermintTestSuite) SetupTest() { heightMinus1 := clienttypes.NewHeight(0, height.RevisionHeight-1) val := tmtypes.NewValidator(pubKey, 10) + suite.signers = make(map[string]tmtypes.PrivValidator) + suite.signers[val.Address.String()] = suite.privVal suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val}) suite.valsHash = suite.valSet.Hash() - suite.header = suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + suite.header = suite.chainA.CreateTMClientHeader(chainID, int64(height.RevisionHeight), heightMinus1, suite.now, suite.valSet, suite.valSet, suite.valSet, suite.signers) suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, Time: suite.now}) } -func getSuiteSigners(suite *TendermintTestSuite) []tmtypes.PrivValidator { - return []tmtypes.PrivValidator{suite.privVal} +func getAltSigners(altVal *tmtypes.Validator, altPrivVal tmtypes.PrivValidator) map[string]tmtypes.PrivValidator { + return map[string]tmtypes.PrivValidator{altVal.Address.String(): altPrivVal} } -func getBothSigners(suite *TendermintTestSuite, altVal *tmtypes.Validator, altPrivVal tmtypes.PrivValidator) (*tmtypes.ValidatorSet, []tmtypes.PrivValidator) { +func getBothSigners(suite *TendermintTestSuite, altVal *tmtypes.Validator, altPrivVal tmtypes.PrivValidator) (*tmtypes.ValidatorSet, map[string]tmtypes.PrivValidator) { // Create bothValSet with both suite validator and altVal. Would be valid update bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) // Create signer array and ensure it is in same order as bothValSet _, suiteVal := suite.valSet.GetByIndex(0) - bothSigners := ibctesting.CreateSortedSignerArray(altPrivVal, suite.privVal, altVal, suiteVal) + bothSigners := map[string]tmtypes.PrivValidator{ + suiteVal.Address.String(): suite.privVal, + altVal.Address.String(): altPrivVal, + } return bothValSet, bothSigners } diff --git a/modules/light-clients/07-tendermint/types/update_test.go b/modules/light-clients/07-tendermint/types/update_test.go index 77c993dff72..379ccba5e00 100644 --- a/modules/light-clients/07-tendermint/types/update_test.go +++ b/modules/light-clients/07-tendermint/types/update_test.go @@ -22,8 +22,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { newHeader *types.Header currentTime time.Time bothValSet *tmtypes.ValidatorSet - signers []tmtypes.PrivValidator - bothSigners []tmtypes.PrivValidator + bothSigners map[string]tmtypes.PrivValidator ) // Setup different validators and signers for testing different types of updates @@ -42,7 +41,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { altVal := tmtypes.NewValidator(altPubKey, revisionHeight) // Create alternative validator set with only altVal, invalid update (too much change in valSet) altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) - altSigners := []tmtypes.PrivValidator{altPrivVal} + altSigners := getAltSigners(altVal, altPrivVal) testCases := []struct { name string @@ -55,7 +54,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now }, expFrozen: false, @@ -66,7 +65,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, bothValSet, suite.valSet, bothSigners) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, suite.valSet, bothSigners) currentTime = suite.now }, expFrozen: false, @@ -77,7 +76,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), bothValSet.Hash()) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, bothSigners) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, bothValSet, bothSigners) currentTime = suite.now }, expFrozen: false, @@ -89,7 +88,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) consStateHeight = heightMinus3 - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightMinus1.RevisionHeight), heightMinus3, suite.headerTime, bothValSet, suite.valSet, bothSigners) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightMinus1.RevisionHeight), heightMinus3, suite.headerTime, bothValSet, bothValSet, suite.valSet, bothSigners) currentTime = suite.now }, expFrozen: false, @@ -101,7 +100,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { clientState = types.NewClientState(chainIDRevision1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) consStateHeight = heightMinus3 - newHeader = suite.chainA.CreateTMClientHeader(chainIDRevision0, int64(height.RevisionHeight), heightMinus3, suite.headerTime, bothValSet, suite.valSet, bothSigners) + newHeader = suite.chainA.CreateTMClientHeader(chainIDRevision0, int64(height.RevisionHeight), heightMinus3, suite.headerTime, bothValSet, bothValSet, suite.valSet, bothSigners) currentTime = suite.now }, expPass: true, @@ -111,7 +110,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, heightPlus1, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now ctx := suite.chainA.GetContext().WithBlockTime(currentTime) // Store the header's consensus state in client store before UpdateClient call @@ -125,7 +124,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, heightPlus1, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now ctx := suite.chainA.GetContext().WithBlockTime(currentTime) // Change the consensus state of header and store in client store to create a conflict @@ -143,7 +142,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { // create an intermediate consensus state with the same time as the newHeader to create a time violation. // header time is after client time consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now prevConsensusState := types.NewConsensusState(suite.headerTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) ctx := suite.chainA.GetContext().WithBlockTime(currentTime) @@ -161,7 +160,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { // create the next consensus state with the same time as the intermediate newHeader to create a time violation. // header time is after clientTime consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now nextConsensusState := types.NewConsensusState(suite.headerTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) ctx := suite.chainA.GetContext().WithBlockTime(currentTime) @@ -177,7 +176,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader("ethermint", int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader("ethermint", int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now }, expFrozen: false, @@ -188,7 +187,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainIDRevision0, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainIDRevision1, 1, height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainIDRevision1, 1, height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now }, expPass: false, @@ -198,7 +197,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainIDRevision1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainIDRevision1, 3, height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainIDRevision1, 3, height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now }, expFrozen: false, @@ -209,7 +208,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, bothValSet, suite.valSet, bothSigners) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, suite.valSet, bothSigners) currentTime = suite.now }, expFrozen: false, @@ -220,7 +219,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), bothValSet.Hash()) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, bothValSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, bothValSet, suite.signers) currentTime = suite.now }, expFrozen: false, @@ -231,7 +230,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, altValSet, suite.valSet, altSigners) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, altValSet, altValSet, suite.valSet, altSigners) currentTime = suite.now }, expFrozen: false, @@ -242,7 +241,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, bothSigners) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus5.RevisionHeight), height, suite.headerTime, bothValSet, bothValSet, bothValSet, bothSigners) currentTime = suite.now }, expFrozen: false, @@ -253,7 +252,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) // make current time pass trusting period from last timestamp on clientstate currentTime = suite.now.Add(trustingPeriod) }, @@ -265,7 +264,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.now.Add(time.Minute), suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now }, expFrozen: false, @@ -276,7 +275,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.clientTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.clientTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now }, expFrozen: false, @@ -287,7 +286,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { setup: func(suite *TendermintTestSuite) { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightPlus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) // cause new header to fail validatebasic by changing commit height to mismatch header height newHeader.SignedHeader.Commit.Height = revisionHeight - 1 currentTime = suite.now @@ -301,7 +300,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(height.RevisionNumber, heightPlus5.RevisionHeight), commitmenttypes.GetSDKSpecs(), upgradePath, false, false) consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash) // Make new header at height less than latest client state - newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightMinus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, signers) + newHeader = suite.chainA.CreateTMClientHeader(chainID, int64(heightMinus1.RevisionHeight), height, suite.headerTime, suite.valSet, suite.valSet, suite.valSet, suite.signers) currentTime = suite.now }, expFrozen: false, @@ -314,12 +313,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { suite.Run(fmt.Sprintf("Case: %s", tc.name), func() { suite.SetupTest() // reset metadata writes // Create bothValSet with both suite validator and altVal. Would be valid update - bothValSet = tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) - signers = []tmtypes.PrivValidator{suite.privVal} - - // Create signer array and ensure it is in same order as bothValSet - _, suiteVal := suite.valSet.GetByIndex(0) - bothSigners = ibctesting.CreateSortedSignerArray(altPrivVal, suite.privVal, altVal, suiteVal) + bothValSet, bothSigners = getBothSigners(suite, altVal, altPrivVal) consStateHeight = height // must be explicitly changed // setup test diff --git a/testing/app.go b/testing/app.go index 3c6a14ed453..1cde8614b6d 100644 --- a/testing/app.go +++ b/testing/app.go @@ -99,8 +99,6 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs bondDenom := stakingGenesis.Params.BondDenom - totalSupply := sdk.NewCoins() - // add bonded amount to bonded pool module account balances = append(balances, banktypes.Balance{ Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), @@ -112,7 +110,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&stakingGenesis) // update total supply - bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}) + bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(), []banktypes.Metadata{}) genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) stateBytes, err := json.MarshalIndent(genesisState, "", " ") diff --git a/testing/chain.go b/testing/chain.go index 28382a6c463..9e248312bc8 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -1,7 +1,6 @@ package ibctesting import ( - "bytes" "fmt" "testing" "time" @@ -60,8 +59,15 @@ type TestChain struct { TxConfig client.TxConfig Codec codec.BinaryCodec - Vals *tmtypes.ValidatorSet - Signers []tmtypes.PrivValidator + Vals *tmtypes.ValidatorSet + NextVals *tmtypes.ValidatorSet + + // Signers is a map from validator address to the PrivValidator + // The map is converted into an array that is the same order as the validators right before signing commit + // This ensures that signers will always be in correct order even as validator powers change. + // If a test adds a new validator after chain creation, then the signer map must be updated to include + // the new PrivValidator entry. + Signers map[string]tmtypes.PrivValidator // autogenerated sender private key SenderPrivKey cryptotypes.PrivKey @@ -83,9 +89,9 @@ type TestChain struct { // NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this // constructor function. // -// CONTRACT: Validator and signer array must be provided in the order expected by Tendermint. +// CONTRACT: Validator array must be provided in the order expected by Tendermint. // i.e. sorted first by power and then lexicographically by address. -func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) *TestChain { +func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *TestChain { genAccs := []authtypes.GenesisAccount{} genBals := []banktypes.Balance{} senderAccs := []SenderAccount{} @@ -135,6 +141,7 @@ func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, va TxConfig: txConfig, Codec: app.AppCodec(), Vals: valSet, + NextVals: valSet, Signers: signers, SenderPrivKey: senderAccs[0].SenderPrivKey, SenderAccount: senderAccs[0].SenderAccount, @@ -169,13 +176,7 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { // or, if equal, by address lexical order valSet := tmtypes.NewValidatorSet(validators) - // create signers indexed by the valSet validators's order - signers := []tmtypes.PrivValidator{} - for _, val := range valSet.Validators { - signers = append(signers, signersByAddress[val.PubKey.Address().String()]) - } - - return NewTestChainWithValSet(t, coord, chainID, valSet, signers) + return NewTestChainWithValSet(t, coord, chainID, valSet, signersByAddress) } // GetContext returns the current context for the application. @@ -261,13 +262,24 @@ func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clien // NextBlock sets the last header to the current header and increments the current header to be // at the next block height. It does not update the time as that is handled by the Coordinator. -// -// CONTRACT: this function must only be called after app.Commit() occurs +// It will call Endblock and Commit and apply the validator set changes to the next validators +// of the next block being created. This follows the Tendermint protocol of applying valset changes +// returned on block `n` to the validators of block `n+2`. +// It calls BeginBlock with the new block created before returning. func (chain *TestChain) NextBlock() { + res := chain.App.EndBlock(abci.RequestEndBlock{Height: chain.CurrentHeader.Height}) + + chain.App.Commit() + // set the last header to the current header // use nil trusted fields chain.LastHeader = chain.CurrentTMClientHeader() + // val set changes returned from previous block get applied to the next validators + // of this block. See tendermint spec for details. + chain.Vals = chain.NextVals + chain.NextVals = ApplyValSetChanges(chain.T, chain.Vals, res.ValidatorUpdates) + // increment the current header chain.CurrentHeader = tmproto.Header{ ChainID: chain.ChainID, @@ -277,7 +289,7 @@ func (chain *TestChain) NextBlock() { // chains. Time: chain.CurrentHeader.Time, ValidatorsHash: chain.Vals.Hash(), - NextValidatorsHash: chain.Vals.Hash(), + NextValidatorsHash: chain.NextVals.Hash(), } chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) @@ -311,7 +323,7 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) { return nil, err } - // SignAndDeliver calls app.Commit() + // NextBlock calls app.Commit() chain.NextBlock() // increment sequence for successful transaction execution @@ -423,12 +435,12 @@ func (chain *TestChain) ExpireClient(amount time.Duration) { // CurrentTMClientHeader creates a TM header using the current header parameters // on the chain. The trusted fields in the header are set to nil. func (chain *TestChain) CurrentTMClientHeader() *ibctmtypes.Header { - return chain.CreateTMClientHeader(chain.ChainID, chain.CurrentHeader.Height, clienttypes.Height{}, chain.CurrentHeader.Time, chain.Vals, nil, chain.Signers) + return chain.CreateTMClientHeader(chain.ChainID, chain.CurrentHeader.Height, clienttypes.Height{}, chain.CurrentHeader.Time, chain.Vals, chain.NextVals, nil, chain.Signers) } // CreateTMClientHeader creates a TM header to update the TM client. Args are passed in to allow // caller flexibility to use params that differ from the chain. -func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, tmTrustedVals *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) *ibctmtypes.Header { +func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, nextVals, tmTrustedVals *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *ibctmtypes.Header { var ( valSet *tmproto.ValidatorSet trustedVals *tmproto.ValidatorSet @@ -436,6 +448,7 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, require.NotNil(chain.T, tmValSet) vsetHash := tmValSet.Hash() + nextValHash := nextVals.Hash() tmHeader := tmtypes.Header{ Version: tmprotoversion.Consensus{Block: tmversion.BlockProtocol, App: 2}, @@ -446,7 +459,7 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, LastCommitHash: chain.App.LastCommitID().Hash, DataHash: tmhash.Sum([]byte("data_hash")), ValidatorsHash: vsetHash, - NextValidatorsHash: vsetHash, + NextValidatorsHash: nextValHash, ConsensusHash: tmhash.Sum([]byte("consensus_hash")), AppHash: chain.CurrentHeader.AppHash, LastResultsHash: tmhash.Sum([]byte("last_results_hash")), @@ -458,7 +471,15 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set"))) voteSet := tmtypes.NewVoteSet(chainID, blockHeight, 1, tmproto.PrecommitType, tmValSet) - commit, err := tmtypes.MakeCommit(blockID, blockHeight, 1, voteSet, signers, timestamp) + // MakeCommit expects a signer array in the same order as the validator array. + // Thus we iterate over the ordered validator set and construct a signer array + // from the signer map in the same order. + var signerArr []tmtypes.PrivValidator + for _, v := range tmValSet.Validators { + signerArr = append(signerArr, signers[v.Address.String()]) + } + + commit, err := tmtypes.MakeCommit(blockID, blockHeight, 1, voteSet, signerArr, timestamp) require.NoError(chain.T, err) signedHeader := &tmproto.SignedHeader{ @@ -497,26 +518,6 @@ func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) tmtypes.Bl } } -// CreateSortedSignerArray takes two PrivValidators, and the corresponding Validator structs -// (including voting power). It returns a signer array of PrivValidators that matches the -// sorting of ValidatorSet. -// The sorting is first by .VotingPower (descending), with secondary index of .Address (ascending). -func CreateSortedSignerArray(altPrivVal, suitePrivVal tmtypes.PrivValidator, - altVal, suiteVal *tmtypes.Validator, -) []tmtypes.PrivValidator { - switch { - case altVal.VotingPower > suiteVal.VotingPower: - return []tmtypes.PrivValidator{altPrivVal, suitePrivVal} - case altVal.VotingPower < suiteVal.VotingPower: - return []tmtypes.PrivValidator{suitePrivVal, altPrivVal} - default: - if bytes.Compare(altVal.Address, suiteVal.Address) == -1 { - return []tmtypes.PrivValidator{altPrivVal, suitePrivVal} - } - return []tmtypes.PrivValidator{suitePrivVal, altPrivVal} - } -} - // CreatePortCapability binds and claims a capability for the given portID if it does not // already exist. This function will fail testing on any resulting error. // NOTE: only creation of a capability for a transfer or mock port is supported @@ -534,8 +535,6 @@ func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.Scope require.NoError(chain.T, err) } - chain.App.Commit() - chain.NextBlock() } @@ -562,8 +561,6 @@ func (chain *TestChain) CreateChannelCapability(scopedKeeper capabilitykeeper.Sc require.NoError(chain.T, err) } - chain.App.Commit() - chain.NextBlock() } diff --git a/testing/chain_test.go b/testing/chain_test.go index 2b77cb75a7d..64ddc6c751e 100644 --- a/testing/chain_test.go +++ b/testing/chain_test.go @@ -4,44 +4,35 @@ import ( "testing" "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" - "github.com/cosmos/ibc-go/v3/testing/mock" ) -func TestCreateSortedSignerArray(t *testing.T) { - privVal1 := mock.NewPV() - pubKey1, err := privVal1.GetPubKey() - require.NoError(t, err) +func TestChangeValSet(t *testing.T) { + coord := ibctesting.NewCoordinator(t, 2) + chainA := coord.GetChain(ibctesting.GetChainID(1)) + chainB := coord.GetChain(ibctesting.GetChainID(2)) - privVal2 := mock.NewPV() - pubKey2, err := privVal2.GetPubKey() - require.NoError(t, err) + path := ibctesting.NewPath(chainA, chainB) + coord.Setup(path) - validator1 := tmtypes.NewValidator(pubKey1, 1) - validator2 := tmtypes.NewValidator(pubKey2, 2) + amount, ok := sdk.NewIntFromString("10000000000000000000") + require.True(t, ok) + amount2, ok := sdk.NewIntFromString("30000000000000000000") + require.True(t, ok) - expected := []tmtypes.PrivValidator{privVal2, privVal1} + val := chainA.App.GetStakingKeeper().GetValidators(chainA.GetContext(), 4) - actual := ibctesting.CreateSortedSignerArray(privVal1, privVal2, validator1, validator2) - require.Equal(t, expected, actual) + chainA.App.GetStakingKeeper().Delegate(chainA.GetContext(), chainA.SenderAccounts[1].SenderAccount.GetAddress(), + amount, types.Unbonded, val[1], true) + chainA.App.GetStakingKeeper().Delegate(chainA.GetContext(), chainA.SenderAccounts[3].SenderAccount.GetAddress(), + amount2, types.Unbonded, val[3], true) - // swap order - actual = ibctesting.CreateSortedSignerArray(privVal2, privVal1, validator2, validator1) - require.Equal(t, expected, actual) + coord.CommitBlock(chainA) - // smaller address - validator1.Address = []byte{1} - validator2.Address = []byte{2} - validator2.VotingPower = 1 - - expected = []tmtypes.PrivValidator{privVal1, privVal2} - - actual = ibctesting.CreateSortedSignerArray(privVal1, privVal2, validator1, validator2) - require.Equal(t, expected, actual) - - // swap order - actual = ibctesting.CreateSortedSignerArray(privVal2, privVal1, validator2, validator1) - require.Equal(t, expected, actual) + // verify that update clients works even after validator update goes into effect + path.EndpointB.UpdateClient() + path.EndpointB.UpdateClient() } diff --git a/testing/coordinator.go b/testing/coordinator.go index 217c257473a..4c0ebc78463 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -181,7 +181,7 @@ func GetChainID(index int) string { // CONTRACT: the passed in list of indexes must not contain duplicates func (coord *Coordinator) CommitBlock(chains ...*TestChain) { for _, chain := range chains { - chain.App.Commit() + chain.NextBlock() } coord.IncrementTime() @@ -191,7 +191,6 @@ func (coord *Coordinator) CommitBlock(chains ...*TestChain) { func (coord *Coordinator) CommitNBlocks(chain *TestChain, n uint64) { for i := uint64(0); i < n; i++ { chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) - chain.App.Commit() chain.NextBlock() coord.IncrementTime() } diff --git a/testing/simapp/test_helpers.go b/testing/simapp/test_helpers.go index 11dcd85b515..1df1714d8a7 100644 --- a/testing/simapp/test_helpers.go +++ b/testing/simapp/test_helpers.go @@ -234,6 +234,8 @@ func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, balances sdk.C // SignAndDeliver signs and delivers a transaction. No simulation occurs as the // ibc testing package causes checkState and deliverState to diverge in block time. +// +// CONTRACT: BeginBlock must be called before this function. func SignAndDeliver( t *testing.T, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []sdk.Msg, chainID string, accNums, accSeqs []uint64, expSimPass, expPass bool, priv ...cryptotypes.PrivKey, @@ -251,8 +253,7 @@ func SignAndDeliver( ) require.NoError(t, err) - // Simulate a sending a transaction and committing a block - app.BeginBlock(abci.RequestBeginBlock{Header: header}) + // Simulate a sending a transaction gInfo, res, err := app.Deliver(txCfg.TxEncoder(), tx) if expPass { @@ -263,9 +264,6 @@ func SignAndDeliver( require.Nil(t, res) } - app.EndBlock(abci.RequestEndBlock{}) - app.Commit() - return gInfo, res, err } diff --git a/testing/utils.go b/testing/utils.go new file mode 100644 index 00000000000..f9f64bf72bd --- /dev/null +++ b/testing/utils.go @@ -0,0 +1,23 @@ +package ibctesting + +import ( + "testing" + + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" +) + +// ApplyValSetChanges takes in tmtypes.ValidatorSet and []abci.ValidatorUpdate and will return a new tmtypes.ValidatorSet which has the +// provided validator updates applied to the provided validator set. +func ApplyValSetChanges(t *testing.T, valSet *tmtypes.ValidatorSet, valUpdates []abci.ValidatorUpdate) *tmtypes.ValidatorSet { + updates, err := tmtypes.PB2TM.ValidatorUpdates(valUpdates) + require.NoError(t, err) + + // must copy since validator set will mutate with UpdateWithChangeSet + newVals := valSet.Copy() + err = newVals.UpdateWithChangeSet(updates) + require.NoError(t, err) + + return newVals +} From c0675ee32c34c2c0c2873bb30e19e861fae699f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Wed, 16 Mar 2022 15:07:52 +0100 Subject: [PATCH 041/275] imp: create codeql-analysis action (#1128) ## Description Noticed that [CodeQL](https://codeql.github.com/) wasn't enabled on the IBC-go repo --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- .github/workflows/codeql-analysis.yml | 79 +++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000000..11d7c0e90bb --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,79 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '37 21 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + - uses: actions/checkout@v3 + - uses: technote-space/get-diff-action@v6.0.1 + with: + PATTERNS: | + **/**.go + go.mod + go.sum + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + if: env.GIT_DIFF + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 + if: env.GIT_DIFF From f83aa8201eaa7b9daa2b34e4e44a219066e6e958 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 16 Mar 2022 17:25:04 +0100 Subject: [PATCH 042/275] update changelog (#1131) * update changelog * fix typo --- CHANGELOG.md | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35c7eb43f20..6a357b21a57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,20 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies +### API Breaking + +### State Machine Breaking + +### Improvements + +### Features + +### Bug Fixes + +## [v3.0.0](https://github.com/cosmos/ibc-go/releases/tag/v3.0.0) - 2022-03-15 + +### Dependencies + * [\#404](https://github.com/cosmos/ibc-go/pull/404) Bump Go version to 1.17 * [\#851](https://github.com/cosmos/ibc-go/pull/851) Bump SDK version to v0.45.1 * [\#948](https://github.com/cosmos/ibc-go/pull/948) Bump ics23/go to v0.7 @@ -95,7 +109,40 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (testing) [\#884](https://github.com/cosmos/ibc-go/pull/884) Add and use in simapp a custom ante handler that rejects redundant transactions * (transfer) [\#978](https://github.com/cosmos/ibc-go/pull/978) Support base denoms with slashes in denom validation * (client) [\#941](https://github.com/cosmos/ibc-go/pull/941) Classify client states without consensus states as expired -* (modules/core/04-channel) [\#994](https://github.com/cosmos/ibc-go/pull/944) Call `packet.GetSequence()` rather than passing func in `AcknowledgePacket` log output +* (channel) [\#995](https://github.com/cosmos/ibc-go/pull/995) Call `packet.GetSequence()` rather than passing func in `AcknowledgePacket` log output + +## [v2.2.0](https://github.com/cosmos/ibc-go/releases/tag/v2.2.0) - 2022-03-15 + +### Dependencies + +* [\#851](https://github.com/cosmos/ibc-go/pull/851) Bump SDK version to v0.45.1 + +## [v2.1.0](https://github.com/cosmos/ibc-go/releases/tag/v2.1.0) - 2022-03-15 + +### Dependencies + +* [\#1084](https://github.com/cosmos/ibc-go/pull/1084) Bump SDK version to v0.44.6 +* [\#948](https://github.com/cosmos/ibc-go/pull/948) Bump ics23/go to v0.7 + +### State Machine Breaking + +* (transfer) [\#818](https://github.com/cosmos/ibc-go/pull/818) Error acknowledgements returned from Transfer `OnRecvPacket` now include a deterministic ABCI code and error message. + +### Features + +* [\#679](https://github.com/cosmos/ibc-go/pull/679) New CLI command `query ibc-transfer denom-hash ` to get the denom hash for a denom trace; this might be useful for debug + +### Bug Fixes + +* (client) [\#941](https://github.com/cosmos/ibc-go/pull/941) Classify client states without consensus states as expired +* (transfer) [\#978](https://github.com/cosmos/ibc-go/pull/978) Support base denoms with slashes in denom validation +* (channel) [\#995](https://github.com/cosmos/ibc-go/pull/995) Call `packet.GetSequence()` rather than passing func in `AcknowledgePacket` log output + +## [v2.0.3](https://github.com/cosmos/ibc-go/releases/tag/v2.0.2) - 2022-02-03 + +### Improvements + +* (channel) [\#692](https://github.com/cosmos/ibc-go/pull/692) Minimize channel logging by only emitting the packet sequence, source port/channel, destination port/channel upon packet receives, acknowledgements and timeouts. ## [v2.0.2](https://github.com/cosmos/ibc-go/releases/tag/v2.0.2) - 2021-12-15 @@ -138,6 +185,39 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#384](https://github.com/cosmos/ibc-go/pull/384) Added `NegotiateAppVersion` method to `IBCModule` interface supported by a gRPC query service in `05-port`. This provides routing of requests to the desired application module callback, which in turn performs application version negotiation. +## [v1.4.0](https://github.com/cosmos/ibc-go/releases/tag/v1.4.0) - 2022-03-15 + +### Dependencies + +* [\#851](https://github.com/cosmos/ibc-go/pull/851) Bump SDK version to v0.45.1 + +## [v1.3.0](https://github.com/cosmos/ibc-go/releases/tag/v1.3.0) - 2022-03-15 + +### Dependencies + +* [\#1073](https://github.com/cosmos/ibc-go/pull/1073) Bump SDK version to v0.44.6 +* [\#948](https://github.com/cosmos/ibc-go/pull/948) Bump ics23/go to v0.7 + +### State Machine Breaking + +* (transfer) [\#818](https://github.com/cosmos/ibc-go/pull/818) Error acknowledgements returned from Transfer `OnRecvPacket` now include a deterministic ABCI code and error message. + +### Features + +* [\#679](https://github.com/cosmos/ibc-go/pull/679) New CLI command `query ibc-transfer denom-hash ` to get the denom hash for a denom trace; this might be useful for debug + +### Bug Fixes + +* (client) [\#941](https://github.com/cosmos/ibc-go/pull/941) Classify client states without consensus states as expired +* (transfer) [\#978](https://github.com/cosmos/ibc-go/pull/978) Support base denoms with slashes in denom validation +* (channel) [\#995](https://github.com/cosmos/ibc-go/pull/995) Call `packet.GetSequence()` rather than passing func in `AcknowledgePacket` log output + +## [v1.2.6](https://github.com/cosmos/ibc-go/releases/tag/v1.2.6) - 2022-02-03 + +### Improvements + +* (channel) [\#692](https://github.com/cosmos/ibc-go/pull/692) Minimize channel logging by only emitting the packet sequence, source port/channel, destination port/channel upon packet receives, acknowledgements and timeouts. + ## [v1.2.5](https://github.com/cosmos/ibc-go/releases/tag/v1.2.5) - 2021-12-15 ### Dependencies @@ -195,6 +275,12 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#386](https://github.com/cosmos/ibc-go/pull/386) Bump [tendermint](https://github.com/tendermint/tendermint) from v0.34.12 to v0.34.13. +## [v1.1.6](https://github.com/cosmos/ibc-go/releases/tag/v1.1.6) - 2022-01-25 + +### Improvements + +* (channel) [\#692](https://github.com/cosmos/ibc-go/pull/692) Minimize channel logging by only emitting the packet sequence, source port/channel, destination port/channel upon packet receives, acknowledgements and timeouts. + ## [v1.1.5](https://github.com/cosmos/ibc-go/releases/tag/v1.1.5) - 2021-12-15 ### Dependencies From fb7a23032727752bd65d02365cd83ff33a36d2ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Mar 2022 08:59:45 +0100 Subject: [PATCH 043/275] build(deps): bump github.com/stretchr/testify from 1.7.0 to 1.7.1 (#1134) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.0 to 1.7.1. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.7.0...v1.7.1) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Damian Nolan --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 02190cf20ac..2bc717ea5f3 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/spf13/cast v1.4.1 github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.10.1 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.7.1 github.com/tendermint/tendermint v0.34.14 github.com/tendermint/tm-db v0.6.4 google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa diff --git a/go.sum b/go.sum index 2e25c13e01f..cb1b3b22474 100644 --- a/go.sum +++ b/go.sum @@ -861,8 +861,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= From dbd2df26e54f17f94a498d3fe048d68df04735b6 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 17 Mar 2022 10:04:50 +0100 Subject: [PATCH 044/275] call packet.GetSequence() rather than passing the func as argument (#1130) * call packet.GetSequence() rather than passing the func as argument * add changelog entry --- CHANGELOG.md | 2 ++ modules/core/04-channel/keeper/packet.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a357b21a57..4b655f7c6d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +* (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output + ## [v3.0.0](https://github.com/cosmos/ibc-go/releases/tag/v3.0.0) - 2022-03-15 ### Dependencies diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index b54926b85e9..51b02f9bece 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -360,7 +360,7 @@ func (k Keeper) WriteAcknowledgement( // log that a packet acknowledgement has been written k.Logger(ctx).Info( "acknowledgement written", - "sequence", packet.GetSequence, + "sequence", packet.GetSequence(), "src_port", packet.GetSourcePort(), "src_channel", packet.GetSourceChannel(), "dst_port", packet.GetDestPort(), From 5cf580cbd9e87a6385928b7440b26f7e92b37c43 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 21 Mar 2022 13:24:55 +0100 Subject: [PATCH 045/275] fix: prefix ResponseResultType enum for proto linting (#1143) --- docs/ibc/proto-docs.md | 6 +- modules/core/04-channel/types/tx.pb.go | 174 ++++++++++++------------- proto/ibc/core/channel/v1/tx.proto | 6 +- 3 files changed, 93 insertions(+), 93 deletions(-) diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 80b2df196d3..abcc6597743 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -2048,9 +2048,9 @@ ResponseResultType defines the possible outcomes of the execution of a message | Name | Number | Description | | ---- | ------ | ----------- | -| RESPONSE_RESULT_UNSPECIFIED | 0 | Default zero value enumeration | -| RESPONSE_RESULT_NOOP | 1 | The message did not call the IBC application callbacks (because, for example, the packet had already been relayed) | -| RESPONSE_RESULT_SUCCESS | 2 | The message was executed successfully | +| RESPONSE_RESULT_TYPE_UNSPECIFIED | 0 | Default zero value enumeration | +| RESPONSE_RESULT_TYPE_NOOP | 1 | The message did not call the IBC application callbacks (because, for example, the packet had already been relayed) | +| RESPONSE_RESULT_TYPE_SUCCESS | 2 | The message was executed successfully | diff --git a/modules/core/04-channel/types/tx.pb.go b/modules/core/04-channel/types/tx.pb.go index e497cf802b1..8f9ebe6ec63 100644 --- a/modules/core/04-channel/types/tx.pb.go +++ b/modules/core/04-channel/types/tx.pb.go @@ -42,15 +42,15 @@ const ( ) var ResponseResultType_name = map[int32]string{ - 0: "RESPONSE_RESULT_UNSPECIFIED", - 1: "RESPONSE_RESULT_NOOP", - 2: "RESPONSE_RESULT_SUCCESS", + 0: "RESPONSE_RESULT_TYPE_UNSPECIFIED", + 1: "RESPONSE_RESULT_TYPE_NOOP", + 2: "RESPONSE_RESULT_TYPE_SUCCESS", } var ResponseResultType_value = map[string]int32{ - "RESPONSE_RESULT_UNSPECIFIED": 0, - "RESPONSE_RESULT_NOOP": 1, - "RESPONSE_RESULT_SUCCESS": 2, + "RESPONSE_RESULT_TYPE_UNSPECIFIED": 0, + "RESPONSE_RESULT_TYPE_NOOP": 1, + "RESPONSE_RESULT_TYPE_SUCCESS": 2, } func (x ResponseResultType) String() string { @@ -902,87 +902,87 @@ func init() { func init() { proto.RegisterFile("ibc/core/channel/v1/tx.proto", fileDescriptor_bc4637e0ac3fc7b7) } var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ - // 1267 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4b, 0x6f, 0xdb, 0x46, - 0x10, 0xd6, 0xcb, 0xb2, 0x3d, 0x72, 0x6d, 0x99, 0xf2, 0x43, 0xa1, 0x62, 0x51, 0xe5, 0x21, 0x11, - 0x5c, 0x44, 0xf2, 0x23, 0x40, 0x11, 0xa3, 0x40, 0x61, 0xa9, 0x0a, 0x6a, 0xb4, 0x7e, 0x80, 0xb2, - 0x7b, 0x70, 0x8b, 0x0a, 0x12, 0xb5, 0x91, 0x09, 0x49, 0x5c, 0x95, 0xa4, 0x94, 0xe8, 0x1f, 0x04, - 0x3e, 0xe5, 0x6c, 0xc0, 0x40, 0x8a, 0x1e, 0x7b, 0x48, 0x7f, 0x46, 0x8e, 0x39, 0xb5, 0x45, 0x0f, - 0x42, 0x61, 0x5f, 0x7a, 0xd6, 0x2f, 0x28, 0xb8, 0x5c, 0x52, 0x94, 0x44, 0xc2, 0x74, 0x62, 0x3b, - 0xb9, 0xed, 0xce, 0x7c, 0x3b, 0x3b, 0xfb, 0x7d, 0xc3, 0x7d, 0x10, 0xee, 0x4b, 0x15, 0x31, 0x2b, - 0x62, 0x05, 0x65, 0xc5, 0x93, 0xb2, 0x2c, 0xa3, 0x46, 0xb6, 0xb3, 0x9e, 0xd5, 0x5e, 0x64, 0x5a, - 0x0a, 0xd6, 0x30, 0x13, 0x93, 0x2a, 0x62, 0x46, 0xf7, 0x66, 0xa8, 0x37, 0xd3, 0x59, 0x67, 0x17, - 0x6a, 0xb8, 0x86, 0x89, 0x3f, 0xab, 0xb7, 0x0c, 0x28, 0xcb, 0x0d, 0x02, 0x35, 0x24, 0x24, 0x6b, - 0x7a, 0x1c, 0xa3, 0x45, 0x01, 0x9f, 0x3b, 0xcd, 0x64, 0x86, 0x25, 0x10, 0xfe, 0x57, 0x3f, 0x30, - 0xbb, 0x6a, 0x2d, 0x6f, 0x18, 0xf7, 0x5b, 0x48, 0xde, 0x91, 0x25, 0x8d, 0xf9, 0x02, 0x26, 0x5b, - 0x58, 0xd1, 0x4a, 0x52, 0x35, 0xee, 0x4f, 0xf9, 0xd3, 0xd3, 0x39, 0xa6, 0xdf, 0xe3, 0x66, 0xbb, - 0xe5, 0x66, 0x63, 0x8b, 0xa7, 0x0e, 0x5e, 0x08, 0xeb, 0xad, 0x9d, 0x2a, 0xf3, 0x15, 0x4c, 0xd2, - 0xa0, 0xf1, 0x40, 0xca, 0x9f, 0x8e, 0x6c, 0xdc, 0xcf, 0x38, 0x2c, 0x22, 0x43, 0xe7, 0xc8, 0x85, - 0xde, 0xf6, 0x38, 0x9f, 0x60, 0x0e, 0x61, 0x96, 0x20, 0xac, 0x4a, 0x35, 0x19, 0x29, 0xf1, 0xa0, - 0x3e, 0x93, 0x40, 0x7b, 0x5b, 0x53, 0x2f, 0x5f, 0x73, 0xbe, 0xff, 0x5e, 0x73, 0x3e, 0x5e, 0x00, - 0x76, 0x3c, 0x45, 0x01, 0xa9, 0x2d, 0x2c, 0xab, 0x88, 0x79, 0x0c, 0x40, 0x43, 0x0d, 0xb2, 0x5d, - 0xec, 0xf7, 0xb8, 0x79, 0x23, 0xdb, 0x81, 0x8f, 0x17, 0xa6, 0x69, 0x67, 0xa7, 0xca, 0xff, 0x19, - 0x84, 0xf9, 0xe1, 0xa0, 0x87, 0x4a, 0xf7, 0x7a, 0xcb, 0xde, 0x83, 0x58, 0x4b, 0x41, 0x1d, 0x09, - 0xb7, 0xd5, 0x92, 0x2d, 0x83, 0x00, 0x19, 0x98, 0xec, 0xf7, 0x38, 0x96, 0x0e, 0x1c, 0x07, 0xf1, - 0xc2, 0xbc, 0x69, 0xcd, 0x9b, 0x29, 0xd9, 0x69, 0x0c, 0x5e, 0x9f, 0x46, 0x01, 0x16, 0x44, 0xdc, - 0x96, 0x35, 0xa4, 0xb4, 0xca, 0x8a, 0xd6, 0x2d, 0x75, 0x90, 0xa2, 0x4a, 0x58, 0x8e, 0x87, 0x48, - 0x3a, 0x5c, 0xbf, 0xc7, 0x25, 0x28, 0x21, 0x0e, 0x28, 0x5e, 0x88, 0xd9, 0xcd, 0x3f, 0x18, 0x56, - 0x9d, 0xda, 0x96, 0x82, 0xf1, 0xb3, 0x92, 0x24, 0x4b, 0x5a, 0x7c, 0x22, 0xe5, 0x4f, 0xcf, 0xd8, - 0xa9, 0x1d, 0xf8, 0x78, 0x61, 0x9a, 0x74, 0x48, 0xed, 0x1c, 0xc3, 0x8c, 0xe1, 0x39, 0x41, 0x52, - 0xed, 0x44, 0x8b, 0x87, 0xc9, 0x62, 0x58, 0xdb, 0x62, 0x8c, 0x1a, 0xed, 0xac, 0x67, 0xbe, 0x25, - 0x88, 0x5c, 0x42, 0x5f, 0x4a, 0xbf, 0xc7, 0xc5, 0xec, 0x71, 0x8d, 0xd1, 0xbc, 0x10, 0x21, 0x5d, - 0x03, 0x69, 0x2b, 0x96, 0x49, 0x97, 0x62, 0x49, 0xc0, 0xbd, 0x31, 0x5d, 0xcd, 0x5a, 0xe1, 0xff, - 0x1a, 0x53, 0x7d, 0x5b, 0xac, 0x5f, 0x4f, 0xf5, 0xe1, 0x72, 0x0b, 0x78, 0x2b, 0x37, 0xe6, 0x18, - 0x96, 0x87, 0x78, 0xb7, 0x85, 0x20, 0x55, 0x9f, 0xe3, 0xfb, 0x3d, 0x2e, 0xe9, 0x20, 0x90, 0x3d, - 0xde, 0xa2, 0xdd, 0x33, 0xa8, 0x9b, 0xdb, 0x50, 0x7e, 0x1d, 0x0c, 0x41, 0x4b, 0x9a, 0xd2, 0xa5, - 0xc2, 0x2f, 0xf4, 0x7b, 0x5c, 0xd4, 0x2e, 0x90, 0xa6, 0x74, 0x79, 0x61, 0x8a, 0xb4, 0xf5, 0x6f, - 0xe7, 0x13, 0x93, 0x7d, 0x5b, 0xac, 0x5b, 0xb2, 0xff, 0x1e, 0x80, 0xc5, 0x61, 0x6f, 0x1e, 0xcb, - 0xcf, 0x24, 0xa5, 0x79, 0x17, 0xd2, 0x5b, 0x54, 0x96, 0xc5, 0x3a, 0x11, 0xdb, 0x81, 0xca, 0xb2, - 0x58, 0x37, 0xa9, 0xd4, 0x0b, 0x72, 0x94, 0xca, 0xd0, 0xad, 0x50, 0x39, 0xe1, 0x42, 0x25, 0x07, - 0x2b, 0x8e, 0x64, 0x59, 0x74, 0x9e, 0xf9, 0x21, 0x36, 0x40, 0xe4, 0x1b, 0x58, 0x45, 0xd7, 0x3f, - 0x34, 0xde, 0x8f, 0xcc, 0xab, 0x0f, 0x8b, 0x15, 0x48, 0x38, 0xe4, 0x66, 0xe5, 0xfe, 0x26, 0x00, - 0x4b, 0x23, 0xfe, 0x3b, 0xac, 0x85, 0xe1, 0x0d, 0x35, 0xf8, 0x9e, 0x1b, 0xea, 0xdd, 0x96, 0x43, - 0x0a, 0x92, 0xce, 0x84, 0x59, 0x9c, 0xbe, 0x0a, 0xc0, 0x67, 0xbb, 0x6a, 0x4d, 0x40, 0x62, 0xe7, - 0xa0, 0x2c, 0xd6, 0x91, 0xc6, 0x3c, 0x81, 0x70, 0x8b, 0xb4, 0x08, 0x93, 0x91, 0x8d, 0x84, 0xe3, - 0x49, 0x66, 0x80, 0xe9, 0x41, 0x46, 0x07, 0x30, 0x4f, 0x21, 0x6a, 0xa4, 0x2b, 0xe2, 0x66, 0x53, - 0xd2, 0x9a, 0x48, 0xd6, 0x08, 0xbd, 0x33, 0xb9, 0x44, 0xbf, 0xc7, 0x2d, 0xdb, 0x17, 0x34, 0x40, - 0xf0, 0xc2, 0x1c, 0x31, 0xe5, 0x2d, 0xcb, 0x18, 0x69, 0xc1, 0x5b, 0x21, 0x2d, 0xe4, 0x42, 0xda, - 0xcf, 0x64, 0xc3, 0x19, 0x30, 0x62, 0xdd, 0x56, 0xbe, 0x86, 0xb0, 0x82, 0xd4, 0x76, 0xc3, 0x60, - 0x66, 0x76, 0xe3, 0xa1, 0x23, 0x33, 0x26, 0x5c, 0x20, 0xd0, 0xc3, 0x6e, 0x0b, 0x09, 0x74, 0xd8, - 0x56, 0x48, 0x9f, 0x83, 0xff, 0x27, 0x00, 0xb0, 0xab, 0xd6, 0x0e, 0xa5, 0x26, 0xc2, 0xed, 0x9b, - 0xe1, 0xbb, 0x2d, 0x2b, 0x48, 0x44, 0x52, 0x07, 0x55, 0xdd, 0xf8, 0x1e, 0x20, 0x4c, 0xbe, 0x8f, - 0x2c, 0xcb, 0xad, 0xf2, 0xfd, 0x1d, 0x30, 0x32, 0x7a, 0xa1, 0x95, 0x54, 0xf4, 0x4b, 0x1b, 0xc9, - 0x22, 0x2a, 0x29, 0x48, 0xec, 0x10, 0xee, 0x43, 0xb9, 0x95, 0x7e, 0x8f, 0xbb, 0x67, 0x44, 0x18, - 0xc7, 0xf0, 0x42, 0x54, 0x37, 0x16, 0xa9, 0x4d, 0xd7, 0xc3, 0x43, 0xc5, 0xff, 0x48, 0xae, 0xc4, - 0x94, 0xdb, 0x9b, 0x56, 0xee, 0xcc, 0xb8, 0x82, 0xd0, 0xe8, 0xfb, 0x32, 0xf9, 0xa2, 0x3e, 0x05, - 0x01, 0xbf, 0x84, 0x08, 0xfd, 0xac, 0xf4, 0x8c, 0xe8, 0xe6, 0xb4, 0xd4, 0xef, 0x71, 0xcc, 0xd0, - 0x37, 0xa7, 0x3b, 0x79, 0xc1, 0xd8, 0xc6, 0x8c, 0xdc, 0x6f, 0x73, 0x7b, 0x72, 0x56, 0x7e, 0xe2, - 0x43, 0x95, 0x0f, 0xbb, 0x28, 0x5f, 0x21, 0xb7, 0x88, 0x61, 0x6d, 0x6e, 0xba, 0x00, 0xfe, 0x08, - 0x90, 0xf2, 0xda, 0x16, 0xeb, 0x32, 0x7e, 0xde, 0x40, 0xd5, 0x1a, 0x22, 0xfb, 0xd5, 0x07, 0x54, - 0x40, 0x1a, 0xe6, 0xca, 0xc3, 0xd1, 0x8c, 0x02, 0x10, 0x46, 0xcd, 0x03, 0x8d, 0xf5, 0x81, 0x55, - 0x37, 0x8d, 0x89, 0xd3, 0xd4, 0x78, 0x5b, 0xef, 0x7c, 0xe4, 0x23, 0x48, 0x24, 0x0f, 0xc0, 0x11, - 0xc6, 0x6e, 0x58, 0x97, 0xd5, 0x33, 0x3f, 0x30, 0xe3, 0x20, 0x66, 0x0d, 0x12, 0x42, 0xa1, 0x78, - 0xb0, 0xbf, 0x57, 0x2c, 0x94, 0x84, 0x42, 0xf1, 0xe8, 0xfb, 0xc3, 0xd2, 0xd1, 0x5e, 0xf1, 0xa0, - 0x90, 0xdf, 0x79, 0xba, 0x53, 0xf8, 0x26, 0xea, 0x63, 0xe7, 0x4e, 0xcf, 0x53, 0x11, 0x9b, 0x89, - 0xe1, 0x61, 0x61, 0x74, 0xc4, 0xde, 0xfe, 0xfe, 0x41, 0xd4, 0xcf, 0x4e, 0x9d, 0x9e, 0xa7, 0x42, - 0x7a, 0x9b, 0x49, 0xc3, 0xf2, 0x28, 0xa6, 0x78, 0x94, 0xcf, 0x17, 0x8a, 0xc5, 0x68, 0x80, 0x8d, - 0x9c, 0x9e, 0xa7, 0x26, 0x69, 0x97, 0x0d, 0xbd, 0xfc, 0x2d, 0xe9, 0xdb, 0x78, 0x33, 0x05, 0xc1, - 0x5d, 0xb5, 0xc6, 0xd4, 0x61, 0x6e, 0xf4, 0xa9, 0xee, 0xbc, 0xdc, 0xf1, 0x07, 0x33, 0x9b, 0xf5, - 0x08, 0xb4, 0x88, 0x3d, 0x81, 0xd9, 0x91, 0xf7, 0xf1, 0x03, 0x0f, 0x21, 0x0e, 0x95, 0x2e, 0x9b, - 0xf1, 0x86, 0x73, 0x99, 0x49, 0xbf, 0x02, 0x7b, 0x99, 0x69, 0x5b, 0xac, 0x7b, 0x9a, 0xc9, 0xf6, - 0x14, 0x60, 0x34, 0x60, 0x1c, 0x9e, 0x01, 0xab, 0x1e, 0xa2, 0x50, 0x2c, 0xbb, 0xe1, 0x1d, 0x6b, - 0xcd, 0x2a, 0x43, 0x74, 0xec, 0xb6, 0x9c, 0xbe, 0x22, 0x8e, 0x85, 0x64, 0xd7, 0xbc, 0x22, 0xad, - 0xf9, 0x9e, 0x43, 0xcc, 0xf1, 0x86, 0xeb, 0x25, 0x90, 0xb9, 0xce, 0xcd, 0x6b, 0x80, 0xad, 0x89, - 0x7f, 0x02, 0xb0, 0x5d, 0x03, 0x79, 0xb7, 0x10, 0x03, 0x0c, 0xbb, 0x7a, 0x35, 0xc6, 0x8a, 0x5e, - 0x84, 0x49, 0xf3, 0xc6, 0xc3, 0xb9, 0x0d, 0xa3, 0x00, 0xf6, 0xe1, 0x15, 0x00, 0x7b, 0xed, 0x8d, - 0x1c, 0xc6, 0x0f, 0xae, 0x18, 0x4a, 0x71, 0xee, 0xb5, 0xe7, 0x72, 0x80, 0xd4, 0x61, 0x6e, 0x74, - 0xd7, 0x77, 0xcd, 0x72, 0x04, 0xe8, 0xfe, 0xf1, 0xba, 0xec, 0x8a, 0xb9, 0xe2, 0xdb, 0x8b, 0xa4, - 0xff, 0xdd, 0x45, 0xd2, 0xff, 0xef, 0x45, 0xd2, 0xff, 0xea, 0x32, 0xe9, 0x7b, 0x77, 0x99, 0xf4, - 0xfd, 0x7d, 0x99, 0xf4, 0x1d, 0x3f, 0xa9, 0x49, 0xda, 0x49, 0xbb, 0x92, 0x11, 0x71, 0x33, 0x2b, - 0x62, 0xb5, 0x89, 0xd5, 0xac, 0x54, 0x11, 0x1f, 0xd5, 0x70, 0xb6, 0xb3, 0x99, 0x6d, 0xe2, 0x6a, - 0xbb, 0x81, 0x54, 0xe3, 0xaf, 0xe1, 0xda, 0xe3, 0x47, 0xe6, 0x8f, 0x43, 0xad, 0xdb, 0x42, 0x6a, - 0x25, 0x4c, 0x7e, 0x1a, 0x6e, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xd5, 0x99, 0xe1, 0x0c, 0xc3, - 0x14, 0x00, 0x00, + // 1275 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcd, 0x6e, 0xdb, 0x46, + 0x10, 0xd6, 0x5f, 0x64, 0x67, 0xe4, 0xda, 0x32, 0x65, 0x3b, 0x32, 0x65, 0x8b, 0x2a, 0x0f, 0xb1, + 0xe1, 0xc2, 0x52, 0x6c, 0xa7, 0x28, 0x62, 0x14, 0x28, 0x2c, 0x55, 0x41, 0x8d, 0xd6, 0x3f, 0xa0, + 0xe4, 0x02, 0x75, 0x8b, 0x0a, 0x12, 0xb5, 0x91, 0x09, 0x49, 0x5c, 0x95, 0xa4, 0x94, 0xe8, 0x0d, + 0x02, 0x9f, 0x72, 0x0e, 0x60, 0x20, 0x45, 0x4f, 0x45, 0x0f, 0xe9, 0x63, 0xe4, 0x98, 0x53, 0x5b, + 0xf4, 0x20, 0x14, 0xf6, 0xa5, 0x67, 0x3d, 0x41, 0xc1, 0xe5, 0x92, 0xa2, 0x24, 0x12, 0xa6, 0x13, + 0xdb, 0xcd, 0x6d, 0x77, 0xe6, 0xdb, 0xd9, 0xd9, 0xef, 0x1b, 0xee, 0x0f, 0x61, 0x49, 0xaa, 0x88, + 0x19, 0x11, 0x2b, 0x28, 0x23, 0x9e, 0x94, 0x65, 0x19, 0x35, 0x32, 0x9d, 0x8d, 0x8c, 0xf6, 0x2c, + 0xdd, 0x52, 0xb0, 0x86, 0x99, 0x98, 0x54, 0x11, 0xd3, 0xba, 0x37, 0x4d, 0xbd, 0xe9, 0xce, 0x06, + 0x3b, 0x57, 0xc3, 0x35, 0x4c, 0xfc, 0x19, 0xbd, 0x65, 0x40, 0x59, 0x6e, 0x10, 0xa8, 0x21, 0x21, + 0x59, 0xd3, 0xe3, 0x18, 0x2d, 0x0a, 0xf8, 0xd8, 0x69, 0x26, 0x33, 0x2c, 0x81, 0xf0, 0x3f, 0xfb, + 0x81, 0xd9, 0x53, 0x6b, 0x39, 0xc3, 0x78, 0xd0, 0x42, 0xf2, 0xae, 0x2c, 0x69, 0xcc, 0x27, 0x30, + 0xd1, 0xc2, 0x8a, 0x56, 0x92, 0xaa, 0x71, 0x7f, 0xca, 0xbf, 0x7a, 0x37, 0xcb, 0xf4, 0x7b, 0xdc, + 0x74, 0xb7, 0xdc, 0x6c, 0x6c, 0xf3, 0xd4, 0xc1, 0x0b, 0x61, 0xbd, 0xb5, 0x5b, 0x65, 0x3e, 0x87, + 0x09, 0x1a, 0x34, 0x1e, 0x48, 0xf9, 0x57, 0x23, 0x9b, 0x4b, 0x69, 0x87, 0x45, 0xa4, 0xe9, 0x1c, + 0xd9, 0xd0, 0x9b, 0x1e, 0xe7, 0x13, 0xcc, 0x21, 0xcc, 0x02, 0x84, 0x55, 0xa9, 0x26, 0x23, 0x25, + 0x1e, 0xd4, 0x67, 0x12, 0x68, 0x6f, 0x7b, 0xf2, 0xf9, 0x2b, 0xce, 0xf7, 0xef, 0x2b, 0xce, 0xc7, + 0x0b, 0xc0, 0x8e, 0xa7, 0x28, 0x20, 0xb5, 0x85, 0x65, 0x15, 0x31, 0x0f, 0x01, 0x68, 0xa8, 0x41, + 0xb6, 0xf3, 0xfd, 0x1e, 0x37, 0x6b, 0x64, 0x3b, 0xf0, 0xf1, 0xc2, 0x5d, 0xda, 0xd9, 0xad, 0xf2, + 0x7f, 0x04, 0x61, 0x76, 0x38, 0x68, 0x51, 0xe9, 0x5e, 0x6d, 0xd9, 0xfb, 0x10, 0x6b, 0x29, 0xa8, + 0x23, 0xe1, 0xb6, 0x5a, 0xb2, 0x65, 0x10, 0x20, 0x03, 0x93, 0xfd, 0x1e, 0xc7, 0xd2, 0x81, 0xe3, + 0x20, 0x5e, 0x98, 0x35, 0xad, 0x39, 0x33, 0x25, 0x3b, 0x8d, 0xc1, 0xab, 0xd3, 0x28, 0xc0, 0x9c, + 0x88, 0xdb, 0xb2, 0x86, 0x94, 0x56, 0x59, 0xd1, 0xba, 0xa5, 0x0e, 0x52, 0x54, 0x09, 0xcb, 0xf1, + 0x10, 0x49, 0x87, 0xeb, 0xf7, 0xb8, 0x04, 0x25, 0xc4, 0x01, 0xc5, 0x0b, 0x31, 0xbb, 0xf9, 0x5b, + 0xc3, 0xaa, 0x53, 0xdb, 0x52, 0x30, 0x7e, 0x52, 0x92, 0x64, 0x49, 0x8b, 0xdf, 0x49, 0xf9, 0x57, + 0xa7, 0xec, 0xd4, 0x0e, 0x7c, 0xbc, 0x70, 0x97, 0x74, 0x48, 0xed, 0x1c, 0xc3, 0x94, 0xe1, 0x39, + 0x41, 0x52, 0xed, 0x44, 0x8b, 0x87, 0xc9, 0x62, 0x58, 0xdb, 0x62, 0x8c, 0x1a, 0xed, 0x6c, 0xa4, + 0xbf, 0x22, 0x88, 0x6c, 0x42, 0x5f, 0x4a, 0xbf, 0xc7, 0xc5, 0xec, 0x71, 0x8d, 0xd1, 0xbc, 0x10, + 0x21, 0x5d, 0x03, 0x69, 0x2b, 0x96, 0x09, 0x97, 0x62, 0x49, 0xc0, 0xe2, 0x98, 0xae, 0x66, 0xad, + 0xf0, 0x7f, 0x8e, 0xa9, 0xbe, 0x23, 0xd6, 0xaf, 0xa6, 0xfa, 0x70, 0xb9, 0x05, 0xbc, 0x95, 0x1b, + 0x73, 0x0c, 0xf7, 0x86, 0x78, 0xb7, 0x85, 0x20, 0x55, 0x9f, 0xe5, 0xfb, 0x3d, 0x2e, 0xe9, 0x20, + 0x90, 0x3d, 0xde, 0xbc, 0xdd, 0x33, 0xa8, 0x9b, 0x9b, 0x50, 0x7e, 0x03, 0x0c, 0x41, 0x4b, 0x9a, + 0xd2, 0xa5, 0xc2, 0xcf, 0xf5, 0x7b, 0x5c, 0xd4, 0x2e, 0x90, 0xa6, 0x74, 0x79, 0x61, 0x92, 0xb4, + 0xf5, 0x6f, 0xe7, 0x03, 0x93, 0x7d, 0x47, 0xac, 0x5b, 0xb2, 0xff, 0x16, 0x80, 0xf9, 0x61, 0x6f, + 0x0e, 0xcb, 0x4f, 0x24, 0xa5, 0x79, 0x1b, 0xd2, 0x5b, 0x54, 0x96, 0xc5, 0x3a, 0x11, 0xdb, 0x81, + 0xca, 0xb2, 0x58, 0x37, 0xa9, 0xd4, 0x0b, 0x72, 0x94, 0xca, 0xd0, 0x8d, 0x50, 0x79, 0xc7, 0x85, + 0x4a, 0x0e, 0x96, 0x1d, 0xc9, 0xb2, 0xe8, 0x7c, 0xe9, 0x87, 0xd8, 0x00, 0x91, 0x6b, 0x60, 0x15, + 0x5d, 0xfd, 0xd0, 0x78, 0x37, 0x32, 0x2f, 0x3f, 0x2c, 0x96, 0x21, 0xe1, 0x90, 0x9b, 0x95, 0xfb, + 0xeb, 0x00, 0x2c, 0x8c, 0xf8, 0x6f, 0xb1, 0x16, 0x86, 0x37, 0xd4, 0xe0, 0x3b, 0x6e, 0xa8, 0xb7, + 0x5b, 0x0e, 0x29, 0x48, 0x3a, 0x13, 0x66, 0x71, 0xfa, 0x22, 0x00, 0x1f, 0xed, 0xa9, 0x35, 0x01, + 0x89, 0x9d, 0xc3, 0xb2, 0x58, 0x47, 0x1a, 0xf3, 0x08, 0xc2, 0x2d, 0xd2, 0x22, 0x4c, 0x46, 0x36, + 0x13, 0x8e, 0x27, 0x99, 0x01, 0xa6, 0x07, 0x19, 0x1d, 0xc0, 0x3c, 0x86, 0xa8, 0x91, 0xae, 0x88, + 0x9b, 0x4d, 0x49, 0x6b, 0x22, 0x59, 0x23, 0xf4, 0x4e, 0x65, 0x13, 0xfd, 0x1e, 0x77, 0xcf, 0xbe, + 0xa0, 0x01, 0x82, 0x17, 0x66, 0x88, 0x29, 0x67, 0x59, 0xc6, 0x48, 0x0b, 0xde, 0x08, 0x69, 0x21, + 0x17, 0xd2, 0x7e, 0x24, 0x1b, 0xce, 0x80, 0x11, 0xeb, 0xb6, 0xf2, 0x05, 0x84, 0x15, 0xa4, 0xb6, + 0x1b, 0x06, 0x33, 0xd3, 0x9b, 0x2b, 0x8e, 0xcc, 0x98, 0x70, 0x81, 0x40, 0x8b, 0xdd, 0x16, 0x12, + 0xe8, 0xb0, 0xed, 0x90, 0x3e, 0x07, 0xff, 0x77, 0x00, 0x60, 0x4f, 0xad, 0x15, 0xa5, 0x26, 0xc2, + 0xed, 0xeb, 0xe1, 0xbb, 0x2d, 0x2b, 0x48, 0x44, 0x52, 0x07, 0x55, 0xdd, 0xf8, 0x1e, 0x20, 0x4c, + 0xbe, 0x8f, 0x2c, 0xcb, 0x8d, 0xf2, 0xfd, 0x35, 0x30, 0x32, 0x7a, 0xa6, 0x95, 0x54, 0xf4, 0x53, + 0x1b, 0xc9, 0x22, 0x2a, 0x29, 0x48, 0xec, 0x10, 0xee, 0x43, 0xd9, 0xe5, 0x7e, 0x8f, 0x5b, 0x34, + 0x22, 0x8c, 0x63, 0x78, 0x21, 0xaa, 0x1b, 0x0b, 0xd4, 0xa6, 0xeb, 0xe1, 0xa1, 0xe2, 0xbf, 0x27, + 0x57, 0x62, 0xca, 0xed, 0x75, 0x2b, 0xf7, 0xd2, 0xb8, 0x82, 0xd0, 0xe8, 0x07, 0x32, 0xf9, 0xa2, + 0x3e, 0x04, 0x01, 0x3f, 0x83, 0x08, 0xfd, 0xac, 0xf4, 0x8c, 0xe8, 0xe6, 0xb4, 0xd0, 0xef, 0x71, + 0xcc, 0xd0, 0x37, 0xa7, 0x3b, 0x79, 0xc1, 0xd8, 0xc6, 0x8c, 0xdc, 0x6f, 0x72, 0x7b, 0x72, 0x56, + 0xfe, 0xce, 0xfb, 0x2a, 0x1f, 0x76, 0x51, 0xbe, 0x42, 0x6e, 0x11, 0xc3, 0xda, 0x5c, 0x77, 0x01, + 0xfc, 0x1e, 0x20, 0xe5, 0xb5, 0x23, 0xd6, 0x65, 0xfc, 0xb4, 0x81, 0xaa, 0x35, 0x44, 0xf6, 0xab, + 0xf7, 0xa8, 0x80, 0x55, 0x98, 0x29, 0x0f, 0x47, 0x33, 0x0a, 0x40, 0x18, 0x35, 0x0f, 0x34, 0xd6, + 0x07, 0x56, 0xdd, 0x34, 0x26, 0x4e, 0x53, 0xe3, 0x1d, 0xbd, 0xf3, 0x3f, 0x1f, 0x41, 0x22, 0x79, + 0x00, 0x8e, 0x30, 0x76, 0xcd, 0xba, 0xac, 0xfd, 0xea, 0x07, 0x66, 0x1c, 0xc4, 0x7c, 0x0a, 0x29, + 0x21, 0x5f, 0x38, 0x3c, 0xd8, 0x2f, 0xe4, 0x4b, 0x42, 0xbe, 0x70, 0xf4, 0x4d, 0xb1, 0x54, 0xfc, + 0xee, 0x30, 0x5f, 0x3a, 0xda, 0x2f, 0x1c, 0xe6, 0x73, 0xbb, 0x8f, 0x77, 0xf3, 0x5f, 0x46, 0x7d, + 0xec, 0xcc, 0xe9, 0x59, 0x2a, 0x62, 0x33, 0x31, 0x2b, 0xb0, 0xe8, 0x38, 0x6c, 0xff, 0xe0, 0xe0, + 0x30, 0xea, 0x67, 0x27, 0x4f, 0xcf, 0x52, 0x21, 0xbd, 0xcd, 0xac, 0xc3, 0x92, 0x23, 0xb0, 0x70, + 0x94, 0xcb, 0xe5, 0x0b, 0x85, 0x68, 0x80, 0x8d, 0x9c, 0x9e, 0xa5, 0x26, 0x68, 0x97, 0x0d, 0x3d, + 0xff, 0x25, 0xe9, 0xdb, 0x7c, 0x3d, 0x09, 0xc1, 0x3d, 0xb5, 0xc6, 0xd4, 0x61, 0x66, 0xf4, 0xe5, + 0xee, 0xbc, 0xfa, 0xf1, 0xf7, 0x33, 0x9b, 0xf1, 0x08, 0xb4, 0x78, 0x3e, 0x81, 0xe9, 0x91, 0xe7, + 0xf2, 0x7d, 0x0f, 0x21, 0x8a, 0x4a, 0x97, 0x4d, 0x7b, 0xc3, 0xb9, 0xcc, 0xa4, 0xdf, 0x88, 0xbd, + 0xcc, 0xb4, 0x23, 0xd6, 0x3d, 0xcd, 0x64, 0x7b, 0x19, 0x30, 0x1a, 0x30, 0x0e, 0xaf, 0x82, 0x35, + 0x0f, 0x51, 0x28, 0x96, 0xdd, 0xf4, 0x8e, 0xb5, 0x66, 0x95, 0x21, 0x3a, 0x76, 0x79, 0x5e, 0xbd, + 0x24, 0x8e, 0x85, 0x64, 0x1f, 0x78, 0x45, 0x5a, 0xf3, 0x3d, 0x85, 0x98, 0xe3, 0x85, 0xd7, 0x4b, + 0x20, 0x73, 0x9d, 0x5b, 0x57, 0x00, 0x5b, 0x13, 0xff, 0x00, 0x60, 0xbb, 0x15, 0xf2, 0x6e, 0x21, + 0x06, 0x18, 0x76, 0xed, 0x72, 0x8c, 0x15, 0xbd, 0x00, 0x13, 0xe6, 0x05, 0x88, 0x73, 0x1b, 0x46, + 0x01, 0xec, 0xca, 0x25, 0x00, 0x7b, 0xed, 0x8d, 0x9c, 0xcd, 0xf7, 0x2f, 0x19, 0x4a, 0x71, 0xee, + 0xb5, 0xe7, 0x72, 0x9e, 0xd4, 0x61, 0x66, 0xf4, 0x10, 0x70, 0xcd, 0x72, 0x04, 0xe8, 0xfe, 0xf1, + 0xba, 0x6c, 0x92, 0xd9, 0xc2, 0x9b, 0xf3, 0xa4, 0xff, 0xed, 0x79, 0xd2, 0xff, 0xcf, 0x79, 0xd2, + 0xff, 0xe2, 0x22, 0xe9, 0x7b, 0x7b, 0x91, 0xf4, 0xfd, 0x75, 0x91, 0xf4, 0x1d, 0x3f, 0xaa, 0x49, + 0xda, 0x49, 0xbb, 0x92, 0x16, 0x71, 0x33, 0x23, 0x62, 0xb5, 0x89, 0xd5, 0x8c, 0x54, 0x11, 0xd7, + 0x6b, 0x38, 0xd3, 0xd9, 0xca, 0x34, 0x71, 0xb5, 0xdd, 0x40, 0xaa, 0xf1, 0x13, 0xf1, 0xc1, 0xc3, + 0x75, 0xf3, 0x3f, 0xa2, 0xd6, 0x6d, 0x21, 0xb5, 0x12, 0x26, 0xff, 0x10, 0xb7, 0xfe, 0x0b, 0x00, + 0x00, 0xff, 0xff, 0xec, 0xba, 0x10, 0x62, 0xd2, 0x14, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/proto/ibc/core/channel/v1/tx.proto b/proto/ibc/core/channel/v1/tx.proto index d4d6df1d5e9..15714173a1a 100644 --- a/proto/ibc/core/channel/v1/tx.proto +++ b/proto/ibc/core/channel/v1/tx.proto @@ -47,11 +47,11 @@ enum ResponseResultType { option (gogoproto.goproto_enum_prefix) = false; // Default zero value enumeration - RESPONSE_RESULT_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; + RESPONSE_RESULT_TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; // The message did not call the IBC application callbacks (because, for example, the packet had already been relayed) - RESPONSE_RESULT_NOOP = 1 [(gogoproto.enumvalue_customname) = "NOOP"]; + RESPONSE_RESULT_TYPE_NOOP = 1 [(gogoproto.enumvalue_customname) = "NOOP"]; // The message was executed successfully - RESPONSE_RESULT_SUCCESS = 2 [(gogoproto.enumvalue_customname) = "SUCCESS"]; + RESPONSE_RESULT_TYPE_SUCCESS = 2 [(gogoproto.enumvalue_customname) = "SUCCESS"]; } // MsgChannelOpenInit defines an sdk.Msg to initialize a channel handshake. It From 163fbc4bde2ce6d61c1bd3440e9f879bfd7bb5e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Mar 2022 16:09:09 +0100 Subject: [PATCH 046/275] build(deps): bump actions/cache from 2.1.7 to 3 (#1150) Bumps [actions/cache](https://github.com/actions/cache) from 2.1.7 to 3. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.7...v3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fdcc086ae4f..330ac7ffdfe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: - name: install tparse run: | export GO111MODULE="on" && go get github.com/mfridman/tparse@v0.8.3 - - uses: actions/cache@v2.1.7 + - uses: actions/cache@v3 with: path: ~/go/bin key: ${{ runner.os }}-go-tparse-binary From 40f9da1efa3f2016c19462d6c2c455812f3241dc Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 21 Mar 2022 20:55:58 +0100 Subject: [PATCH 047/275] fixes for go-releaser configuration (#1148) * set the pre-release status if the tag contains alpha, beta or rc * add separate filter for final releases --- .github/workflows/release.yml | 3 ++- .goreleaser.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ffffe3a4dae..db50dc06ba7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,8 @@ name: Release on: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+-?[a-z0-9]*' # Push events to matching v*, i.e. v1.0.0, v20.15.10, v3.0.0-alpha1 + - 'v[0-9]+.[0-9]+.[0-9]+' # Push events to matching v*, i.e. v1.0.0, v20.15.10 + - 'v[0-9]+.[0-9]+.[0-9]+-?[a-z0-9]+' # Push events to matching v*-[alpha/beta/rc], i.e. v3.0.0-alpha1, v3.0.0-beta1, v3.0.0-rc0 jobs: goreleaser: diff --git a/.goreleaser.yml b/.goreleaser.yml index a1df128c661..63ecd8822e7 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -24,6 +24,7 @@ checksum: release: mode: keep-existing + prerelease: auto archives: - name_template: "{{ .ProjectName }}_simd_v{{ .Version }}_{{ .Os }}_{{ .Arch }}" @@ -32,4 +33,4 @@ archives: - README.md - RELEASES.md - SECURITY.md - - CHANGELOG.md \ No newline at end of file + - CHANGELOG.md From a776e47198489a67a26ef79a1b7feefb2651eb62 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 22 Mar 2022 13:52:11 +0100 Subject: [PATCH 048/275] add banner image (#1158) Co-authored-by: Carlos Rodriguez --- README.md | 7 ++++++- docs/ibc-go-image.png | Bin 0 -> 1460199 bytes 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 docs/ibc-go-image.png diff --git a/README.md b/README.md index 5a3cf3b7e7e..f4a830c5149 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ -# ibc-go +
+

ibc-go

+
+ +![banner](docs/ibc-go-image.png) +
Version diff --git a/docs/ibc-go-image.png b/docs/ibc-go-image.png new file mode 100644 index 0000000000000000000000000000000000000000..649c879bad963a747cc6042dad4b0fe14bc18dd4 GIT binary patch literal 1460199 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
  • iOZsD$GZeBN0@4>$%lrz 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%0Aq({=Vu3vHpjfV_Zl*0BwSnkU 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

    &96N)%duM4y@Mu&|%rR!TnPz$UXqQ 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

    0guc2B*pjrc8+#PxRh!<>Z*? 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 z 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�mH9P!QP)f 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�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

    )RDt(CkMhTt{hae9 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:?l==5p=cC|+mCOugrHK9 zz|{%j-mW&BvbZ|z!BXVHlYk9$dsoOod)2*@88nu>blBx}@!{K!dOPEgCEWPJ=8g$} zbA#}|apF!`5Lim0r|Kfl(s2cTrdO0w@22OdwuLq>w94-hMsF z`vHz)$80CMjARh=A|)-Vzs-$+mLFY8l z39ns6kj4$lOL=?Db25Uz&#T{3=^_$YtyleheY&DqZbwBWt=gvHE-`?eTpT?k^mjd>51AU;li^}sO zVz1sN`sqiWWA;#rPfh5;+|dTc{ga}a_LH*NF8Q0DAtcrgp7xYVdO?@jj#7e4zYL#s z7RE0xDxq@gO|6aW&alW`rV@SoQ?;<<(d9-MH*X(hX@mKrCrw8`Pf`3PZw8yDB=WP< z&_9(|l_BzYGdYp?_a4a<7^J0slQ=_qdI=6$LlE%WO5jb)4o=yg_TG?V=606Lp2SbE zdF zN*F1C#!8)S+xr;s49qmL%i+sXg#|G})3$nIRkBVfW9H*{!@}#i0&<=|N0{Hy=*_Tq zqos#{Gby=j&B!-;DRg&Q3b$1m-cL5Sdh&UT6D~sPc(aCm^#1$+!22RO#NGq#TP|z6>$HxMRP7ntuDkvL$;kA$#c{h0J;38{FvpaxR<7GLj&i7cj z1yu8>Y@zKVe>ic+vz<9)6l6(4j#n7}dBytJ-RiL4hUA+wJTNuEZ@5YP&@U%L#aAp+D<$%-Rc+!j5sivN zQ3`-`|1;bI5OrEo6n_x9YEIDsdk%}ELwT(L=>IZVK%V-2ZJs-x=USsRv9N$lF4__o z8Zoae#r)grF;}F$^AhOw=j0-Uvt6{Mv*`^mbT>;A5pvG*mt8OnRMH(cHEU5I1GQ>I z!(Aj|O6_`I$E8d~y@Ax!StY<-&awcxkmpvlqFf=u?f-y_VuD>QF)h4yt_jOUIMOz8PA)jz!K^1&(2Nj&Cj_D>z4y;Z%2;K3Deq_-)C}7M&7jSP;d34 zbc&AYClnFx<|8`VFQUj4iWgfsTzDYe38fLolr&hX7uC>IDA`>jKs>ava?$l~>G@pO zkH2kWv9uROVR1{Fe_ZLFHio3hSS?xq#5-EMOqnNSQxoikLuK_JuYX!hrW|J?g)Z=& zKmPG^8p6=p3Q^x1-|C5%css;w;tK{Ie6t%}uOuyo(G#IF>ygpy(U`N{k-;$J(%%zl zT=imHb4s0AxejWeHaQ+7VPT4$St9_3#g_ZMunoUU_;y1ubMyzdKp zscVlGJopL8iB+}aGD&)q2p8tsVm@DJh^P#d?zhyWI85QkhVrkJstvj1b^0TtECAMr zyUgdRKu{q-*TK){5N>1uavS?(g}MIrf9Bx8&y17=0c~fB0%h&ra?62UjT4VO$EEsK z0vTy*SNV;dnwX@||Y%aop6brM6RsQk+u-pUVfJgNnoDppDyVpDWYK0w~`nekhQEnOz^K7C^4L|qKWGFcLfUs{90 zE5d#z<={S9VEX)k@Np==i-|KkS(?`} z+S6{}U2{P63gAiY;@n*Ap*~=`J&(8&8f^KvFd}B{D*VAg@7sFj8ppnbz@FFGE)ty5 zxim1yU#&=nX9RWHx&5qlo(JjTGqguv(kn_8+-P&{1}~4;R~bk)Y1wlzS3K_Zl@+Se0?^4A~w7@BK*bJ_!8F z^Cj;L7XFUM_;1`Q<)cVzrAqjmL)Zq6I5mo9|G$jXrghHl%M?esCRzC6$E?nrN5FGA zsD{opXF0Bj(*r)K*Q|#=8!1oGWQ@hMUTR(W9ofPpk^BC-g(0i`9y zaAiolqdKC3j+)0YQ)=+bSD z*K1+s7muQl=L!0rab6fqAvU~CHxnX5_rp$ zKy4BDF%+^K=exSt6N)>#7tZkwRqLSbs{*f8o

    bt->3wkC2LAjKd8Y)n$3&Y}-UT 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 z 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

    VcD?Q%^jKvdP9hR{4;15 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

    iI1u#`%}CGKBk+{81B4B6*rtW;@B-Qm^^_ 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%0D80``zrp2J7JG|Zg-4yAzhc-RVI(mb${N) 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
    F&-yr8acL14HR|6hb3ZAj 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

    lVU})PP{DbWXcmgy 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�qYGO11+Yt_Ob> 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

  • uLzUU6*j9N#{SjF+L98x%y)ByF&-x z^0$&YGQeW@3ktl2uS{yky(MaG->=IE!WRhdvk;2$K*+8AvVMCPWd!HGgzBx=Il<}= zAcy^nM5>LC!h>Ijkf-z=8G5Mj5$#k`s4Zdl%5W{`r_+WJz4oh&nBYyu_4|beTi|;E%;LhBsM662f z+TCEquC3fezv)c(+Ei=-@RiU)Rh0AWJ=CNIb;*n}|LX4wPSZa66V^y8)>?Ty2V-Ve zm2ugWN2jnoHK`M~m6qP_Q<*Zuc%I#*!@iCrQx#9RIjyI4RE5$$EAbQpP0*73eb z^bEeR_mTF^cphN4ff2?tv5!f1QsE9ph^?1%y0bt&S)vXNjjK zP}J?teR6~Z0bKE(xYTZ|3jG;DLpZJW(JlCcqma-XD5#ZlAa%?F0M z4`rs~%n9(fd4IIxlVCFIqb`EzQ9H&Ap1C&53v;7R0H2u*P)D>;&|ha(U{Vi8WLNhB0!iWZ_EGbi2c$l>*h(ysn zj4}lI{BUBHuiDm+y`JM$Xl8BE7cq}<^A87?rp}uOBK)A6pF;3G!QBJ`a>)7i+*md` z-@=^BA*+Nsr!fYqF%|X*GqMww+mcb8N%tnduF;4RmWvq;pFs0`wggI0uA3w@LME_+ zN{Q>BIi{}|{R7B;c^w0BC?Q%(ryNiH$7aj8PzMO)yIrYdh`v&kAT})2b8gAtKiST7 z?fc}txy*Tay-T-yawxdFhsQh87Zt>x+40=LXSxQy-GE8S-|r-Kf?SL}jtHPYjrdzaCbJ715 z&WXnlb6I0P$6VGM5g?&o;&B!8qym=JsQ-5}OD{R1rG>OqhalFbc)bqovHTw&fgi zXo&FeoND~Kqx9BRf1z7&j>bBrFwj7!FI3)zBO!JCDgE8(UqJcX+03HAQEv4PUI|+K z(yh3aD;NLF2#6J@js`sCY zm3;fdN_!1$iBxyBq7rL&Ga}dLl?0DXG>)O?#(0fK^d{}g`Gz)$@k~KTuFtFPa2u%O zfdZj>6<8Uu>4P2*UDB%Ovs>6vx1I9m9=MI}XdmY8U<&l%jKQ4YWR!qY76JBx?<05h zZi9ozJ$@=n#c6blLax07H0rjAP{Il?-zby*-)Q(Azp2o%!x2>r>MnwwUX$rf84=0~ zcsFYjx&PChUH^H-aJGim0xK*Yb_zeyQ?T6ocC_vh;77HT#F4gRE7C$ZG1bpjyfAQv z$}@i84jltQJzs+;MJh-^gm3q?I(&Kds=kS2KC|Zh*af zsxbmnoT_1WA=^)q&EH8w+GlFQRBw39V=-;9n_%e?(VI*=t|inRY|`3`zcBg52I?Wt zR+362oQ>TNZ|Q}$h4aERa8s=WIVq+qhk^f zc9jUM|C;D2V8v+J`2B?O{oJ7%=c%VhskI$bZ-0e`WM$Hr)^_7EU$=KHwEK;Y<<56Y z+%954%1u~HA5jkr!3QZ8xtKmkn4{T4dzN)>I3JerRZC3?rO*sM9o@%%v*4Pqyae-^ zTCGOX`^`V2Luk&&#`bD$v&(kf3epX(4yZH+zI&_lpksd;;t| zqLcn6a8_9-g|Pi>?CAaUVg8()N?ud2OlFQTIgO!2z3Nf8fQK&i#JhbSHQMz2Xhg#& z+89UwJ3pkq70oWLx#*f|QXAe^$t3SrH+R&9ip*+7ZP6W^f$f)(7}LCTJ47QF*n|HH zeb-xCbv2}a(K50@uB*`f4=vpV;1d+0o#-j$hVdD|Ro&XyYDvaRJk#K+NSC~)rqQdo z($}`Eve45%-{s7^p)31l36a|qI$00hTUO+7pCq+$@vV2BDc4WFJC-pFask{q{idaA zpz%uAJw?Chy41*9hXqX&?9ZnzdCB&lYn@Kwy5x9H8cR-$_&fk{lZBdvuRYzfWX1)S zp#%~-zHuUtXJuzuVZSR<*Z~Q`Dg}CbCM7bj!?hP|nr?SqtzqP9qV*e@z+=KJO|YPC zbw=LDqHVwF-$%C_t2?q6++}V{q<=tCA6xQC1D=0H(Jp?B3(C9<%p*7vFj)!Z5jI{7 zcH_6@lUvd7vj47<{WUvYsqcT7I;ZH$qHSv@6<1WTZQHh8v7JI?tj~qgZV7z`5b=S zQ@36J^NakUc+sPY1TDvms-#fQ6G{7irm8u4y7a;I+WrBNQ-A59Zc^|M(eU3MUQ6sS z3IDam|MKm)gkTxD^T58e7DHf!V10jDXuVn~-g|1XOj}AtTGd|)m7q@8dFpx_tDCY0 zkTDP8@t|x~=?-`{F+?M;0|Vh1I^tIdD@WZS?E%e$W>&ry!G)`pTMJwVu@+^S>Fr z_5nGcP_$NDSne0x1v>SAhTahFC(UQ0;aplgozQ=fzG7tO1eWL2#zT86r( zEe=|5O|LB&Ke?_$n{E|C?_-q2y2N`hmeizky>WF|RUCYI?koO~F;z(ljgPX{eX9~; zJ!eK9AoM5Jw^)qn*~@LIn4TYhLg1ns_eGOx4N_(~+Jb2wBpzz@Z4!D6zXr>R|HxLmwP-BHH&WR?fy?rYcZ!q z==QOjiAxo?>Z_|$edQ05OF8`c`FQpDNocHBlS+6p18#O!!}h)5(tCN>n*@OML|G=m ze~p4~QMh@1CBw&iiqQk(0~MQ8!JV5`f*ZB^GXzKvmt==X&#qWUumJH9_SpbR2yJ1S z^e|>djB*b8WXH?yKH!e1$FT%$dUf$2k$TV--1GV|WVfk_GoMgvy8LP7T|LW6g|@!u z&Y?puHlt--zH#9}9otND#uXlh=ev~HRw&;uCKobNf)sGOHv%VWF#?DTdamE{#UPt$ z(U*w**7gANoKM`#4auX-d2kxkZj)3bq~jTWpV@@AQ=)Mx7R;I67{ksx36HW;rU)oE z!^hdlxESALB-KlEx8+509CDC&y8oQQ&<~@wjTYm{7_i3iModuJ$+nuRj)(4-zuo_J z=Op>-O2b2`o32*Ir0Q6w^tUvg+-vD{XvjJ55hi{H9^-CnfDmNAHXb=IVG`FKlX-K| z#cu!V&_>~&kqgxrIUbatX+?ZsdqFOZ^Au?t<`I%dX(qzVpUWSTW+mc9bs!z7?>EuI zw%i*XYqN_bb1iX4dJPG;#n*q?C%18e-YEqaTOzD3HDsbZ2efl>(WWEoAm>#rKQiO& zerMBL{B`&q_D_P>@LFy@7}hA8fKCpVi_U<&t!%y~^^V%LX~%;j!6h|2HQT#0ZssTO zTZIO>Au()-p)O>x+I)GQG8-W`;h z)a*`mEj0zQo;=v-he&U7%dS2mLesLNTrnBy8>Uh*2~ke*0phX++|u{~ z2Tt0UOG3qA_&I8;#FUbFmNh$(=O$(3(%bsm!z`gnPTGQLhzXBHY|->Fhb%$C^FGUN z9K%p`LSodY-|j0HpV;)W~i%8Q71B zJL(fgWJN=Ix5-8LG~C4wva;>kLoqDU<#BCZXr|wOH>HYUHZ%fWAO3&m9W*)SG^zX9 zdA4~gxHJ;g^giO>zOBV;;nCP#zG0p<))ssA*7bRQdR6rVcJz$j-;Ais7`UM4ppqtC ztWFt3K}k!>xtvoAE#V*Svlgg-N6)fiEnWa%Tp+~jU$9_kP%tAOoiu^C{?we*Erat1 zE9BErJg%YREWZ_ui(TzmHHqeLbp9OGm?Pd-+y%IDI~cQAs+bh0C)s3cvv%dxFc<)( zEwyiHt0)9wrw)}kbHf;8I#l7wB(gYgwiMR*FI!=;r;Z<`N06LUl9XJ-R?9+caexEl zSpLodR!!O0H(JQYgp``wg_-=eaed$H3$JL$WBZA5hX(5`eGcN4-8%3*WV%mm(?Z5k zN8Ep6x9qLGAveCyd4M{6UoAU2`23&TO?$IA+z-x;y_<{?A{m``v>?xrWx}FI6P-wr zh2Cr4U#8xp1V~$Wph3-y6WX6&WE_E8FaHZU&dIGX7+#A+JTIepqDfF9;4$Jc8%4D7 zm{KnSooPpZQGuKdKJvn0sB!T=@8Y+hX0!7zbEt8byJd|kT}Po#QXKrw4loKiXS@dB z(928Vt-tre*@3AKc9reNaWgUE@+W$G4{x=P)6iOk0 zvM%>^Qv(#VJ?yd$EbkF2;H<_<#NrJI}p5AW8rDHNx>YR+ja(*PL z)6oVu-sMZdr*k8_DC%T+-Eidw+#$WLVqK#ppKCHizZl*IrhF2p+DcNmbYS7OovMYd z;VX`I!+0j#BD4Q&FbjlYtv6Q`pm)?=y!7LmwT!2-aJ8V_DH33giHd^|La58f4+v*; zx#37-z;_qjDJGSLF6(D^por?>17pas-h^|u{h4=^f#2GB;l}IXsTL4txy@71KyGfx zbA+-&{?E)Z{F*Yz+WIOAappHCKb4G1___>LhnLQ>y_)riJeB5HZHP2WPZck>KgO-O z6Qh03Tysqnsn6Kx6S}9X61S0@r?wEE$M@BsB=m+@HWU|muzDzkDD(Mq^5rh#5ek9C z2wR4p4T2UE8u)^@uICETruw+C2+SR;RO_524V3;7LycHy;8llMC(kAifOSZ~n)mf@ zfUYfidSwwbDFuTSQo}C$E-LYb^#Y-S7rNrcS7Hjy()$<(4DIAMPiK9rwQ7 zQF+SN61G&7ex=K*4@vc|-U*|wi)j?a=B>69p#y&)`&b1=T9ygFTQl4g9|@?}CO?7@ zKxZ4)8q|7b8gaiy^A=%HF_~$9aN8J_)2@`quaC!4Vm%$SefmXe>m(D{^}So48I-^fE9dlz)v?%f`Y#5n&n^q2ZR( z6-y3am%<5QasyyUUTvqiU~25}JEnwOrl7YH`uGcl2bYG1a})NFqevXJQBN(mZ+bGp zB*?56*YhD^6DJ`k50S$GP2b z%H^#HRW_8th*JvZQ1Inb4uyL4mu>le(d4T)`$*au+LYf9bWKf3{ zj68YZVQ+dOz5=zxi0$6n0ms4bxKDm zwRRoL{MJ6^G@>(rIOL7=gkR$B6Znbt#5;Q?)Thzx7gzRqyTViWF zR_5}W>s6Md(bP>@Gf}nRQ2`c4j$r1Bpc5R2Z=wwDIpB8*QGn8x`~!R!mV9&gALd)}4bgGC>^758m^@7>y+$!ovm25ldbTj5AYXYP zw0th#{Imnm$0iHgfA?L~ML zFUiiLjg-5rqY+MeskddPZd%tl)}CB|MNH^OuI-^)wu)eeAH;i8kM?IzhTaoL9+ua6>ehB2#Y=u&zQ?^=9_f(q`{HLs zXK#Iu1Fs2C)Wt{TQ*6&ftfG>>_xFFEF&>)WZNyF&ZwU5=#s66Kgs%p18(X4ALSHSk z*40r{rUZJgldC6m`W1WI!m)Y6Gbz>{Pg>Jvk#$PJs&0&f!tvB#ljjGE>DRd8nAvCd zSh>qrD9!Z{6m9VeRia59qH`5GA|x8}mY}JA*dmAvQf!qf!1J)AWy^gCmkA8M@oCQX z2dZpOPxD7D0lj38j+612j|f|TURf(a>Ab=sf$yrrADs*LUpnf9QH>J7yC6w;T(4x; zc}kiUVJ;QTk$KMpD??cyAPS1#uqQdi!=7q$=rDLEc|yLi>|&5~kTA4Dt)Jynv9@+j zYBd@%S(7Gbi>}b%w+6@+A~JTe?G#1vuG8Q<4oiFFe>~{DZxMv_%1LqetMMnIINZCo zI=NThfynv0hr{{ZXi{%Y@63xQL&a4e0 zG?Roo^~J}(OnzpfLJ%B|2Os}xdn{DB|LS*euS?J2hr?|}#ud#4z)ki^ygnLCkSBYu zy%1%EzqYQQ0w7{{-UWDhow4VEb*`#2%*PFfBDsn9D2p3A2s%v#cH)j)z{|Fd#ZP&c zN2SF3E6WtQ$rwuKVGry@m!eIBV!LIp<{Tx4Mw0%+K%eQq&;)ikt?Nd%u87(xG;cAS zuwYjtQVh>M*7|Q+?C)geZc~IcURR^9&i;poYR!Xp2lv4O$ukqAW%X@JPVVoVNV-Hh zX+TDPnx)vP5%@1ON|jVz8~wEcKBCZEg!*LphKe1H916|q)E7FoH0V=&der-ZUo?xZ z$2B|?GpTpT9%;pzR!6Pr$+Iv4%O>|Q_cZeyeNl$|%_S_a301r&x6 zpg?6%P1#H)7F}W+x`FC>xd%38i7Ln_UbHV#)q5j=Dv9sJE2~%PKP=D4VTs|*^en{W z*dCcc#Ca~V#rrmHZD{0|hIiHQ+7~a(9{-IpeEPHFfmqcXZ;rr&muSH*7_2(ER#-aC z=v~7p^)3|8^lr8dc~W^Hcn{*Z%+p{=*okH&1hM-y*#@ z?oe4dDAE_KFaP2TT>MJPsc+w0)1<$cK)AIU4$Zj6`_WhxPIp-9?a zDq5kRJkgH!((-20zBhH#f!Gk)p#2bv4@`l@_yyM*gS_;~C|C--t=D^5SGYcw5MaJ% z`f&vpmtq?#!8k--X8J1|)5OUaM1U~a@MXd9OmV)H6G_3)Did0}sh+$WT7j)Su|jM= z;_#t>$iZ|K7n8J7LYLj&O(RtZa7^-Y+I@#8fcqTPb&PoXpF2cAn`M8hH8b~~fd03Z z`&53XmR#I?LXnCqlusRb{3lomwKy#@-YN;jNohrrH`=3uyIy6`HQcIY`{Y*_4RFEP zsslo!oi)25i2wBs}@Ib;>q`^fB>w<200}*yc z{0Q0ij3(J(__%)h(jS=iDmndKj-!bevFIuJh*00Yw7Ax*^i?~`FW#`1$PBD#oVXWu z`B{)u^6kxrds)R{I(#N(YKvM#E7g?3A+^)Avbx*BAQ2 z3#csCjICnFT(YdG{xXAG2W~VS+Fi_8Vv05L>e>x@^Y&J;qT(Mp{HF;gZTSR8)CAhN zc$)I8DPH0>t%Y_6ia5LKQ<9giEQm)?V?FI9rFu-3Y@b(~i8K$U#e zjBt{}OWa>?iLIFjao!IG(__M3u{Bg zCN4kN8{`Ao>4p?i8+NH!+|6QEv>iI4cAeoL)i4h8IZ4r& zi1Z}?4X>QQVjg>A<5=k|7QaY6EYRH5BBd(ic5>6}UV}rEW{Dfb^RS}Y_Ur3#)f=|X z-VBACs~dcCL3I_+$EA2wS|!+ea@SZTl(33tS^0#3At1}W?>ikL$q85FF*N;rC{X+& zYYvHW=*za#h-8U|fm9{zFMgDsq$Z$|^-e4lsaqhq5Gjo01w|d&D8jIkvY>0Am`lAu z=&AgpfLwukBPc0JoUO5tj6VmeW@q%FLPBo4byZl?hPg(Cm<&pcF~~Z_f?!IMmL|rW zNO82x@9H#^5V~%(ws{zr*l)6>QpN)-cbUYX5_^T=)9b&?=uI_f5dtI|0n~L1*0DRZl)kPkYzydiw1<=b+JB%+jF45sc`0=kwhS<_$Yn zq(z@iq)oi)J$-`h)1;um0VL*ux`=2>jIFpU)uB8jXp(U*Ia6*D5}W2jM9xL3LV@Ku zzNFrB_nO1toJ`8)e~8#0ZNcmP2*DPi>d3kW@LH)$?kUAPd0QDx*BhyJi~HiU;TSj` zJWP~`stvrip)q@66Vdc$Ke3j&^OjOC4n$vXz4nmHBj7FI|4NylA{z{lv_@wRLN*v( zZ~cWy`cV%2211R>j!;Rs*0PX zQ#na4c%|kp=>qrH{kQGNzS4xA+r2Rm=VF04l#cjfCx#K-x+~7IuVPLv?RM(8c*ZYL zF3<$E*iW`(w1$dN8Jxbxh5zgTK1WLLu0mwbp!ZD8F-^Zgyo1JSuLY3Fmm6cUEW`R*}96zqywZ1MHnsF@#R{3xT&F*swX1e%CA1sV)G_CH9Owx z_haiV-(H$6Pdc_S1>SdJ(CPuFgaPqm;<`-%#=oCZA4d`NL?5SHRtnk%kn2-3rd3WF zYQj~%^)X|vzTJ6r?dTrZT|KkB3d7WxBjvhE4*{b*>vir5~P1u3aXH)XqVupX$MRv{P+`+%~ zCVY;D`Gpai=W3vPLaQ41K_FDM@N0d*9D;Og`~AX|a2L6j6$A0~>Oi|r2hVmj#lu($gh`)<%Z5qLOkqJh;@NS^lF9$rek2dYkfL`)Ir#2-RhY<;f% zqr^VY)H_nbYdRWKFKOn9i%2o`^GwgcHW)nD7u__bB-;vMzu z4A^i}DF1>Gn^7G_NK=w-Dxokm(;s^Q!#(QaHm~74IsFllu>0n{I7JuQ*A}IOWZ3Lx z<9amenlmfvMzAAK4fC>^0jj4h|jdm|s`&!YOmY?z$5cm!XFqhV9~z=3V1?FKp~_hcdb*ptUO3WioD= zk1YrQD2ghGzNEX0qck~}77UqkuhD|;FXWD9CpFd-Tz%o>N}@x}TuV~1a@-+tu?2Z7 zlSsLAKn>o`hrh;0 zAh#lhrfrX7=<2Tfo0bGoa=UMZG2-JpeCtQ$N1VIAjsk>P%9KZ8^EL$UWqeUNQi}<(n`LrpR1dxAtM)rt zP6KXqk4x)ba~pW?+3{42LYYl{@|;2ir4(ko6}ftNr-9!aj1w+|Y%{%b&Y)}ltUXCF z0pu?`AErj`9NMG=Hw$9h`R9@?xmk&Gy5Zucy%uLAXaI*w9A3o<*2S@H&Y59?i~AVk zcwU5qXLO|Icd+*n^S{!OT--C8=jF-@Lj=v4^&1?=Ul|=zW<~u~F(oA84LOv^--oT_ z_IY6((Ny;||Q(|DLs-qN7UHFqYQDXE9yF=$}?AV04=#!Z>Un|C- z_1lr=Qt+Vw2!I(KCDO9&y`cY2CpDcr_pFCQBoXAdZywZ5X}4GGaUUHEw!jn~K(F#w z<>FaedI6T|&moyiowS9fm><&)+Ebx56;_$Oh^7!13EXN;(_#t^Tx2hd{>TJZsCdT> z*=wd@YEYiiB*~dMwlK%Gl5l<{n7JAd_}Eh-pBk@PgYa}g<5>Tf#Hj|1Pm}6_lctwidude%uYPNb53A6(EI30 zo9gKFv4666kZ8$Ea`28H_HDy-NWxEm*nIpkU3626!i-Vg)=7?P>;AQ`sIL^rcq=0_ z`LRsw42Bxxa2k(cg3nUgrZcD^Hqb0j2SE)pi}xggqt-F>qa)xpNvNP!f}`exPlE*% zLMkJlR@q0Q!ntW`*4tE#XYCPu){B7*Pz(pKY_9IMvKZh{2kKctK9egxh_xnz4Wx_0 z%0I#F`@)OTBeCJ`{%QC_Q5ijKP-R8R^*Wmr+L6{m-6$d(pj`H#FoL&Q94x}c8>LMkaes_ zSp27Fz@NgO>WV$H#z|QJd4`aL#E6?_SMYZ9*=LCFzjl@PQkIvT_q@8a|Ma=J<%Wm; zK7xY&p7HfKYTB;dr}_6w6Pq{uKf8ciA%DE<2h&h00!Z+m0%*W}Kh(7$#y3npu8M0! zU{qps6%=j=naX!VcUQt#ILBZD%}mqsB)o!E2@vhEnxa}qR#4G*aMsSD;b zgcS>lw*z&}VcWkYIJ&PN3>hsUM+EF+rJ{F4h1%S+dA+1macxsYPQvN|ofAs~1(ajb z{Q#iI0;qiJ+3jT|?`2GptB267M=evjeX+5FbEHZ%G4#_rSh0?=&t z+|VrUN1+fUlo!Q$i;qJ;j@Dm^VJKXeR2t{2f79I+KB`f)8qeX6>vQcS7MDZ9nt&R# zGTJ$>vZ_NVoI_|n=Xe-N86aY7 z#2BeShWDOXVLcCFC#zT$o%Mt@igjRaRTL*hTHDw*o(I*L2K7k;ISJ&wp#la{JXqkY z{vMm4>sr;u!j9~oQn?$+t`>!4C2-lcIia%=0c_lwuTe$7ua(Xble{*`*<;CwZAdH! zgDPw$w=e_mIHg-nV7$&f`xBZ`<|Q5Hf$xf1$OO-vao!0NECH8Se&L8apE)!^@a)F8UM5p)HM ztqhGe!m|kOOrKh8FsKr;+P3DYGPI zgAq80Ky`Ackz8rKKTnLpBq?QZQeKqZe%mi45%y@s2PTZ4wyW|ymtkNVP=ozLeM$)B z9|wC}4r$w;lzm2B-3@I>FvS7pPmh+xUe~hS!blzOF)*{xfS4mnCw8psiHft*dyOF!`V+ILaDd-!c=v5j-b-rgbZ)Vp6EF(YJ37Jryw);KLkXz6wjO|5>17#kXxUe?b_l7rvv6?yZ!gzeq)` z?-c260r$HnUf@TCp9Zf2Fixl1P=0fVGGfVyZJV2fQmkVB%#3VE(YKFvdLWe5ZTbWE z>yAJmzI1L@h{~CyvtUpX%4R7d)Bd?i&m6sQ)Lyz#2SJ03XT##01?v$N<;>!34_L!_ zMI?vka(LyZ=GPpz0)J>BhPCEE6!|_sI~*3qJAv!00=mvY(o`AkykI1Ae7;_hkGFBE zVS2*n`Y-LC$r8kA6KD4P{;|<+{Im4opHB_COKOdbdYUOCW=oYqIKv4aPsxz{>QTa` z%=US+KiLDANRZ_>ilYqgj$qr9X7eOqIkzIXQ~69gOgz}&_g}x9s_Le(p~nk6GZD`n z$Ei(0VJPD7Tu@DojOY$Hkv|^kgkj^+FJudIqdM+8l3Nm6J5Vl;_rdb}NI4Rqbma)x z&Rk6K0@g47Zu#FBzG~JPPQ$ES8dZI0IzV(8#DX(G9xKMebOf482Q^Wx;$Fo#W&@Cy z;Yt=SMQDM5n5aR4v*iP2G0nYxr1-!{k9yaPgc=>>x`|t))-1t7e+rtiyDejwQj$Y= zJR}Vpbqd00Bb@D-THpC#R_OA=iZ$o;i9$^sGbC9-vF9 z_R$6QJSdX8bt!Ml7Y`|to71P&TY2i|$Iw2f7Xz+CC|tm@Uhb-9I_S{kjVn30&tq0G z%W{An!$tMnJS%yr0nbJ^_m>%UzKZaKfaHRPw96f!%{oROVnKnuggh74_%w3b~kiaM^P>4j?3lKTEl#tD zq~BE8#R+bJ+WF|D=|!=X2Yx#~uZKQ^7rRGbq2D?C()YfCZe3ykr0)`}q~uY}4`FrI z<8+`knnO`EVs7fFv(MaJjqPQj#+&#hQ$Lp z-`&yU&gfS=yFVG@n1)nld;NJL#T4HzZP(pwNXnu4W9Pxqrh>#8WA0CbmJU8o0^YCh zu14$c*mj*tHyD&-I7OKkoVGOX3F}?cG9Vi2^X5}8Y*guxYda8@^1QSEP2bhcz8joLK6|1-Cq0Oq+x0gf43MB1QZ%N;gdxT=w|$_>n4@K19#|D)Q2O zvpDbfU3+Uzq{FAQTStRQ7xWH+UrNXbNv)l&xmYKLxa7PrJbZfDL|3gBg>7)6ti&s; zHBl{Uoj>y|c;sVEQvJc&kCfU~D7x#7xx3H0k52rjfG;;yUH$RMdNfOx1r28TmOOouV_+|du4_k=;9=G&-u6+u-+7fzd6%RDOZY!D!lL7!)&;9N*qhnwsuUBw0AZ%I z{a&Q;WCzL|p~u%ASoCPPSO_AD!p;=Rk$?L=P2Z{WLAtM!kiO+P&hw9ZoD|ly?O{#P zJO%w(R*_HZB!Zb02Z(Ls-a$;x{MuL+dGaP%Kh(|iJER#D!I2~lUDSEq2c|EPaIp?w z3q|a2#ad2kVFJNPJ}_CyoHkCZnva81%3$F$G=%tUGS@?sLQXH<4O3X71@seZ3D~_w zx7ghn%eyHdv`V26+>0pPua~P4>F;DB3T%6~s@YE678O=vaVRZe*Sa{Up$TL)F4UYejW78HWg?vN;6?Pa1SNVLnuq+4&)eOkNehCpxV8s5vq7<{77+ZE29meGoDa4ugYVB zgCF-!5th81JO(#|=*lB=ZRHcpp-Gp?l_gFy<}K4c^kEmvV>)X?3bnl9avwc=CH#2v}CWfOA4UWaQO0{R&@_t zzLV(ZmOw;qzj=t$#;CaqHo~}FqG<-Bgd#N|3ruI*G7(s9m9~nO?)}G1=Qc+T7j~*C zCnl@Y_+vHL-)(FSfiqo6?h1s`>voo)I$H=tJSeTH7MSHBYHKjo^Y=lBQ#ztE-zJp_ zn!scT1#VRSbo8g=l7UD;QxS-3_*IMZMnr~&oF`3k5rxXZ4s>uGgsOXZd}7#>6@FO(bPV5uteS}Pmk%eUwcs( zPpDB~Ls}c<8(HyCgw%z5u7g-q>+2OL`x{+b(Vq_5j;_x%u@YBHWa6{1tT0_dK3~P> z!)QD6ATLN4>QjJo)!cP*gR|55?qs|70W*|H@Kbpc@WSBrusL=+;!W0gJnS)*7c@ot zql=Q@_0k>T@${WYM1T1>)<*~z&w0%AMlsqEO^YO`MvedKDOR2e@{fdzM`z;UB$`?v zXv^n73V3$~__TBAa|A>lQdx!D)z@(}zw34@c}9@IMEcdm2Aj-3?Z3DBUhjw9F7|uu z7tfX7zD!WbSlLiRA45f{A*&i|Ei%XD&<;4{L=<;kpUw(>1!5>)(C@aGgLNtxO) z#Z5ft6B?wZLaGVZG{%G5Y4FFYh1NU_AVgnIQ3XtMGe~OdnuX8=B{%#6cb*`?9ee)vQ3ph-q$D<~!vw`2Wml6{5zvX8SXC2#Lj%K-j8*fGsmlb5X!tdaw^`ZIgJue9bJ6dxL?J&j1chP#T&s>V)^vA(P`4PT_m|X8(@ngU6nxTc{W{(dfn4YM?@&S@rElw!?;Os-6 zOJ-#t3e^2+FNvPVVQC^Y*71vzt}i$tx2&ckdNveS%zcEMuOBA?kVBa+MNBy6HlYfo zG4p-YxZ;c>+tom7)8FDPQ-V9aa2|Rj=}V)Z<#q-u@HJcxqENGUe#FlrIQR|16tj2)BFJMYklB1T%VOAY8iYn4)VgRhZ zeizhh8%~*b_z|5#eMQcjZq@FMlXW-d*X?fq-H$PkvscDd99T4uUECFvyDji%O5j!8 zfJhxESog5@7|o0sYmx-6Q(4TOuYI^%cfPv)s8?N~iLcY005Y>-*|>1Ww|@SF(x|!> zM0fFxfy+*|W__d`&-q}3G}S$`Kq3fj0o795W!*6HXM55k80p%qcy+OFpjwAa>GmJ~ zHgs<_Gw1Ucl;Sn`b*9L!Kh<;>;wWV-KhB;Nyl9lMHjVa<_H%k-s81*%PwDMsr+H6Z zEWIxh2}DYM+i*WOfz7Bs5tT5Le@b(N-jKpr%>Cud$^zX_7l}Fczw|+%5JJ`rY{24c zZCG~nb|&fvz6rt6-;ibODK29i>=E`i?vK+OifF<{gA>7C9Jb6X;80XYyYfS2G?zlY_E|ZCLJ|MHk(kQ-1IOZnOt|ft(F(Fiqr7m?PTvJ62ona_tmuN!`Q-#T>af?i&}#oQ zEPKAJKP98fU6AgbC1qsl%l{7V7lIG>EW^mxnJj<8SFT@GQH%EGYfyiM6!v7k&ePdP z=;mt=5c@(ZSBu_VwXOLXYemP^E;eA~W)sD!A}beS^HeGO?F0Ll4QF1|Wiu z7p58qv3OS+j2CAijq(IjWvAZuCSAn}Z)zHR*3S0-#n_unN}t~nTT_nd0j!X9<>xC( z6I-!7*x&xP>z)_sje`^2`=@>4(W&hIt8%pd)M)PHoxpP(*O*Cq1b-RNW*WMx45b|b z*NiHQHQ$FMX8?|u{s)U@MjO(yb`Yi0{e0l<2<^J+)J#rhC#S$V$|+5^TWn za>o#k=HsHQ8A}_LiK(6!a|SZekc4FcsuZs%eJIUNX75MMCum!}dHFY^Y7bX$q;pvV zY4cQjJtm>^%$8_MG&7!A3Ix5E-5e*i_`B(5_$4w(e|Y3{ObjrLse1pMYb`ATT_@Fi z^o$ittm=l4d~;U8wU^LaDP`>vqUIs1+66)=H8ift`(^Ut&`wz}d&uStYpgo1Gd{%)9w2sU5fS_$ zZLa(oDU9o`ZbDY+9~0kdAuFxEhp5HUlWgo$qkz}l#L|K4>ScWFVQ@l+p_Up?W{0g| z@7U`A{=(1U?cILdW1G)B8XelizgYq8xqlYHUXBJsVIW7 zt^2LoNvE#kT%PrgJJ*X<739nAM4h3R#veo?s50Nr+#_$pni@@FcKl1qed<@BLl4Sn*n0z*)>s2^MAn*|SMFkG{B@jhIgLuy)!c z6ZTiVfX}G@bR(XCZmj9q4Lxv}K920k=bsmsOZ3AimGd&}c|oql88kj@BxyXNz#jV# z4+*Bk+kdgnv7aJw^b%S5K$M@H@j+zJ@Dh?nubd#NI3dCp1FvhHk&%7);d&0U;IUA* zgZ!i=F83^<4D7QwdZ|G?yJkp zpcx`?M(WhlYzI+m8}6O9@%$s}R8Hz^#4nfc{( zZL|BBvTq9KlLF&oBjI=YW9KeoOgf)*izf@klTu$>SXo8#f9vnj0Rnmn3_QRa)^is5 zu%8OQlGh42J)50lMRE5ImQ|b~5y-NvZL89<(oa`lY}}--fbTey_VrlUK(f#Fw~zNp zkrr{#hfkQMOF^=_Rt)$%g7y*r-}xRE!qw_W+ZcUbM@DuYHiclXD08I=M)Dz633p9T-JgB)AZ2xFDqp*|skkku&a-GqbCP&X zlT@Ga^7p8N_fD%alDjfp43VeVAY;fL$sKROcS4~%UOBYYzta>F3fdKdfhau+R9+u3Jj0w(v}1i zwWW5_7m$UX)-*jIx*=`gr zQJFBo^b|It3s;V^iGC(BO=|D8@*wfVFj&I+^_B^DnmQB66A7(!_OuvlZha)o3t#s7&X;MwilkvgBdyw z-zYgvDn;S727$W0fbb5B>@YK20H9KubvGL+1VT8_=(0Z#{~(UOg^fPQ8DhOmmSElp zw#L1!-PS6I>uBdPkKm$`w^=^natv!Xg}{$SdF>{^p|f!7V2Lp{C{+%e_rM<7IQZ=a z{}aREr_P>%1KO$#hUEEQDe^d(N2mEFX3UOCS{b79g-fPw8lYn$cs|{*e{(zjmF4ap z%ChPR->?f-wc|C*E4p3v-d_U;WN;~@Pn}T|e@=J#$VhYI%X2zKu)9{wAJM|z z>lddN+@Kd+g!7Wdrag2%9|C_j`HSDym0&)%pwqYFrAALKte<}+iFv*)HkEW#g86Mo z*pC>-`fry6ZnI(v6AMT4@^HuMS5dkpa~i&F_u4VJ#6EEyrHuD3zc4lWc$lx@N#O!T z<(H8d{Bgr1rM#;W>=qZ)p;>|e3#h}L{Pu| zz|TSMid4lnOfWBkHBG{NZCohW@>JLHa!v4ZJ@QqIzR2L3djVe;nHV}L|COCV`9cm* z=GNl*$$05w%0_@Kis^O>!D4TEUl;38H}-MfZ)&a$-chLj78@rLCeN%Xrmdb;0cLVw z_mx>^aq;NY#==L@8aMarKCsk7StXYFmn3{}@>I#cL zSXiUi@L#u`5!FUu(xB^NSv(s02gxh*E?myD(Cda4V>bC;?8(tYrj;FQlL8U{@#0Hp4^#Suc?0p871o(!E?TRRxdK1zKOW_z=}`rib7y<1u}v zqf*@=F%Bj0mb8qoz1>CnyTR1(Vv#Ax=4@kLel@%oqdsrdi};qSRy4_k@tiA3NNv5VO3 z3GTkkR7ld}-Zl-fwN%i52XTGcMWSz0J|)WLxAA!2^QS73GNyo!QI{6T>>=j?jg84jfD>G?v}>g zt(V!|`evr;{RwZ~x^?b3&)K7GM`P+Z?CT2iHpT<5|8(ao0@QeO;B8%cEMyXVW8gDsN!UG#!xQ5D-=y9wCLc844J9oklEpTCShVgDL(A$9+PIPJ!uE4UK6 zRu$xZ>2b)P%;7$Txe{UzJz9ZbpM zqp8|o&HWl#p!)%aTELhiKp`iaxQQHa&0}5xS@(Jl3reh?&_;9(cSVw;@wl&!o3Mc$ zljoF{EK8=Ga4r&EaHO!>3wKGtHkD*Rv9v{8Rattpp$J=pn|Sl3CEq^RsO({OzGpQ1 zAjl3EU!0q|r;?7S#eTra2K*FXue0lAdVxI@NU`g>cHQ|E~v(-cWPbUB|z6weTDQMc>%`*HNpZSolxU|;B{5@T_(CfmwF6R#{mP(?i0 zE!R;DNPstJvWNTHQpQZYmj_VO56Sr)6cA$2P|(?I<^MH5`(%{bcl^nugiItF#&?Uu zY<}D$^1!|u^Bj~D6PfjqLa15+F|IJ%2+aTWfGFKEKhSe(z>+V2m|jIB_1+-B62W}2 z`2i=`6Z2|ur&tYuViHQwH(Ej{VTs=LYoB9-k8cve^E0M5R^J*&fb&W(2_Q?Xcr|yW zr!OE*3SD7kS%D(_#Q$Z6Nrdy@@;N^c;7M4%5#ICZYgX`ffx96>v3GO2bl_qT8sP0& zPHM{AYBE395quV@0t(cHbYmkdz;N%kivo39m1gcLIs=^JThc%Js8T#uti-wzDyiaSrbtDzxJdCEM+Huwwoh?0RyRfgX+`l$DpTBwzCNJ6CoOHAI_ z|IBa8uUWry%QLZPdqd2sI|RN(t)KK9d2$0|by!bXq|p+9a!aIEKC1IW>Vb!GHMCco z_q42k`oFCQi#KrA7$z22;w1tA*8OckelG#YSG5Hh>j2H*T*Afg_%1nsfH^f&Pl5T*>Uk7udW?~ zI2hR0@z?8NRw%TqqXg&i^Foo^K(K7rfflE5wq2b}FkOg&ftSZ1nu7VG^8JTXA{9a5 ztl4#&`~DMl6Qk7-JfZXyj6cw6W-<}j?~ziK=zs*ps?iQPGBNa&t}>29RuGey^}Lk_ zLng3~Sex)DQvP+jMvDKg4vj0`x%4UaiJC?oyF~JW_4edolH{HtO~N2uDvOm*0bqtV zfblW1&V!A$dDqa5Kop;h^qX`bmhpvX+z%M+K^Ad9-1MYqjvT;(H!^c?kxnTM-n)f5 zrdRLmpn>L#GsMAYL7tC}XxKLxiY_i&%tYHWI6*_LL!{%?F zL-$hIU+cPcU)E;(ZOO{pYw-WxfKs0*c0cn7R}fxnuf;GnQ~lYjZsPi3)1}4wXUQly z7OC3yW;3J)FBR2e)%DxLX1?>7%TyAw*IX#K*lNoH#_5Ur6(W#oUWjo?qla)KRIJ&R zSd8=|#n9geBE}oOkZ%z|ke14;J$?z|ooCo#f<5>TLl0Kpj`?Ri5aaCZw^7V6V+r*| zCrtS33nC8k-@%E!)oG$%&}TEe$A+FG0cMGiE@_yRgA~LQEA$uoH^tot3kGjex7IDz zi-)`zDt4fW`?+-q3kqhyd&tl&zD9ndHr7+?Td)*Gxe;B?0gP_7q|NE?)1$@sS~`h< zmpCfW6mTnORb0i++CQKibT%pa zPA!jd%k%k#SG;?~tt2ME6|~JLYJJAuKj2H|kYrfy>XR&k4gSfsu!{Ix6$%LlGCFPq zjuO@&P>aULQn9+>9d6D<6Vz=VTs5>Jy|UoLK*Ciyr$3uF?3rB4>a6%ceNA6B6MHOY5;W$-5Ae{88@B;6Kg+Hzl@&rOXC2 zHAU|SPZBER+i_rOyU+~l#U)&wOWmWl6GgK-!zB8(Dtq?kxI35P__9oL8t2f{?*K)F z`(Huu#;hQ|BOjx5k;>fH^#KgSh1~eGyWeFP?D?Z!OpsdyZ=!goo=lUFPn@j|f-G1G zB=Hi@*r9XCTYcFycbD}x%G+O_;1kJUCdFPqEL89>Y+ULAGvq%u zMXi@7mMoJH8FFalFuKGVU-_b zl%QMu%{gYR!#}PZKg0>ib8E#sf||{@4i>!jK0z7?AhRggZ9Lj(Hg_gRc!AMSYng^m zT5wBy1+lUi`q2nGlW&%ii*W{FR%2Dyfh`J;71g4@dJ8`;O{<(8iu(^dS4G|+=J;Bn z0ZFG0I&l1J2h}waeA&fORBi@r2vxg3TjCz(htV5x(=|BReaEeIEB|))W#8M=CFA8~ z^SbfsTI4>GR7l-e;CuaG47^fUxt)q^91;dxrk6NbRG$fn z%uR*RoUxXbRd&A2KQ#F{HnLM|OWdIi+i?_9D2$wtiw_gb{3BZ(KsA6{qx0`mLsR~M zs9PLqPCfM+a+xT$)XV1abGw^lRC-t+#kLn~h2Jwg+?Z-fOcABb6ua6h7VJ^I&WzL5 z-S{cJzxxAuEpgPMXquF$>2R``jbHc>dkjXG*20HKk%Q_pthgCgwJ_$gr4Vghz= zwR852K&`D`VwVv&1sop;sxd2g4O}`bbZPqK2b;)&rBbT z4fg5XV$op`WS1G2HBU2Rlofww^JFZp{*DUwl&WQ?b*@s5^DQ85y*M4Slk2E2?(dtTMsTzO0YCp_I?9!gCgnuliCUTJ{ z775{BW&NrzPmcwyWm-o(D)9c=1eiN?9`1RXu1(uLvu|7Li$>7R4xNw-^oE<}|KzoN;JOG(vjW2oS2|jw`r=;|uyq(Su6< z^wl=G&cQeT(yVk86G_0dvfZf8?W_!?!y+1TK8SwQ@~fNS=%j7~g`J_~UDy1XFs$$4 z5(54l%1u4Ckt6NzLh+h|pKtqZ5l4Qka1w&JHWuT($+-+?w(&Q$jiRJkC6%>&Z9!umEzkZ6rYPH$0F~j7wcMgI+_)4_+A8u>z znD^rPR4ca~xHdhm5dNLT!y4}Vyw9|ir`y_&!1cx0IbUdvfZi3bl3l)nE0QHBFl0A^ zo`>XR&8GExF!9RErv))97Y^xzE*3t`SeA>jWKzJ2CsPLcF7dY#P}Tap!E2Zh+u>nB z>>mV=(a0mfpJ|!YBQmxHg&;VPJx8MaWTcR|0#Vga(C#99#7_} zdvL|bqCoui=&OVkf6N*>g&`8Z!Y|)=eWND2L^lAb;dB*QUOJMa-<{0=LFI`la(+<# zbkVsR_EC8L>sSsrKf2^=n!om!?EROu>^VkR5rEyg1wmssOZkuPDS(Hb)+d`y(U+V3adeST6!c7Mg90aK5~aot-*`oRd9x)*Z;MI`!Xk+Lr&3eg8y19v7jh zfd+4b(0$63z^!xW^B(;M^fJtS;lsT3A<9SX@5-r8PNde!6)FiVb^}|_EzkF_wf;X? zOGRE)-nbgn-IphOM-d=Zqf9V1xZaI}xTBBVs6E@f*8oFmNXny7ibRpjb*Il#j`ps}@oOEQeZ9dQ2 zfQ{$O>$yfa*~!4JCVdljkRky+BPg6>L8)QGH z_=?w-J#FQ;Zc_m2p$pfjAswBB9)|_-Yt9T9QSvh;vGe&;tvTinlMJ^*EWSp)e@#$mR~`Dk(oJ>`SfrpEp2s?kNaZosAoEOi(6){@oM z3Ah&W10xv3qm1>-HdCm@YA$qv5?2Cs)p?e-D?kf4?n6maYESPuYe`sU%;LkqII;L7qu_k3ZuJJ%n*^e??+Guuwf8wf? zd+)94ytS0MNG+uxpnfvnZaOiIu(WPVTO7Bxi=a)&;3;607VN8jk&_mvMX^9;-qIywC2c{|yqD^!6S#x-a+=qYS!V6L;n%bCB-8rg!OIu*nf62Eir0^{H=K`Ja2 zjj4e*lf_OxRa$hAq>lk97zs=J$4#dEkv}>&%EJ_>?Fhu*#!PnfaGOY8b)j<0Ag$2e z4t+%!hTGCD#)l+s^?p}mrvK+Su2WC&gJJAXIOl2a4)H~uEiA4uG=S>QzEpB}Xh~0c zR|xe`V9n(ioaTN=NF!EvMUT4xx`A2l@?HgsK!m)sMYToTLaMWvpIUCCfu;CCr09-F zv`3rBhi~T^q4=?CyNuu$%BPPQDsowMMPP3-1*bGFMJ5=!wQLK@lk$5JsB2*BODgEb zape4U9pw5Fa6Hbpm;Xo)6=}_PlvkzXcqyd%DMVsgyOP6~``VqXq!CjFkM;Vf9(YBW z*g2CAjR|ZwE6_gLLM;iFQQUINvW9Juhzr}-;_A_@o8G!p7mq1DX$~6JLXXm8hp!53 zWrhBJk_+Ssrv2mD;V7}1UZH}e`oRv`BTzockD<;Sk3+G1z$(w5Ar$}TG71RA9-B2= zf)Vjrvsv7~Gw)N)Yl^}0!mMX*ACL_@iH7~guh;y5w43{&s|)p)`Fv`H#=q5;`U^wG z7sxs|UG)KLWwBr2CK6dP=KOl;ov9veyQqAI)*z^jQ2!6LY_>qh9|L@#(}3`x{Y^RS z?2oAdUM2*2%NU`?^2pxP1pc+r*Jtkf|I6(Wm}qpquj8)Ea_NZi8`Z z$s~H$a@J|X=^~_D3ON+a4I6l&w9roc6EP z9m)XmaVI<$uQcwuEVjt~ybKnHh)FytB;p5v*H18!1CuiET?P*|t_LPds6mAJ1-Cpv z!J74*W>R-w(8Hf*?|d#hhlB5HhqiFqdfYpJY5l)K-QJudIVKRBBlN^DNApZ6nG-l^ zW>#{4!~CdqKS8I*zFo}ye|N6{%uSpnW74;DT?5$o=hthk6D+p~eXy9});UX5p1=C| zti+UNWM6z1g`ZS8S{ud%pvc+$xP_VmkltP8-l1vebU75-I@EX`a7S8rubhZ{Cmm_X;R~TFE10mO&M24FI7d0g>F26tft0tc{ zAS(29C~+P`F=mNwxhssam0Z9d%14gAqa8lb;kY?96 zf%6>80KNfdgw+^256*G_OlNR#&WP_^kKzPQp^699&%Hqn<1}~Vu=L~nUzI~ucAGYY z-aMeQsUn2zR$0tlb=&y3Z`H-**%b1xEf#h$$Vub}!!YakN~ZesTC1M4^rv@)8FWu8G!XxuM6VIT3=O@9l*4Q4TaHf5L%S0~u z+j_cPCG0&RLwX%KVJZp@7yi<}-gdOpr|_ek60DzYaN0fOXg&DR0rXmwbqm%e00JcV($7aK&gHsGmo6zhjNU zCaB4@%qR$r@*%(3j#M;_5Q`~*So}8GFg!(Tl!k8*z2$Ypg ze#DO0B{JKi^q+l%VoaA1fw*8G!iY?-jGPDj9S>j|xPdC%P!pR-^@7(OYCyI8-XVfN zNcJNc1@(}BV_Vr$ilymcV3dv4G@Um0ao1~iEA$j&-Mu@pd$!|W3o#yUg?^oU7n9bv z9ayQ1AcBYCJDUE?8WV}BWp#u@>z zFKScHi=%C>cmJzjW}RKI^TdnkvOLkFxLR_N`SO$@)`BAce73lB*|xnfLZS1(4MVLL zS!Dv?2<0hD;i^dUU9KQQhsWVAQbF}08vLO z^^2tv0VdGja-5~(Uw}~Udek3qT5k6KU8^3C-W$Zx^W1N#9DGmHZoimb5G3Cr2(ru% zurvd##=UG^-tYHai5hf6b==Gu42bU!vP4!N9008A^2*z0DBy0&{BM2q|EVB=1bo!<=@eA&HYqeAxmvFfksTG^M z?3hZB)O%VGL7xT6D)42c1q^(@Mt69z1T(QBd)s-@FF;nLABuc`B6g4pF-;`5UntTA z#0VBDOidnf2PG!q;#eSDX0k_LnSmCDBj@MQoMjlsUQF;yHyoyu z?@{S8UO1<))t3xH6O~)Tp(_7NpWtsR_93hK)7g2nbq>lD1YV8TeXV^rkZl)mi)2H4 ztN_=I{snEqqp}NkcKPYKUFjG1oP&ilfvq^9(a6q zxqM=Dx$(ZB650^w9ziGk^=9)ju4d3EFT7tZtE8H6&duQ7v z2-6L>+V3!ln}}l7O?Y@nM))vUnq)h{j(tj>@f_-%_WEZ6OG^L<#p5T)E@#Re)b~a$aR~^yfYgMA)0l|rLamwtXnKlvUYT&m5ix+GDXH73@>_^{PO^+5fvLEPe>&3FQ<1Xk;wMsh3SJ@EA_TOJkyLPv}I4V2j> zg!U~GEQ3*RX8tIDu{R_1AX0!FO7Q^SmYRi;{q8)}xKg!@X%bg%tAftzywU?%A}}5E zqzt=}cE>N2l_?yA@Gnd&msH<>v>VDIbxi5s@?h{#2=U^0-4&FN@|+(t`a5WJAeM|L z(KI|bk5jmoQpeXn#8Uk%zOVP?-dAhc4%{N8EmDyINwV9)VDIn98X+(g$==zPuI~~Z zH$JXcv^g$rOZY4QS{U5G0ob&{OycZXe#qy3-Pr`!s8`tHw{Ux`OZSFV<0H(l^Xiho zo=9~H!$?H$E9-7|(xo02KggCm5Q8*Xx6t zVs-pXLTD;FW7~8LZ9F{P>#v(JtPIAAqxGhj9+nQVRoz_OAnhoqdKnIx^{o_X`N3lU ze${<6|G2v{EBlqD?LlEyrB+lQp4 zuhh-Jt1N)8hFN;IRj?LD zHYQM7!)%fbpXpV9EO!>iw|f9d@c&Nr%&4ACPSL%@HsLA+%|8YG&ul{Y3~eNlid)|O z+n34fy!9XFFK1H6pt%XwrRy9)->EwXA+lEJ3-65gE(k%IG}}s$bP@Ts1X0C)AY;EF zW9vtr0mh`~DIYxlimh~U60KtX2M48`8JN867K>3sMf;u%Ok7`cJEm8HEEK-o#HTOF zrtVt_B4LLGW5%3WUz)7j{;D!b#i(Y;<0&cButS923qNo+#b$XcybX@JW<{naR0A-q znw-_G-SHU6wnPQj_m*t(a|$*n(6>dSlk}n&oT^qiaX)im9344n{~-0xyCUCd-uk6e zl83#f9n!NZsjEGz=(2K|nPTkf&v^;BN^dk9CU%}TL(rUYs0>*t@Q5L(hPSzvKW(SH zk!_dp#5zaE0byahaM%+lg+e%GBRq-EKuT-!O+Y(UP7^v!TjZx0IVO!Jt^<-m+_ z!UCzmx(x6ZWNzp&3fn`Y>MQ%i(uUF-7d(aaEyec@O=ncuEw!I<*|52x!L!;w{^lg!Wst1W@eL zIM$K$lNMRLn|}28>;J?3fu$Aow9~fd+~tZZx-v>*Pc)oKB$D=#YXT2rv#ofB`J8i% z-1Z+Qpbx`453sIwFKsxpkQBmx*f3i-5P4l(>{49t>*qTkE$U+}?HO01kw)J@40 znI+<2Rxx$8p8`*2H+GrmB&nGk3alsY5fopr=Q~>QQP4-IfcU}J8(wEvV#|9h1!LHc{f|Vj^tG5`HvXvQ?;}Cbd$_xfp)Ole>#s5*=bVSCsud&0wF zun6;;%QV#%gcn*~{}+3AYx)$-glUj|eQ0ns0C%fO!pR#lAvhA{&(s^Ff531+cQ8zaVHEvO&s<}4IMEzvF!YpltNJ(i*iv9JWa5fW zYk_5${(vJS*y?v!6)FRQ&1#mOTwA(uc_!q-AKCBHr!`f|rsoR-*K!X|9#KS|vfm#< zhw?tTmtH-Nk*Nyognaj_NIK>Nw$%{5eC5r?H9F#SgfO$}>;9tq2%%+<>HB@2Ib?20 zFV*&(vjCd&H;6&HjmAzkD=`194=)~%h?389X-_{;1AS0KFc z8~VR@y}b?aFu|vz;hfvwxmb~L$No~)Ts^=1Du>+Or=8xH4fo^}QUXpx-e~UMvv_^}0m4~Jh4OwL#F5+k3im^} zAKxu(YQCa0VYYO6RnwzEZ&9s5$fcdI#0y1eI)7NCCY|n@!igl$hC+*P_^xxguN>Uj zH(}4bXEZy5GmvS?c@Ff-;j->gZ&y)KR{J#3#D3OvbX~fnU4J$B^AXu#CV`zQ>^>;C zRCz#ULcXtbJEJk84XA}EvWnrLOupKX&yNORhP9pk*(^3$zTY(JH@~7hLH~Efz4FU^ zD}=IUD2gxjX_Au|M7pVndwIHuDg$$mVp>TAE4Lx3&Hoh#DUrWuDrqT$Aoi)Rla=`lDnS!a z=^F$g?mmXDq|N)sU?h|87P`OvMgA#F^ufj+HJG9575;<%h?7n??r zpHwcpZLK`4nps#zDv%DIQQx;XX|i(rZZ~^vFg1Mf9pkH3I)?im9bA8G-P=^-J!mg@ zEY)FW^=~t=9HY zbgb_i8cmlA_w%GSujvko1TH9_aCXhZ00@$wzV{uIeIMOz@`e@9K~M0Uh=>dE<>s*a zCWDeyjh7&2Kz5^jzc%xwj1`~ZDO7P87-6x`V@BLZEy)HC+5NTXnp~P?UzqAD1Lz<# z-BI=;7wRGhWOM!uOMgDMZ$caza&m;N$mWM5@kAmWmWKp_LKgwrO?AzYrirb&2}Fu< zppS%Thk+s!_(I3`2#~{1Bz+2VloxCYi0qLBoR|wC(stFwS*z>43&+8VXv4HH9tf8v zb_@K{tLOfAyHLJ$KLZ8eg;4P-V%qM&ljlow@lvklWSnyF%8s+H0$0sk`a4Jf&O`^? z3y6cKi^-iZ9|$3!0!N~^xXu7~ZIvj75z*DqhE7t;5~>!ClZ1O+Vxp z`^N5!h#pjw0b(|J7uVa zJZ)-@nC@p<+hf4T6g>C3YFf1z4R6-`;*jSfSJf){Y}d30f&q?eX-=dz?NT5kVX|=i z320O@$il*3;xxKRf_h~MHLx@xWaDSL(P`UmUdgI$qv=GBogN40ap|K2$# zv@&osCa%wm&t+ie+jHMd0aRxZ=V}yrFM1#8=&2@fWMUu3K zD zjlvkao?6{8Dpr0eL5_4twVD{LKkH;>?PF z$apUKJ;KmTZ7)82t25vzWNq$0;b?ENdjPXhVxdmQQ&GB^iCG736X9G79QCcu*qU+D^wHi=vAjVC8v@zh1_ZkJx%^%2zvxM?BKGSBNFv+zJ0PomNV4;hDb z=5Eum2e+<$oJEkIZXLhk?#KobFg!AS$B&q{K|#|@A>>pd?UBczi~kU}SrTHQYsz$W zP%LvL@(K@C@HSXE+kHI-y_}EaKY`yIuW-*NJ+D3V1&$BhGK1358&*J2wzsYGbkJ4$ zTO77kfWea~^n#KSkX}e=Mjtq}%?NLm;!5N{&H?A2rs&y35>vb2n9Zb~n`QadiZSbnI9NCr}xlC%F^~7$Jtm47f^NG8yv@4G)bfj*E-(rw#?Sn zASc|%>XB0L%5!VkZMl(|(+Nj{jdL_($E=+7U}?NZN%6wg-dtmQb%5h}(l0HVAXrJ& z&CTAG=PMH3!pTox;)%mQLfF9Wt@KXB${p(bf^7ynex*MMPs><}=JZl&g>=DD1aY=> zoFjf|PXKz{)I=*NDVP;rs!q2t;dyP2T=laei24~v-TTMA#ck;(R8BAOjyA>pNEQzRIrx@_yz zG!c_UkjG`~YejoVy^%m-q|T?zCo3n5`gXy11tA}}RQ|mg8t}ao!;Ew0kL`*!(Ia*f zrVl?0qj}rn#HuPjTM2gMwf7v$7lU4Qvv08sUV(8QW=EX^r($M*J9bnzPmk(yLKZZN zVCA~!UIeG5DT0|F<#+y+ zexvY;aNu4uW%_;^9c5lVLjIDy)0KqxX`k)YQMcyjUX2(=-fzx^cUxmbY^_W!m!0WE zPH3h|#vLa0l2g{p4cv6FmW*j}_l{s^GWfj8{oNWPmd)W#Owi{^2l(HVBEB@uL99LD zc0^)ANs*^k(1P0@tgeU6XXmqXuaKN3O2G-X76+Hg@6E@1=OT}H(wA2Yp`NZBYRQlw zDzHKlkP)%gcDT8}JZ*}=EqqVmcl68$^IG{mCWC{DJ=}qaxzm20M;pyJSr(XYkjt?c zk;Jw)(WEme)YIiHjHsCyhJ39FY*{sXA@(hO)AS6He3v^$smRVY#HABn+8tntA-ty*Ip`S+vfA6(_ z~!>VX_Rn}5>t{$0>!wW-e$xij6Tjq8KUD1 z$VLHq_+*QS+P;P3du-FYBN#~&^R1ryO*3fR>j<<0ohYiyd{ZTu!EiQm;4E3lW2g%C z5^9*WVs$8zjwOzL!}vb}$lzor#*WW#2M38gz~LM~;nB@LqBX`GZJ!}}zh?v+KbT0C&@*22*{saij@4Ee$ebsdXek&CD6!=2<7|6|` z(e+LS%KYx7sz*ufT{y^CzbdRa`8kfhRKd!0c>oTvORzziy9|E^@xu?we(f)Um&qt( z5VApC*2C&`LjHuC5R|%;M!;;lL0~?hxMcPb=bq`Ph9aV8H2kG?+3{`Psysyc1_mh7 z!w4^y3QIYZtUNZ>Y12F;8Eu@D{)fD%;+bHtS~N6jp$&ERBl$3D7xVtqfH<&&FeUU^ z4fp{6Rm1+$VK6Di^+L$r#8faz5@oX@BUrqH+A-31FJ~^2GP`PK9yky$s)U%t9rD+T z$zw9vKf+Wp6;YHr(DpS!J2w;RdjAsc^{vvUXSES>(s}lcz_jUKLiKRK-&mPlBbMui8&bYvm#ky&VqcYC1 zI3DG}Aybp(4H;w)TJ*5AWJGZT5nez&<5*M)ew+^kh9xUT{ z^B6gA2tuZpb@z3P;71Lh3ao*HC~|IQsYbp2;c+WKrGL@EnJP#}Z9R+!IWv~5UagO8@%4+Y8<(e4MXYS*$QPOGXwf$~ zaKni;-sX7N)rUSOMfJ?`W`oHtrVp~A+2sPAE6w+={I^la_iYVXcjHZ{Lfe}ey~IlY z;=TH+Y!;XssVhP_fIOrI)8@-cC1!b5+WCKZa^$EzRmF8bexh68=Hd1})1n8PMS|A2ChawL*Kw}=T}lQ9yHf%ey{0!gpSab+;-4K3@GKK88I?&$JUS> z)Eab2aI@}#1AULe0x&(WH*?=EMXoLPF`Yw$TY<_@mu+&AYT*I~!2Z|7?GW?kVj_SR)UA3pQ7Gi$1xC;1KIYhfRraW!PUk zJQigYZ-D1WXrF1MZ%U6)YsYr3_Z7Lw*Q{*xQk&pGG=mGz*9dX}B`i;P@2598we z7RLF>ATpzYn;!4nWjpKa3XO`?+O*HVSHAa?q3Qc3HoIf4wEhFm_e4kWiE@xhem5q} z*&+a+Av3lmUF)RJJlTRdWRMs^cgT61taqO@q`r~prR7vZ(YN>D&E;W&4zcV|+ z0nHGp>Eij!-5r7K>E1wnAR8gxFC~uzMpbM2qohlUs{8t?-mg~O58z8@;e3Axv)4?8 z1Up2@=N(_oACjRqOoA!Q784(zgdryQ2T(rG6OfL+GU@%Pk`5G%8?(!A<_9!x=`4F; zd8-L~4!)cib#%`~4%qO$mDvXy1RA~#oCoStZ2Aex=gUBIC`Wqgh87uiL*i8K&xRen zU+MR%BhN<+pWi_ADw8Vv8M*kfIgTg=TPdaDpufCfoC)0EOFM2)*|El|Mzq+iwSjcjJ`9+ks)3&Z>K=&m4V^ zL5!G=#;>H5Z_ihD{+vgQ%Z;d{ehKygWw+Vx27Og*yApo z^W3lJ32RZr^5!o$A_4w=mI-LsncPMAPTs{J%c-)o=zt~Lct94p2y^itUDc6y9Cl6t zcDr+9d@_DSxEA;h#J%;e!S(l^ZkPjZ-P0h}Y;R*|X4-(U5cGPCm^@?MZ6dUOZe8zZ^d-S2&qY8zmKNMZS%nXHo8 z_NY2_OXczQBJqijA^8VlrO1?!jyvFRNIui+VgA$Ve*Sa$TOhU3vtdfp`r|YBZ8A{Y z;zw>mV@`fze9GqvWP2&h2g(Ve9RZKLrUKNXgtG}=la-Pm5xHdgxX%ihC<;vArc4*M zV`Bj#45O1LPX3Wb9AnE=tdr{c&_Q+^369}wFV0o8A2NYwodoxk$L4S(WewB!?`M;Gh@13&c8 z4IKm{2MTSa!Y1c-kDEp&Ivv5**!mrPIch$HI+YdWI$PL%sHl;^o=QL++~db@VDW-P z1u*h!ueM!Qnb{wpkY%sINv8Q5lMFkDbW_t>3Q@Hzh{IJBkkn0@2KTb>A+6kshD@C) zl~quC)970yGuw7#O{K$XBR8Fe;iswUJMsu-peJ%@n0!QX=v>K$C!B$658vHs#BS3b z>G?lYonwDpVYjbivuR_qF&eY6ZM(6P6^)kunxH}Vqi+(Vl#eWeP>?TjmW<&Q?wPF|CfNnw@ z-RZfA{f6*2#%M(c6#25=m@Jtvc^3@Ps+9uPB|@7WTa15L5D`OKPIIQk#@w53&x8L- zp_^8rXmJIuex_Z7tVEEYo1}nLECt zizM%=kwt^oikr^}(M^S7*YaLegE3`Cl)4c)s(;54k9FOIi+_1{!9PM@T4x zCSU54$}xWKl#S!IMFMMvcd!hR)irrOc{M(1PylQ*`j!@q)p-)1#jxfFTe%c4LraqJ zz8*5@#jRd{33=#xr@e2S%0yLZF@Xq=q-hF&EBg_h)XUp(6(EJ)bEFnd)IEs4-B{BC zS1WOdh$VQ~cwi=jX1hFD@g>UDOlLh*?nxE5M+M80F4+_~47g7MQm;;15Is}1y^KJP z!aeZEgN9p`H;%4y+RT_hIN#eZC=f|!$ zh0%q({2_Er0zHOx>2aFCkmgu@=2+Bv*HT#>JdK}aCPD2+->QJID;Y?@52~%6mSVSq z2l7LMHFXC!T9C)o^aC)edmGfQeH>m#JjMoWojbq!yy2p~SxGS01*dI}PolhkwVCwb zMSfmw#`#`^?o1Dvh1|E%($ z@9fBsz724Q9E(^;H?QvBc&{DkklF7&Wxwmz{VisH@;$VR66{%Q=Y9=7Lw~EX5AO0` zBMCSjlj*mLb1~J8cYDp{>q_|iz28>Mn(}@c6C~a=cvn>}|5g&sW4*KBz%3)gm#9`@ zGA?N8_E>q?)9OZDOuO*U>qjxU6!sDE!+X%+UODxyr7%z$O*yP}cd{f!AM=W6kJOoTNxE~mNH#!oCC+K}zO zKuFZ~XKhOCg#2FMB`mdRbZ_24YqW(Zke${nIms=vhBl3t6AeOrKcrC5#xYV{j-P~U zG+o5riV8S#+>yOtOQP1zY~=JYSE90nYJ=fX;_{=-%n!_-mrWgq^jMK63a-DpKBPhS zSd5$Lj-#GfB6g>7D%M{TXtv=vrWhQjLjw?`vVdaLlw1yfHz0kOoRRU-ZK*cSFa;_` z|JiN%MvOIR&U~sHR8b8>1V8ph0+>MU@`15^=GH~lPvCQ`m^`)C6xbfmEKXn;IH}w^ zdKhsu3oxd#kIBWT&gc~~(@{F_Xa-~T3^;wYC@|+OY6g~=n-c~a&`Z9^uSwHs@T=Xl z?V0{e_BaZ>#*bkviJ+%@x{y#0X?TUARzJ{?e+u1i9zfHlBF2oDB{ywi-4cd{PSz3& z>1%9)csVNmM)Fd#A`7R6LulwgUM??jMR|d5-!ppNQck-X={J2Ds~mf)0b+U;`P1+c z6>w=c<+fJt{5sju9K0A~$E05uJBDk=#KiRu)bDD-Lyr7Bn(+eg&|iMPI#JzS$hemP zy>o&ul?1H}sc_mDV(%%Fxd>Pek*b;#D*-$}f8->)xLN&H>*h@Sjkp6#ygKa0|CG0CXK;pAQxyn`&E zZBBh-n4BD+xGARCl)=fIU5W#pRCNAoKJnRxU{0{%-#u(gv=z4%$LA4upP06aV5Uv) zXGw|f*H6wr1*L#+t>7=$%ZgRX^~#5+!+!ns{77+vbW@5Ww+%*AZ`smAL1L;On&}Q8 zEzHcA>~}|guiKB+niANl=`pq^@gr^LlzC>d_mG+c9-+~m)*q`O?@oofDg6W--|gsZ z$*FLYw%CJIT1G=HAo)`v&WwQ3(L4Y{Hwh*1XXoRywN zb_|LRF^AhydI>Kf>w^xeD-h}AO`9{WzK0_gC@Pf`<&_7LU~$?OHks-T&n1#N1|;1p zPjaH!b~})auj(YoC<}0M&EhVOm?l6QAmchT!Q0g-a*~nXGSt$TMjdAZ|Fz)Ho`g}O zx_WIRs!j*58CzJb zN3@H-bi88vO#EF#dQFJuo%Zb_H>qG*O)DyQLA$fGr{}_Foe?} zt#I6T%34KsxuV{YY;}{ecUyVNW2Nw#_#sQHiIHx7EE!ox3?1WxXG$ zIllv+2uc;xkHnzTy+$XDi_I7n;obPB5Eip9z365h`LnU2&P+vm?Ho9Z6GuUS{S?l$ z?S}_DoBES>ZvMnh*d#A2c}{YxDLT}3Js)e=@ro7+UV&X`n>5GVh$kpKzzzjxaos{^ z=LHTXbw-(f7IU-IMSV#)`z>{uH<*J*8CqVOrLiHh88GKGvzOlv{*ev^ZgArEjM-vY zm?#kYBX$W-ry*@?w#oLS@g!9mqsrKgqf*NVidjVn|A8%8;EYM@6L}#v```;Ej5L zsPbU(Cd_Gv7#+ySAJCEtgQXgnY!B!U()^od=^qjL=STxivrrZJ$+bJKHg=C{7#0Q- z1LLZ_SvDDN^WUbpF1~ph7_&LP)*L7A6)0^WBlL|l_($w&0df=1o|QII3_gerp1}vb z7A`nTOXGkXnK$Dn`hjJhP$0!s)vvAv>?gfw;4+SEgce_kBF_u8>tRQ73Etz23BP(7 z^N^^s;5AvYFT4Uy_jf;VJ&BNgukZ~OHYdbp!&Jjd8|+5c+loV6@gdF4^ep;nst33R z7s~Z3M#%wrsJnrm!x`nrXD;0V+_{J?z4Rh?_ffX{TDQu%;dy)>Sf-fmn|XsMnY-AF zcSt4pxi8xaGWk;>6dC)5s1U}@fu2f#T|XeOYqB-WYh~BB_rAYj2l3Q2luttvUq&S*-z6C*w$54?&*OZNWFnfF9f zCB87fycIMNRnjN@d#~vG@M=pqO4A-KT$>n@bDrr7hsWc_x&JB_;XBIup8?oR+{(LM z_AdgdHj#v>;03e0kcjWIr>z(Nvl1rKzYKZoZGGXhIdG+A@k&g|nY={Lx`aPxY5&BT zW9zHjqj_EpH;7dK;*}joUOUR;=j=^#I8o^SAj9p<{5i1{=}962ak9;du1pTI30X z)P*#++i1d~#3o)(t1s8N#X32>i-#MrJuzv<9U`$$+J%sdI1Ji2Yw*`J{$*g7`iOF_ zjyoWoQr_)tuu`fH4yOuTGH1@C|KFzQgjAkF!(&Y>7D?H(hewW0QYX74+^#wzG5^!7 z|3Oaj=5+#C{@D;52R=uD16yP@5`8ingsv_2yI$Sj6!$&{ltOeQK2P6Ygi}TRTWj3} z<94bJ`ev9WJ>*i815!fSY<|@i!S_drmB@2*NdH4yk@+x8TX^q?>&^x>Kq0B@R`pY? zG*gFq0ED#{(pbL9SYw#b#kr>L12YG6J~^Qf0GumSJgJ$+jc~c?p|*bix*u&ktO;8c zSAxftRD^@L^o?Aa8|e|O(VUI?2EpKbfj!u+0xV`AngB@Q#~ayFthbvn@ArT?GDbQ_4%cV<7yjw*@bIS*i zzy#_GdXg5y)`=7^+8cx3TOah35!iMn2Is~DSYK#uL7#dK%R=D?2KQhcSbqqMnXk0@ zD3%bK-J$a$Y-1!0tI>^)mu1qkIp(^q-Z;o!j+sAx@CL;#OB?}v>CsD*5>?_Arx)jl zU|dF+@ES{w;qO@UPhlw6yWq`_BkEJPVu0NIBrCT8;{^KfffF6ngT^J6zcDD$= z%GvUTJw0?O+6yKXH$iT@lXNmZ+6Pypk_Q-KEV+1M+|XfEu3Djf#;;0^th1_(3oy;E zSS&T5sF(PL6DW(j>d!wu6G`uro%_6uw$y=VBN6>7cS3`M%whp#(XXS%$Sa>gwGf;y zyl7U!iQQqt0^{d0WCw1@I!1rK)Yde%3Uzu?t_~A8tb5a7w`o04&9j+Nm$~9FvC&|C zWz?fKqs^%QmIWQwk4EN@P@aKy(>|3F&|)jL!69@g>1+RzB(T*HR24-=F732eZ{qqFLCeCvw1%J!+XV9Ghc*%6X$Ilka1#0zlTgl@;fC=ppY^H z_l1Jw)D8Z>2bDN-DM8helb1+K#2x+y0gvAid=@W1Z_^5YUKBnYOv?7GQ!Fv{aP-ZU zchL$hj&8C#tu{^Gudjz$k0bxWUEMR=%P6<8CNE~wV7_l2)_-LMPavvYT&RC)a)loT zjoshmB!o~V5p9FKyz+cgE-N$7vTYzZ_;TCdk+z=Rs!k+Yc6HEK)WQf75UB3%YT6{{*hdJOq zj;wn?X;V_*TkMCFD`v<82L}=9gJIdGU4g!gA?**?4Q^geP3tpKHJXErUPw4() z`L4`icj*!kIRk+@>+Y-m%qwa=wT^y6sT;cTpn!euQ?#FPhHnFg@&0$K8joEJ<8n6KFiNV%t+3=1sL|Z!QsQJoo5S4oyS>Wzb!FO#%-uFyKuVU?9-kE z3!r@uuI7WnreB{Slv86qO+;IeBdTi*5$z=WYcTfbN|_Ti4B7czX>LAp*+5m~&+LeZ zJjvN#OQe~7zg0J?22~UV+atL%^5Cfc#{1EDUUs~M; z3ddv~2#0oE+{gDerln`P2xRX5!dm1Yy0y*x`fC0r1hrhhBY1iuDE^xFnT-aZbTMKh zq&6`Zeq9Jj+jn{viqc;pTLkJL%wFOlEqcq}e$ysw-RXQ+UnY`XY^5DwnMpA1usRl( z(9+7+xFo+EIcXPphO4b3R9VAehIj;@aX@#Zjy2LBF+wNES0;^Tx@Y~V)4fodv1YzD z2odx61F0=*fVZxQ)V_^iXUMM1%T~iVT{4?^dyn1Rdm*@mEUC|2Z<@CM{b}6@CbIt3 z{B&b0*W1q`R2I1ifD5L+i+VB)(jj(Zu!~?|>>bXW{c?@m zJRVGA@b$bF-Q1$3;eAklutgXDaVLmtCtEYF5=zF89@dWm=O6$|BKMmlSyO2BhQAf^ zzugk^$QqKz_62+2s8DAR%;QcaaX>>ZM>@#%+|;51vg?4Y*Gl0N$j4-H-syDrSl=&j zAnbzBJKtLqOTciV_6MAgHoep!2YvP!CHqV*cKZh^&N|0UZc%exu)_54^t=5K!JXT< zsi*mwSOfozxAcnFeb4D9oI`W(6M7%k)X(-AtR^l0EI?gvRGx=PkM^T}vVwj$B~Mxi zRsf38_r>_Ijb?BwKc7(2=dKXJJJBP94Xh6;h?_Ybl2emL!wa7qeZR0}RM6}z@IE{h zj-;ZD@c7Z&%dqq2L=(hxB&jHbk>)(FH$sZvI$^HOM71l^g(G0}T7a-*G`OcVX-TQ3f$>WPju~k|7 z17-5nx75$n^b*K#Sg^sY0}uWsIibAKc9NAd={E0u!?Q=}^P@6x!@cZf=C$0WwyZh& z-670^Q*!vo&QXl#Z$t;JWLOa~Jel0k&&5#|DY>v{6jPXB-K~Z43;W$hXKWQ!eV%~G z?QgDeKqpGIr+%f?1mDelh{u^jqJ5*8W9^(OIU_^s^WN9CnSr>Bl`~a(1FC% ze~$Lh)dI2%nScCUB-0)<)3nQ2~&X%!=&cVCc6Ji00$YEC7g)xu@Ug(Yz1gJc`5)AWh2P1u zq__j0kC4xul;8FzUbO2W+F_*Yi5Xl*(foFlA2XX~xi|My=u}H`5QQ%f*FOd8%G^Eb zLYy<^L zgPd?dt6^yPX49^Iu^nu0Gk9xUY&atc2m8jY-kFc<8v=xYbLopEAIkMaFL+D?*oIZQ z!FM+hfYl?Ffv1Y=hq2niorF%{E>LUS3_1?IKWNSOws~pg^4cr5xqB(`uq2mEY z&GC%CzQI5mkcsF$c(!?hxFoo?LfSU~%sF;wjsb$_x#dEp%cpk-hrTvuYmQy#)nmH} z#eNSq7*g1WR;by7$4G}9F?0Za22b+7EinJZGdtbCT>GgQtr_GM+<4;lI%9f3GSnhv ztteowH?lT7(t`VF`0)t1$x1A7*MrFZI~3-h4{zx3SQ0|LU_m{gRxK ziGE(3{l7QZnu8awn-4Dz1XmyMF(2v7$*h}kHd6zhZ>`atb4(X5BcpB|(k(QYKOgvV z822s4c_wNChTM9{V>#x#s@mUl_r}8=M!AGOV(g)3b7l~CePq#AWV5->uzJSMu^#GxPnvr<-3~>xFeN(aJyP-|(C_zfw>1 z(*T0Bm~4$cf5|<~jGJZ>Q5umyGS`1pwL%Sd2x+**ol7`)^(}i!S7St-?;B9M<+I_( z3JS#OhyUo7c;_apV)#Ymv=(En;t_oB(P8P1OVy8JBM?pNu28^2mO(>cJLU4cjJeWN zgqZ(u$shP^60u#$`-{e2RCi1zXLW9mYO6cvifewM7$+R>iv5DSBwv;7m7x|L~&UrBMoz9p5YzHnyGrpm%vjeBxW?~pLW;q8|f9dWu7|E(@_*RKBr zo_Nm>N0EYjiotB?*Q~n7;}U;IT=tKq4Z)lBr1Z6fO0W`@QF1PcH}R{gh2PG5RcKxL zX}%%{1p*^3Wddss&HdHC7eL^*VSxSu(~dIx*Q;9 zJ@1QCK^Qj!cZ2tm0~o}9k-iw*B9p3D$wry5FkEQtHu3I+8#~s@*>~Jxgk!k&K0=9k zH2~Emxqf~6+Ait}yF9F5(H#jT0a&JNaM7bOb3aF#DVuz#>oE4dbCBh)>xj8{ZMcv*2i%8Q~!_FVwqx5Yl^a9G@UsG$4qC zz^Dwuxdj-pR^H- zuEUDL+MJCV=d&0UbPk@`7qI@1=3WrKd&b{MgpwR~KmztQCDAjk45NsaEZn|+Cn;dy z^{>zY!MO7R@UD_)PQ(RMet86$&-C}|g(7-D4)rITV9mfM|AFAD!j%T^%waDV_}&brNnP3Ad|3tWrHf zj&nEs`17`OdO5oJ)U)`ho1Y}`y-r2iwzqket@07~+iR#Asq(+0zuDfsL^f7RWD(e# z=t$Yyurb8D@_pWa+*^mg9IEoWp}!ffQxrYeetP3L;?`k1BqQ9mc^*6R+g!~a6bW=% zb7p|TeUg7~+UFT9pKJn?Fre?fYx=kG8we#hZ1nE&g==rbZ9x6YvyhR-aG2RiIuhy% z&f0a=eN?N1AFxZ3v6`$F;p~@sCWKN+Z93jQrh2{!CP`A9%o#$@@iTN(WM}?F4R{MM zW-;UQKi3}r!aNxNCwm}`JFm(ceS?WIA0}5Tk)hCSvE!rzV_xP)G~$cVYm|X}KPN#& zBN4C3aE7g6)iVg#$4(@XT(r?s&10nh5x=&-X-AYeg8Z64zDYXJm%S8o3UifMDf#oi z8E`+-v#bQS=ME3Nr(Z5cZpDLTQC2b6Zf_6ocfXTzG}WM|^LI_;KiZOB8}f{vV-&fv z5iaOYKyp^ofq&Urjb==AYoy3uR?PQ#vOMR=Pp&J^=)p<2tn?a4ZxHbi{G}tmeM0Jy zclo_rz^_-DNp6Au@Qg(TfQS&O2NUu9buvC%~7d z<=BV@CwG5Lv9;(ujJhmcviV&R6WZ zZfHh7MtAm0u9%jba#frE9GF71YZn%kj~fL{D<}SNobmQx7l5z2=|xR6p#C`QoOs(L ztk$`5;geou+de|W18+;l>`mv#*n^1&HYIm2uM=nz!CDVaBw`vo3Y4$?z?lAe&mINF z+U8Ub1{BBUw-U%g&V!Z4zp_|m1_g#0bfqaY@P@$&^oo+HLpWc{!au=p<=z>z85z8A zEAz3XAsbw(n+p5aYbFD^aB-{5k80ea+lreBhfgJ&1Q<^6tS4_8Eo&g=p-jZxo5c2p;p3H0TM?5wBfAM-8j!d?2Z&06x z14Q5eghrQWz-LrK+S&R7J%=3$3QHo%!`?q>L%dZY7>!ulZ*^A*FHM;9{^XYwUvXky97KP+*kuB$28dPe4J4 ztt+N$BmZQ9w+|;#Z5o=f5%3q3=JZCjiQ>5g`9$Nn#~f~O>)P2pfe0Vzn=NhqJ5Y}E z%^6y(AF4*yiMQPp*!%?*($Z!y92J8YQxJJlp=>x^C4ONSsn`g1UFU!kG+;)**gHIC2a(n;D^CJjbZDLq z>xce-1CLG{41Sv3*0;;))}2U26gY?ZZxxK{6^Wo>tP+4$ ze=cN?j9Xsx!yXE2HPClTllIepa{a*5IF34W9XeO#H7sgR%Nf*hAv8~q8;5(DBMD8A zcUP)b?y#7g@R!Ru3)!jJUsjne={qbYT(|SVp}U(J5(+b<=}b6F=<{Zww2}9QOwbrr zNzk@ah&{PgGn^=jG0)N4dQU?iL_^9x8yjGG9u+(X*&W;>^}}wCRQ^<8C?!yNiVJ~t zkslO>>mR9@8`*bIJ~=V?AReX}2mID_p(0D22R{49i|gDVF|*~giemA> zU)$aR@SU?d>s)2=RVJc}d5HqGpICOgfyHYBB~&DMlDO}L{_(UcsUrVaAx2PPF}@y1 z=`EsDG;7ox_-rBv#B1&i6|Uht=QuZgz?sr$$v8{XApG^0&F8bJ4Ggq;2>7CadloSP z5L4PyIbTn*#V00yY?w9t6$rE=y?H&xJ1#9qE-2q+_$ ze30i=uJG2wa})69qLw?l-G!w%*r9QQhj-XoQ@7ezdz1qD7nCw9p{r>JA+INjEBe z6N4OFs8x2(5oAJADZ;skGcCln?^H==8zuzTVk zLOzbb)AI??J%6XeRnFug0=CXUxSXvQzMb{-IKt6Td?WK!CLIM39?-e<^D4b(v&Mz- zZf(gEzu9HE<^V(e3Y$9$Ale8d8lMK7H=eRF$C(s3NGbfBXc(Z}eL8d5aI?v!GHt=> z@hw|-C`;_fg>KZ5D+q9BpmfyBIVW_*zTfY~UdtGL>D`7B`t;82G#7J|Zk|AQMs9Yz zbC5Fdjlw|w=tK*Y;`CU|VTe@Vji;0!!Pt>k|4ZVgqwgzuwwo~tiW_-Mc{R_7jO9_O zMRx4GpJ}_<`Vf7-DE6P-1d4yfw6(~PVDPl^eL)bV6Y_Y2_O$Y}S`&z}C~f=ZzG-u@ zGI-$&(Xf#Ts=IxrzQ9PC+g;_pdSA&0u7y_iHa-b-&{VDY%V#goV!jbaj)gq&n>!3K z%~MaxaU2gjbzxVM`j^T_V#!qxSrZy7M0(QUl~wlpp78z6P_q=HDf}uf=09I+o&rGm}j_`Q;8K0Pby#MkaaHSNZ~EPHZq&8r}&3j1fCJ5 zqQAkxJFELME3WD;dT_O-CmIeDP~blGhibSM6~L@OJVfzgb>!iL-La~Od`9?UVSW*# zud}rc%^tM>zYQDqJ2r9? zCY389wrFy%|1qj1Tf4Zhp{Jz6$w?B!Iko%B+GpNfS3f!RTx57PDd5tg?t{ZD;xXx8NjgWnDIkd4z@2sN31=Ph`(s`m{u*ZVSNhNeuw)XB zgPquHDe67F7(jd6PiM3*x%EYFWS7!2(eXiNnj_g*rQDBy#m9H8&2bRE~o)$CC-9w%7@)pE?(?Y&Q3Ta0|og2 z^|Yj(g9xzMHn13`t`0DXcKWU8;uU(Lwi2hKiV@#osap=j%en7XLB@|#u-1w=fa}yu zSO!XKCuaqf!+=!rmpMGTevS{|kVkZ7B8M0?gbd$4E05b;kk1_*oJiMO;t#D;e$Q5w2FNY)kh3#dV7+Q+uEM-&QjL& z)7%ri99%$WVTVqjO3n-mbI<%9Srbo(O89H48wsN^pW;dcs8{;qKluA5JhGj{zEeol zo*BMz;qh_?>=!RU0Hq~tBvCp)JD%?vRP(CKS$AkOsuG;}D$jjr=r+PLJ2vGq&kB&w zla-TBRh~+-7v3b_QAlrmT6r)2R`Im@#*aJ;QMSa z*^>$rMoQ2@)148Y#?w4W0?j0GOn#24jq%}i>x}Ypy5w$U)AOQ5PRylHJF1MmUHjvf zEGB;#!)^fGpuU*}EoqMRvHn0?u09$*4VYj$X*dIYGcI8*fyC$GyxeQ3`nDV_TU_^n z69xYwqjjrj@I*EHTY7{lSzgACsyw&q33$DjY!P3m+=IQg0SxfVMc?1PVKHJ(Z6#rl zWV{^R_`;kRUxI%CyJ!0{Tz<9iq!nsrw14Zaft0c;?NMKC7S9IlLlvQT*&O`0P&Ue( zdtMQ6KGdlu;F%SGFu#q+Ifdf#=v(SKK;@Ja1kCCx5|fR?7VIVQDze_}2_Ep8;FUd4 zq3hXPaHGoNhNN-kPElCe`!8Mlf1cSHKxkBQ7l@?bXi3kjS5MD_#%oX7&CEmb6TTPw zS(qo47FoN=WAT#~vvxh}OHWAaH_mjD*!S=DEIrHWSR(ED$tChu6WMGJ?=I+c1Rf0u z9uxUycjmep>WQW#e8@;_c36=Hk_zRa!Nuxq?U>InSY8RHnXiXhMY=9pz zCzXH(ogTcOO~a}ehAbD51T!4lL4o=S$815@*<@@I-=oWf7T?z4CstmwZC?^J9y6<& zHfdttnhq^8R`_H{mjoZE7o3()8vi0rf%0%^-+G2$K5tHDolH4;>h6}1r+TGvl75?pNoI%&pdflBSCkkig`B(oeH!E5|8ZghLNvmq{M#4OrcSiB3F zye{|fTH#Yz+?X;FOXA*v-F6&`3sA=PMTeHZzYdT61o-K8;wuF%^qAJ_tBbbtoow)PdP2 zRx;M6W&LUS2s!brmVrb=snoMOWbPC{@NvlXrv}AeSqDnQjw|~QFiw4kvs6uvzsnNK zrv}|D28cHsE;uF%tIVX0lAFm6UdOX?5_?1g@YX&Apj&zjUG&$rc9*oON@VM@VylxMNCK42c%MGAO6R^i4~a;%!bP$pCL8~`%1 zGWc!l+tRQFY6QOUMQh}*4?-?}7rHG#TFx|}59+-5I_O(%uF66J5ks6hKooC7sI&@A zXyb#{hTO2#Z1NYgUO!87`zOVqdxTR7X;D%|Fe%xv)rL8Wwn+%|o%Bl3_z65)K0!A< zwpgZ9*FWq`o=&LF>;uv;Qr@Z}*6rtFIK}{pM*Ys)9i-h{MgY{{^uWd_6=?Cb?tpn< zy(V`QGgH67Rp{8_e!W6mRvFHj?Fl`Q%b^&+=KT|V_U4ezXOWUfVnAibM)MZ&_1x3Q zevJfWjLL)-q0qMz63;}K3*qF?Jk(Hc5fwN%$GO;{drQ(lvN~}P719~p5&u5t2855m zRH_1)Zh=774SjLX=*5QBP!rjelF5Q<0nyzGA6VFU|eS%{sqw8VG&aIt?*KkF_*p$z1 zw`$$L@Fqh#>o1j4qDOScE&Eo&R#q%KEnn7kH35l_l1Xz2$mVe)Hse0c=k82-#6e$y zDjVJQi#>EZ<*i7_6W43Ug2~rG_!HT8ktewtX_qy%`+w@t)56O|>~~Eu!~*Zzu~!c3 z{wZc$dw(e98z8Lnw2U(F^Bl>ZH2@u$z+6?ni?1WH726!gQioej2=Ksf?{b1^tFyp> zJjtT1?^>di*TM$|BmG5F!xKRjpxu(Wgnq2(qrul^cb|&7j|{>=f0=6al~H?fvlH>2n$UlL z9e;Q)0aEx73Uu9_iLV^Pof%gmPtNGsOpZ#cN|;qvJJ{i%WEYRTUWTI7;epB1sZ9e5 zL=uA75n@(OJ4y^YVyw)Hud|aBdAw;ePFX16<(Q#CQVl)6EB=ZYGvvh#w#Sng6K?qq zz0b&t|6a52eMCGxeUcH)0Aj~#I8}p5e8*mXn_0Rj`9uqDH2z~A3$g;RVbzqwFoMv(2bo9-eb!#RM0$6s1^1TDh#_>A2p+Eti?CvH zew-n}A(8M7F!XV+@H;6glSb0_D;bR#PxxDF@5+AKXMdNumqz?A7=P40-!b<2H~5jQ zxs!sscWzgG379S=Iz-$?5YRtX+U4!72apuqHX7l})b)-c(6RiMR!#(3+Mei@8Ja?5 zU@rT-Tob{?FS$Jypexw)G0`_a)UJ2hWU7o52{g2gQ&pWB-kAv9lM3ui zX&ls)PAdnP1EaoiQ=A~9VLo9z&D$X89CV z_!kx2Gc%pB7Bo^^2%z9>A>=In{!(3^CwI?w#PVG;l7#DzVIdIf5Q5%zriCsN)Vwbze={~ve@dHk-)T{jk*kh@V z5Y>Z{Z!m$~U9br|*2;vcr<7lOzeT``AcZ9?lC+b3&f^$1!FRgRG~!8>Ff5*qUf+dY zRu=!mU>J250;9&$H`Y!6L>4zDNY5U=*)rEwc!Yaz_XLjzro}i2BE3~P-QDu|$6%p} zrOS6COS4HG!Ja6pVSKfCBE2>6ze;X@-a23P^O4OikI_GfP?r^soWPpR6h9DepApL) zHBcdqov)?|af>R_>m#guqoBoe$jJ&hM$6R-Omtq^cNve~CiAlT{EGcs1u--6^PY(r zdHIonCyG~=0nrCB3!OefUD0}o{O-B6z_^jn+nI;84$D0K z?v8`T1$DV6j&oUNt(=BYQYWM+9bBq;gx7!@^$o4LoE2w;pxUvP zSMPd~pL7}7{(?K9e^|DjPz|{;7D=068yRnW3TfU~qBnMD0{1RwWD3@?OBH$K_Z970v&c9w5uY$m#h+=2)vN zs}=0lW>%z+g-V|S1?89oOVqc+@rsLy90s4D3?mgJt%re$k(EgLL-Bps%qv;(J#5OL z1vr2@oj`xMd;JmAUM7DbTWMv)OSe*p!$p&PyMkA-YK#h&m`8E?tj_M2wa{hZzRT-Fj-6k2LjlH}E&Fr#U0uy5$BnUKQ45@L)86y`Q_; zR1*trK4>#_$vljtG2&3yf?xs3SK^(hO@j(bmUEr9V_?Vx#1ND{A_5^=T(2c!9R*pZ zAvt)+ZT*!`VCy$EK8b>T5{g>4XZm{r(nsx|euY(j-i8UryBJ2JpTfTqaquP z6pW+schhDqZtu)8kT)Kkv1etbPQGKgWsdbvoC@?Wcy110Czf+d993;8*dJEjfzkb5 zxR>o6Gso2YE)l%bm-F%VQ7$?e=LLGAq=b@fFIg23f(Loz>qSJHIKxC;@@PERto*j8 zrjH-oXde2jTBRC7Z`pdIKj{a{%tlTm)pYN%OiiIbToQFfF03BDy*sg&2Ysvg=PK3= zArPxS;DCKzz#kEiRp$$eMd?wCNP z^;{Xy`bN>C!AIQnGeORqHE{-7DFjj49V!#$dzZT3$64_7#UWSDI$XR^92aprZSia= z@Lu1>;+=Fg>50U(wZW@yf$7(o4)t{O=9Z12s=8hK`<6h9cFqWBQjo##dftkML@5hS z7I`wt+nP6FQ?)ZCSTHkhl%-O+sqDDg$~dRs+`Lq1tQDN=<9SU=C-?02`Z{|H+MT%4 zRII{b)FH{qywx4j>Q;DZ@o-<*i+2@)(PmbmF^AP|f+fx^uKS+qeSn)TG|cXA)fehL zQW5m>V<~?b+{Y+rKUU+cpy#MXrSltHx@Fg8 z(<94xOPK`Cq9nZVJDbOjXaD`y|FO^HlIVGm6#=G z*1oH}(um&)$upEcLp`f9k5w&kZ^c{8J9hT<2CaGdjqoEj7;`&9$|dnz`$%Xh^vW-) z){H4v(G4SMEzViuA~qJ<4)hi0esbD@%xC=4qLuF-Jh1LW z!eXO524oFo3^I%t7qc+_=__y&$=NR}2YO8GS9jiY)ihL-yuWnh-LDEKlTF%cjF;3y z&7}G_C(5m4#w-tTROqS@&@={7tkZ(a zpcHK^o^ePucFiV6EgN$SjNGO!^J@YRX;iQM)xS;UMA0pu>iC4+-j|Pmuam znq{PI(-(X}Sl(TR0bCcx|36fn1yh_+v#oJL1b250?rtHt6D+s{cNyFhf)m_za3{E1 zaCaNrVHkYyx!kYLJ?Gr2{sV8lReN{uwR%0>1S#3Qfp(W1As7pc$m#Ywg#+J)nC>MI zC4=B6k0WQ)*+aInk4N3}W^^Km zh7PbQ;a6FSjy;@JX@FLwXLCb+qJd3Ueu7A_7>}m^pTP<-Bj%3Z{g7CCy?7`c_Dfm0; zoQH#lODz(V(8;eW?BljcKw+xM_@4333~NiDu&?5DFfpz)b4O6mn%+-AtC&Qbrd=nj z%0?po-Y6DUww0?`^S?5Q)iQ)*b~}ndPfy2SCDLwt?Om?NB86%FfCII z0srT@hJ6ip*4%?KY{hMy2Z|h{geCGWCJONvwHyZk0uH%I+=ya{&Yr9>EaN{B4ZYyp z!8hbYFR2qvyxY4n<@VN>76zZTz_mpj@7)a&M4jAhaV#sQn;}~rFD+|3GKcQH2vxh8 zL2Qu@Ee<0IUpvG6i#M3o{{QvyLB(K;%b!jSDMd1pRieUo!3`#*HaN4PD^>|)MIWv6 z+TKwq|3WaW`YPT5$rihCLbqh(t;cuGGbI6D`txK6s8*H8D68@Bc*k^qU z$ExNMK!3q)o)|lk5VnwA0@fhHM^}&Rry;INPi|t)x(HtH#Wbc|Tk_`CTlm=4SOyks zMKWOB-+#-r~~#tgaVEFC+g_*iJs4Hc^JXUv3lAYVq2uRaNRmFM5e zRu;|C2eO;3*oC5MAxx&jJvdz?m5H!#qruscj2Aya?s#=z%q^GTT`dSQa4bFXz@EP35ie3$^WW^4cWS2T+$?wx_7QO{n1+jV|NM`b$ z!?EgfV!LE;uyY0|3dFxuA9jEio-DtFhC0=LsKPIybk4ZO+I_upvU{lsBE42E`I~_= ze{DGgyY&@an%r36C|2j5u>gOD(qlDzPk_Btf8$1S`~WqA3aw1IOqFZ1XE{igbf$iC zpVg`8r7ygU%$`_C8~&WD>a7YKi$oSSsG3`&E^;3xb*wEUZ@Sf}Dp#h7AZybGcnpns zpXI?;x_(lA6H^d%Da0vA5c+~G#^OKzoO=a`5w156FBd{jncu}4K&q;ISL_?!+;igT zbbgd+>}K#>gN%AF4ymEL=cH$*ZKkz&4t8MBXJCm2wah*QMo`|Sq-Y{%v3gp@_P8W9 z55Q1DA=5wFRh%uLi*wh1OFgnt3XVWuO;(V;dsKn^J1-~X?}3OnB_kF*-Q*zAQ?JHB z<5=XAI5-#!B>5}CU)*-vsoP8UxgwUB0e!?CLP4} z7V2uDza+VZa^YL31ej&TQa*XE-&R14Qhl2xz0B{64r=YqrE^j~ZH1IfAU9yb37I@Z z{^Q*DwYSe)@Zvs*(xt95T+o!SZ$0e!WKHmJ)oB|`cR)sP_@wQuJFJk2(tVI*msnrT zo>e`08q<*H_8xdbbz%Fp(?O_cH$U5p@)K?FNA;?N`}RE=Pv^9f)3N_=w@t3KT*Wu& zkd4l-EQi3x4xPN)dZjg|eUuEDsar17O$>dY%i2HnYRUt&kgE6+kNEdJy6HDzKP&q> z-bAgkD%)n0<^DuBzecjpqx*v$<%jTDT!IX<)G6p2JWE}?(RLv-Z9NzqGi#6J5FGLT zAO^W+z9TUu0qz)Poj-=+vR#&c7CHYJnA`0JbgEg@2%7_~X|Xf-*{#5~nj1)qGu-jTTiBIg?oRr?o>yzFLPA@PKU0OZ}y)Bq5I^Lbld`c52?8y~7yCzasR zWqLuYPt{%hOx*evA)||+Qi5Bt1yg0d6iq~P%}GJ<`WMEuhZURhnsI{kBcsmbV$}z- z+nHDMyA6Bglsy5QC)V=G03Ub>^zejp_xz>#b_MP|IHX{sDSgw?cg_3!Zd2v9=yVdB zsT=;x+%$f5poxh-(Nc_DK+8}*!N=)JYWP%hV)$lYq>fnVm>9d~3X5NL_m}{SsSi*~ ztn&7DhMEz4T86jKRC2Zk(OS~$PqLk*FWGuPP~}rEd3_S5WVQMB{GDehY-{`>X=Z%d zm7eW4L^ zIvec(0q%cig>#~+>&#n>3I-l@X0!KudTvo6Lpq%9A1{|^1^e5L~S(=Wt@G3CBj z3t+`UGKaHnFiR3%SpAv+hqE4mdAMDt>Nu&Fl7q5e{R8t%XvO63cmY=7ukBqcGuP5# zUK`_0?c#nWB9?-pN6;-a|60`=?*^})Ak0cRbg=m+?`98DH~#N+RQaz7HDaz=f~JFa z#CfQW@5HUb1hUI8h`i`jjEto}HBSt!WxO7oD-Q)*&O99gf6NLuf;_&_+Ca38iO`pQ zlf0=F`cRM7T7_MPD2!lp>F-`2PE`+I{0IsO!d!_E5DJFj3eJSp7#KuB}I z>AbtYnZ0W$&N!floxp&1PqJUA-dLENdU^|R>upfN>qI}>s|kfI~G}AVaPYLZ*KH3^c;rhbbvOphp+=@PAx>gx+_3&zW{4g z7FJ;N_}adxgmHDlHM_F>S6x|b1C>R3<)A(VcXeSW zZiqfUbd1+pYR<{lKIP&yQ!hU>j++IEMK&6nUdUlay{sCDzeF5sHiz~MJ70wnwGZ)r z*}wncoglDX(XdBbvq|w25RIVk8Tw#7EChG&oKZ(viN_m4Cuc>B<`}2|g2;9we=`Q^ zVv5PftGMZ{mkZvQo9_R{EPAi zHl+tAx|(xAvwRLi_RtF(0ZSSopWzwi_~vCy*6Xbo@4KkksagDe<#!_}E~T6trVW2e zy1bMN95}xdEXj8haiB$r0u~rUcU8$rVCfwa-*G*}fPVM0--)aZgX@*=jLQ6@`?&JT zv=tx=h@ZGw-N(|TZdTrR(h#0MLd*pm6WqJaPAVp1>>6X)ET?nsCyi0ME5G=1{pzFT z6E3>z9JP%_Ezd=3afxf(5Py*eP?i6{l$0Lq1fYrNzVd?MQkb1L)@)Go5?o@llYW^K zzLQrx;~N~hgm)!Cr$571Kpq;yU3ISO>Zx~@A&l%)5L3_(Lxaj|muk-hk|)x)%8MDI z&mT)UUq304$!`8*O#h-&zyxo?@!*Jq`h`S{)#M)+zWLd{kBULq7{aFiQY%R7lm*jtnVe1=HNd5RpTvrfSNlNyT=)_RZbdLH6wF3L~C zzBZ?qe!2d^lf9_6Qzyy9(8V4#L6mc0fbzg@2RIpB^1az(Mri3x5jt zlS6o%TC>DO&Xmge!Y^6#J+XNxhGJ63Hdn>Qc{s!@Yor`fPXIQ^XHDwZLIKvaouCeUa@EOc#O5&YboKu;^4B{p1|( zj^Tb?Xy93gZ_814d~Hl2h{9gBbOnyJ;A3-UdbWi7qkP^e?+kvzM<$HxL*1 z8(bReegY$#4T*An;H%f9<`(7Szb^K=7 z?_Z)ebK7%wZ$EuiOpOSy!MH$bTXQ8+YVPITbC~B`0SJ6Na54@ETzuNT&fOMvoC{P1 zUDavL@(IFzXO<2HA7(e)B0?{~S@eet1{+|*l{IZoj%DmEEKIB1DTB?6;c$)dN z?>qJLkoaST3%R1b8@4BMW;Fs<>5cBf@h;S-Q$;y`c%e>^(BRoU$)&A)Vu8tJV%c4vz%m1EFgSJ(oQG^3T+vY4ERbkUBplLM zR+q>`@GBsD-;OW*kvZr)+2@l6G#m$s4x}=aYZ5Qv&M)57QSY^*9cyq{7Oe)R6 zGP-q7Se!*y$R7dsY&24jAf{bN%5Nv(mOh}aK4WAa!k1-TL|Bu{waUj&@~8&zF% z?$g*cMv=}zLSZ^pP_2Pbe)OTo3sqGKQ&f<9dtq8*&G z-}ch(H#S4Rh@}9Y(Ixngj;7%v!SuBDmL>HggPeC=njHES8{St;Xw;^mx=;M`4@!93 zsll;M$!GM=Rd)?*6v|$_c4tYr)O-obC`7ZXc;CcfqG#UE6$8snMk|e^$KIZ&Ttj`~ zy{8&fH~7aSv(I}&`sYn^Q*@Nrh6=myiyL>m7G=)__LIU~zVNTi&PFz@d~&r<%FkA4^64+1wC!_MaDM zuKK|u{NvhR2(cJPP(9mN#cyBIlHpdfBAAWabJ_;zDB}uSLBQIyYfgm=3?*k1@$!J8 zCpSNdG$JVsPi#v9XaAG4*!9?uU$}=F!!x zh5n#Nvau81@OFUM zF=XFwZ`W8gIvM$C-irT{Z$GPfcN^k?gARB=^4de7XRi5LblbB;~oFcekO89WJe z!b-6FJ2x6%p9IJjjkI}AmdHsec1N873~s#IU~$A+DRl4i0~vtJWXLSYhj^fan44IUE13liN2r)dFMUd)Tgf>SU@-5o8npD@F z`o!mj5Si~asZUJpm8VB(nxJprV}8DmD+K$TvVMs`d@re3U32sA5$B*zo9z0Z)#y7) z%LO?}%!&kIra$uUtD^W=dnlJlgf;x~8#q`mGw4YIkKmYhlWwZwWUg=}=LVz9jFbBn z7^zL05pkDRbi+c_Fkk0|=($WaPeKwyG%n%?yCbxCT26yMDD=dXBaRMVm~A9U>xtF7 z1h*bdDOgq|*ck47&6ew3bqLi+B?ctlV1JQz@L_Y#)Kqefx0(MVdl>eysl9XIo!Z$K zwGF{JpW3^mdE7-!!!6rK3=>gRVb)TLh1u$FF(ztDflGoiwWMXc!A9|Voz%xC=aN=* z!YOcH+cRqGeRJk7_K^EosnS=B@Ur00+Bc(R8=KiQ{TvvunR>N&0_iP|X|@gJ&?k1? z+8^5qR4)I%eyGL=yC%JqOcmioPd0NLQ+v3t(G{+OKi$SC(HD!%x*W?1PsQ~P7~djE ztiEf8%kS6s=)Y879TAFzE(C70R72{l|0$Czriu-V|3e3`P zQ(bx;J!Ll^&4{}(WF8M?6Ta--Rs{Lh zT4YXH?uzyncJ9(O33Jn{G!sdArTfS3TG6@X%66g(U&5ao+wVcH|1`!si+TXok^&T> zZ6db3bmc^B5?XSAk%hHn{!1=YB*F2G@ZAF8PhzwsWYY+xPd#iCqbD3~*OccAw7VfDW8z!sfIe>JF@S z48k_H+Z96c?|Df3F94-cBjqWwcRXQ}4)IfTul}@=&>mE+!~47AZA2q`X#O@I=IbR` zeD}J)5GV}OOV*ZE?zde^g$+^2x&$EEAAI44M#vS17{ci$_- z!dwcT^YJcws>DB#qqWw1_V%`2r(5{=E>#tVUpu7#QO@YilCUX3fBjP*x5Ses@_x=7 z`!cwXMUsr+ywyMXNLG2#yah)=JcV?NPKKk3)jQH zjUkpNkfB8xa|=7|C89RVQV{1cbG~)nd1N4vyzD&rP9U3BndK=L{wEWiu_y(pv&f&e zPsA{0wqa|H%A(|x^cdnSA`E0d|9gd3fyg*Bvfx7v2#y-5>sJ zm-fK_-5XZin4BqWLt)d|_Y09y`BDhMT2vHayK8+6u@~kgKV_L=XA4 zY4r9_q3Cms0oVYM$nIGwcEqIyd&XEV6ojw-z1%xxMKOWUE+Ws!e?Wq>bI}?m_bZ#R zypvP>cpN=lYAm=jsQEkPL%uFAwSTsef)6LbI3+qET&)+aEr_BHqU_5pU263~*?JLh zNZaJo3FFIsBIYT3da5)B9{Y`31?UVWIAP?Bhp2*&ggu%VQqJAqj0pMiU6Mka_|ETI zSXZeT1>!PQn~ASq^rOdexqE@r`~(x`ork^n3UZFW^PDBM7tub&2YikE%6V)FzqH1r zmNZE$TR?TxT40Rx{tvdjb#uW_9>RJCo9@H>lX_l)HlmJWjDG8HgihN6c5J0%gg?0d zZ5PQ{^C0)Ye`|`_f(tzbUJCY5l3*-Uc=8~)<5lE^B%LNpAqMahmt9-VOjQ9d9kn5O zkC&~dW(LabTcR;E4DvO!y)KOJf6-3GO&R_hZMo6R{rjvC>ebWO=$&LQa{Dbo(2=d& zg`st;LeO(K5j=o65s}zo+QcD!m*h3-j_1YkD|ZiICIh3y$L)>*15N_LrKxsH6cw`d z!vX5+=8+RONDoMPe0?6$OXQ)(E)$2>LF>0o#j*+VY1hycXcBVLlZ(*YgaEO21v&)R zo~L0e8<%WIj^mdDmtpL#5&V^MoASuk`XKR6K)?OT)M-1!mib^3;VSat_)R>6kcpju zZDO7kRtIo25m(i9wld`v^e7-DXX;E2;EyXg2h8)I@ zn;CO$r*{b1WxP!1EueiU7t_v8PRm3=@eSrje=pg{Dl@s#b5!f^xS|0Ysy^&@T8%ho zyw0YNQ87>RTegm7d-X=Df&Ah^Ac0|v+ZCvYFFMRp3~5fVL4-BC=wXeclU*!tQXCFO zN?JxFw+y$p2fg2}*k#tdvFw3gkI7Z8FeoeB0>>crPSoMU_12l&l;HdUZc|_;9gPY0 z$myQf5kcu`1JLi}I_KVN)^hlf{Ee$;Ffma5{lN>ho}$WcaqWXhrFoYlS;RcZ{{0GI z$?0|g{ow~8Wc`QW1t6?FcfxJm1$OS(L9+a2;`$Q*BRujs%20BLGn%BYFHBTzPTd#A z4LYfH%$=uzQ}7i%$9`3k4WE6n7Ge`V`y=qSuH#+5x&3&v-~aGn=8NSY0DZ(bteXye z-tXSMUW#Mlqn(h2Ye*R9aX0vW^$< zx(ZDr0StodqnBw(0?Go7Ry&uCc3xhZ?~lhY?(K!s$zZkrZZ=K^{=pgrtKa)hH_!Dx zs4od~kb{e|DOS#2X_ePzZ1iXzJ185zxANqT7E$!F8wZN92e?5E&&%TkQ|&2vMJSf{ zIce3#g%Ux-b}z5)qtR0~CC}03s?^(xc61Ej78Rd-9W~Ex3DSdKnbXSwhS6P6uFGu8>K6qIDe)N})GXxCrVUcxMfRfht5jKNjA>{?iyH|t^X{21!e`Fe5MjA3 z$=_T5s~A2AL*fjtPp81w%?2>meSOz9V`Kkr&p^ERgMb=PyEcq?otN-QAe*SzzP+6N zMo$}Ye({vq%LN39dA$w*oH0jVLpm1Mu$(kubrRY@lrH7^DRux#2K4gv>MY#U$f)SyRg*I9hB+ldwsY`R%Kg!H(cg3I}=4= z2_6vxf4)8^r6*y)_8wAwOD5B$FH0fzz)UjpU$ForwxTHq?xC!&G?y$f zviMu6egN~~0~MkjnHkKhX@jRg4hHYtYjb9WtfsB5^fe+$Qd8wwPV$ag&|4%1Dc^gI zxn)6Eq55wo`NufZK>pz`m)B0GJ)5UTkGpqjHj^$d;!kwOHU%!@HiAR&BF#*F)sEg_ z#VLXcqXvLJYk>zDPB@W#k2@?`EC8u&AAt5N6BVQO8n)0gW$dQg)Apxza*3v&28eO9ZqN=jx6;SJ2Ow9h}S7O^J3eSxVNW=)=wEWU3tKK9pad%^ecun>0 zZ@{OF!h6{0_1}rOOBJKN&Ofv`zdLiegC#G~yqcIH{5jQ$p9yRI*|ZWDoTrjhkkp%M zZns0L#ud$xK2dOz!iCx>-v8XTq*i!}sm+xwfM%v{?)LYy9}1hrndibDCSacD<1eYk zu$oFaPg-|IWbu0dxmc~GnaZ@pRbe@XVT*6@)D_+)$lo{iX>N&PB+ag4a40S(RuFt1 za$P+V?ym})j2AYx^eBU2)Vvp@Kq`z7%k{>D;Emo~hrZ+}j zBHZ5I^QJ0Pa8CTsxwT>}hx3+H%&Qg4^|pqH87OoTW2GWTU9#5DxBmN(vPyZSU2n7t zcq!|fl-65DY$292Wb3Ij$bwQPH}%9WZ9jI_1Oy^;?_QC1wC28AY}<|pfc1^>4lTh4 zx*kULZgiS3>ehIJPX3nN?cLJFI>zFVwxpe(1cPSCjjYDSycDeZ%dF&xXip1T%02mW z?^W2$kXaaUtsRibMFwWUUky3%tsRyHsFjD<%#E{9J{7?+rAfv$PMG-_V|oS6*yQvw z9Xgx@K{7`!6IBrxfq3jUT&3y{=;X~KXsA1b?dNIw8jJhiP!pwFy^e(TUJ&Z=-7{)M zB9eSVC%++Jf3m!Y@5QMS!THtiJ4}Wj$L2|hUtH(rTsM|pq$*Fi9Hy0B>1;`{3%Cdt z+RamC(x)Irn+-)UB^BoIPA+~mTr#t;1hEl(7D#!%+AK#;#a%Ay%?`$DK4g5p*{M8W znN4`8lE2y@VbLLkK8q$)iti{?gUSV*f>6+yfj5e_ToU@383MAOGkAw-8V|G3Kho_+ zlU?c~_%4cPV#@bKS_9O^xW^PqR8OJz5kgl^AsSKmCjDOTCf0-*E zolAngEcfz{r@){y2}{!1sTBCJ0Erbk!B_U6l1#8s1IhawiX=A#jX8*4ftE|Qa6(4y zRn_Xqy1CV{q{H5mEe`*v|ssr|eavX9Avo`@eK#Qc)iq+V5P%Ll}IH?Eq zb2_r_nqzx@cS0iD#DyW>7s2MRoB95@d(DLwLNm>F6Ki7UPr7~P8NdKiYR4Fu+2Er9 zyT5_R=2%UY0{i32ZlTuLQxhts2X#rHYQZYmWq>ToIJB0^msI{VbZxR&bYDSn(>6i^ z4dK4J_u799wcG!2d%ru|Q}b6=@GoI-Fu2Y=?XI(HXRNj_L=EgzQ3Zfy8Du7oP&8yW0;;R#*Z#$n@^*d*bg&-h>`JeCJJoRIQ&AqGm{?lM-%-ZM0C?t z7-eaCL>k9=LHJEm`)h)60=$~9?BCN?e}1tuj9np$h_i+(!MSZWif2D)<>gWQCskT2 zYDuXk&%d|dJO0jl0bj)qfcd$)TP4h44pOT^hcNn%NyhlZ*Wz0MIq;RKQ90d}{Gaik z>vvZB08J-L0o&ksR)WlF?r@!1{)<+*s+{iy4G*V+6YsG7vwQ$2^k7#l*4kQ;)(Jrh zLg#K~3xm)&PFT9%lQd-?B-|k?d9QA_{Fvar(1#vpD4v2sEDItn=DAHi(dB>n_JkMs zQ{4Z4sm`3-rdbbW>XmzqOy|Lko6nROj58T7^L6Kr`YAV{?c$F6_3D=0%MFHK^CtJ+ z3B7|DGo|||?6`nWy~ujf2=2IpNic+L`+Uz{{QP?M0*gRPOo8x<#P@+Q0g}Y^&9hEJMo;Wfzg+b5; zF}}QeC0oY`d5cLV%l^SpsQH4E*gxGWdX(vYN>}G5TBA+dI|;S%ZC}i7S;UNKZCX1@ zuB+WF7gYTu0=y9nR%wD%wm-4Z==&Eneh9L371(k$LbRUW^0IGiKW6d#j%OR^NZ+vF zu_=KFX!rSFqw8}@-^k42ynm&VWRYi;>hsy>%E$5%T&5*oSVdPZqBuj2z*akPdmK#^ z+>6-FgqD=_!WT>T)EejDcA zNCKR_yL1Mvr67-hK+9*ohv}AzPL_}4^T;}AVId|;?t`|=CyOWnna!|h^um1T;d9sABI>~#z zWU`A%MwzRaSY5=TxOIL@=!dhvIs0&o50HCScKl*cJ)cP(!fu$OYbrCW!Ur-FYR1m* zqNK;Epd0W^dC}l}B=_FB8q)>jaTEKmmp{YJ(!=Xd3_99@U5rmv8eWA3-)sp+3 z0IUd8xDbfYSkYuim~y0(28=hkFWkZ9VNR~3NDO%`WsF^TK~@_R08ItCcWPl?@$7Ly zqGE9%)$8SyEy>khkytK@tanPR-uuD@AtoveK}WGk=J6Z4#^g5@5y|SFiXnnc-lX85 zzqEqC?{c1^!|^3#Qypt59TT}Ny4%;h@4Z$CGSCmQru~w87+i#kU2_7n1^!J6>)ttb zgDe(YkgS)~h&j9xSoYMok9}$BA(Ppm!-k1eI1%C4A)&bDI#$(0^9Q9Xld*dXl6b;R zUQ5%xZ77!k*oH%P&9u7@7x8rG>kQZ#Fi&x_v;!sfE*jq0X^($VNQXu^2{Kbd{!+}| zROugCPQ^>04?Uq2YoBcx#_w8shQurR_ z%&{9a7vdsLJ4zpCw^4o8FZL~3`WRn`mgy}80Vu9^wfTk;0N5`vYG7!&Z1O7IyVwqgdGz3TjvY*a zC(jZ!*Y2ISSD@@L=ccFQu{dv@M#{(Q?8VO%R>l|=yI?~Y=q_S{Y9r;q{(R0_nNemz z06lBfl48i1V(O4!X}fb$ejwvf?2c3%uC{fjqYJN~C~^vD&n z>NW8qLjR4gpH@A7Z}hFq9Xk14iL*Fm1N(j|iUKu<>O}13H0)1poR9w2shOA#`abbC$o%DPh(ruP^AThr*3&ZYcJGoWB(!aSZ0YJnGgje*ZM^B`7 zFJ<2BYx`{`zotT+imHW2520=M)LN$@KTa|&`XP}oSIFt{AG3A~8)g=zwXKm_HPT?O zqH0p0PT{#bk6&B;b=rr=wFbjzfO zt#qUpDJWg;MfJVav;({!YZHpWZ1QSpjnISnj9iNA9|4y`EF~!Oht5dmkfBOKk)tX8 z$TK}wa)#TWi-C{cv&$C4L4Rfm`pv;SHnjib=u9?rJ}3Ru`h!0^o349esxgvbk`zyH z*@cvb&HcG~zXn(T0?(-qx5hL0lys9n6?{fWu12Fp*~gO_PqOVI_j|X-5X##PEu1!s z>VVvzYb8{qiTW5S^pLmUTl_iJIZqp_n6=Q9(oXv-)A5}9LiD`frcwJ_ko_xds~fR~ z^H+q$s>Z5|gCMb#9hYDm2YSmS4OzkmzQF9&>MTF)8-f)D;$Ofz?RHuTq^bASA@o55 zF_>(J%h9&e`d$PaGy%5n1k{rKQmIjY>#uhsiEXp21hQrOiCj8D&^^&eAU|a;xkV!Y z>jH_h8bf~~iF}S9A@at{(2u2>zH<*pOG`L2=$7ca5=?9MjC7H_p{@2TI~li~br|Rr z*3;YvB$C14cP%;c+Wl@G%&5c=1PtH?vmtZdVJ+T$-64iOAL3}!nS)SZ`7PxWwkdDdy`KLe7I7DwL zop$@L0O$|LaNiH6E3yvG#@3u{0&JQH+W8#WJK_01v?EAG492=ko%j8yvSv}a-#+;| z*LQbbYsI@D(b`wSOfSxSX^H-RqceN(IXiFf5A=pkdC}EOAzeU>Ui!UXR4HDC#lX25 zPT$o1sEW4ZEY26n`#27Y&aiMo@7oNl^XUv4CGE_l~$Nv}{piuN(Cg($fb zKsCXGoO6BQ)&uXuez&6i*wCj;>CwIZES^m{jBwR!DWj|oSSdwbLzGu(cYOMFgjC<; zyg+u-rtX%w(Au*Hd@1D*Q62y<*g=WAYV(ABPoMKdp%HqlLu`;Cf^LvLRQeXYfKDc) z>J^{;1J*DDPjkvuj#?@cehiOTc`UeM(Z{})@UlM^ckw&^5sc&HHLwej;dK=+ORT6T#Q?lNI1FwXY|-g6BsK`6Tb7|ZF6JtKXIkp*=HAW zGw^^-sI)o=MD#HjHFmiw=_hQs7me8X1TftLbSK*`#Eq{sQaEl7R`}#&xiNCD8oCFqc1z#7ZhG>H&R18|xFe ztEp%4o|(wrs#Sk$%$@Kev*A7Hoy>v)9EMRH#xHyRK^=|kpRb9aJ!lI0a*{ivhkPdP zUMK62sJMBJjil(_(%{CKXa&iKHsog>%6!VaCl-mWv2XUM3~4fKOO-GZIsM70{w}Ar zM(NwTW$%;gLXO`J{n2lB3`_UI5&H?ySpe4u26`@C)p`c(M~}zkx=hkN^8?OB5nczj zI2jkrrZJnIZUzt#sJ|sE{@l*M=s!w+qavb0+T=H6H!Y{`r!{m``WK>L&);QpZZ87C ziX(d!N_}MgMC^{;Z?d}^631z_lw8d7$O)2<`ONU?PRWdRMR`V!WA@yY3opfbV%Vql zhxBsV@~6)hPSfKtZ?i!_Ie|g*FYrpAQpgLUBIY@LjsAs;h}ta@B~kfbty$NPdt5lg zx=G>g6s%<6dblN6r7@PgNmERG=Cg~2(GciD0i;Yw<1+fF`qQ*(M2&FjT{3mMeej%{ zc(oJ#+G}1={|*@1dD30bHPw10ODd_j9ODri*$ru{-6m}&KjCI(nVBBia1g%mGOWR^ z|MfzUfjWQ0 zjC$klaZ?^ay91$tTi__DMVzc)EUK921U-buAyc~@<+B++ErTOm)@Q7-g05RGawAf- zEhvLw!0WU5@{5;8kog|uRc4m?k#jeI=b^tMaNx9k>3-}mP&jcVdW`gx=@-|rrFlzC zc;2M9q!ZKiVw!JLU;P$j^g`KVd7~99WS;{$*_ge{axRKXgoDdhvH~@1qxa2ho`NU5 zpP?l$OJRt34FyA1%?jOaTXvj0DQtHX{y7WUfV8L|ET6J(LcO&)z0K1I-qY+UsxBGA zbiitf;~THb46K=`T+`jMKHziNW0u8Xd3Q6Z>hSi{u#L2i@TYW(k2{t|}(CpTl;M z_F-+sGRBOb+4FWv8`>9zSC}Cwj9t z562((U6Z5anL?wehgn zD02}I##wH?fX7K|o%d`LQdK6SEE^w;mx87NRz$5*c)RA(gslu5vX<_xS4WhyY0NS{e91jlH zW>~wj7L(#d9xIeNt-z(Yd5)KYkmw=Hxh_c%5K2Xn~l1zP%3-#E>rc9(t~B!8^?WX# zLoZhZeQ0HSPH#-Bq_-Z&4bmUsMgSmLq&eIhgP9lbP{ z^mG`Jwxho+s|LnZjs3%iyzT{@bof`n5E|w^Txq|OZ4_qE!J4=uw(398D@IQU$?b$> zO?Ad-HGUxGy?D2EVeTMOgJY|KOTEA9PwQGdZH`!}D!X5GL29|q`iV(*S&CgACaWQ| z*(&U4Uxhx3hM1LxG7H#i)P21p)-yYF?pHr1TStZxh7RBWb2&w=vv)D1xppi;oi0vOb1!7Nmpv2|h)Bzz7M=Z+m@4_3U!5`n zXNUZHQWZhXP{`%oIqU1=EjuB@42Ofq8DCR1z_%Fy(iV*mpn~4N?u%!&8^CTZjmNdq zU;kR7z3@LbUCu|0Td`QX&)iyVhoc=Q`+s`8j5skoY#e%o(sEyToKjGwI z6mRxafd1rE&Gl7L?-ABz?myN3U8q~eX38p; zRpO?$7Ra!h47G`$!Dsb1owW=Riq3ySP=7B?{YgV-Q0ascxQO@Ti*ob-IeJVb0!evc34AI>84nls^QiKPT(uoIlfwFY9xvwMN!$xmk^($B!F1+WjJUQ37|^Q zXH;4%zU(h2v^)@o4BZAs1ZHPqcMW||Ok!hdNI3)|r8tzo$e+7Ns5CYgg;lDFONnq2 zd)In9>{_(pA|jZ&nUS}JAev{KEWr_60R)yCkDS4Q`N%|vm(p}K%T-EQ-@F;ke`m7A zKKsz(HRjI`#ge>_&sHs3NyJ=$;Yw~n( zC7Q+3a;7YTKOh23myzNO&@>e+4u~41cUXrLc%X~bUgXB|5bLm(@8ayhhaHKatd_@p z*;@8^pQ5b0qscMB9XT*_+!Rsi(f3%{{m+7MP9!N}+P=?CA`ilIP_4%fVz{i{?lrON z=6zujDw#3n=ky?Lg6z%#w&^<6h?kg{05iWtue%R+XZFt|Mo`s5#LLG|dosMn=HL)w zcg71EET5DB(-a66oEZL8U3H(~(|kYbDXbmEG&b(49tJVktu%dAZaZY1-Lg3$m~r8j zi~<^lrWVh+N~%2R-sV~v41%i69tk6dQXZrPkPl^k2Qm%0tyAKB@%9(_KUAFsR~*o` zq;a?4!QDN$y9WpacZUGM8*ki#y95g!+#MSC;BJk(yEemH>&?u)f8v~7dsltM!DCPH zrx=;W zzK-jw;a;52NRF%~H8w&?}i^v&ZAjf!Nj!u?grJ_x4;ure4kKTxVr!d~Dww5&2+vp6>{O|1bMBz8aJvG3h^S=?K{ z5gIN&LD_FQ`&BB<`$dTqOqnEFDO+W_++_~CO+O&cYGdNNwxdMha<#G#0aF)m-VIjX zUg+*R$5on1?N1KB!&TVQY4$jyzi$-3fZp1$b50tI3tLPK4_e&LIx_#?by45TiV>$l zU;~&<+LeQQ-xfzJF5uZfq%oH7OIp!_f4KLeI=>@0>&%NvQhhg_B&gc6@N&yr?)>;y zYQE%Z!Y~bE)(a29me(GfKWH#DL|ioAtEYWwwkMzG}wkNCLG=qGQK@Z4W8_;ai9WM_R`yH{i2{zLI&)QCgR{=GRqDK1>}S z=dRzhQly+wh{3b_jqo0PV#{9J1Cm^9$#g0S5D~E+&P0WGA1o>xiA8|_l(BXohMG8x zjX_M_S9Fr;7D>EXsu7dXDkARPymj}tMfnzFb0yagVXQf!x$(TT5#(KPRkw#irZtUr zXmZTVJ@a$HGbL4vv$63iw%haAWZrUb#1+|LeqI41ZK;;DmUrM#rUWk{^!0{q8)g>9 z$k4ByYck8FC5FAuM!PCPnL|)eg&53Px^jvnF4}*%Su=F-vh)GAjqP^0gVo>WFNPUd z-xK4sBrYjH6KcB9JC<4loNK;25X2_kdFI*p50fgxLORDEY`kj;-Z?G#$Z|e?Z)S>+ zy=YoL)yw*_=3UzE+cR@8j7r#*KtU3T#t*~)>aF3YZu zYtWWFGRa97M0R(DdA<5yql{0bEt3ReUwK;O&oz=*)Y$KB$8XFFI$O}>QHl-0=JW@7 z^Eo0n=R9ZLNnGTR2*cH;%F7Yk;cz9{zafOW4kWFqkb)xRckol`mS z_1`@BKHp1w9@pZ(FiLLS&KP5q%6>_s_Vi?v4z>K*<~K7SOrOS+o2-9jyR#dm$Y)#DWEei|jI>5{ zGY!*!F#HX+tMh$g->ANtkPC}zFONY?ht~9^YrU&Sn`B7meN#HpKj9Luj%R4H9lbXR zk;a7LXF>%tH1#dtUU|n3!Fc#LeM$?kdf5FoHHEDu!GUv#g(c!msNul%K(_z@+JDWz zlP1u3lh!CS!re=jlk}?`foOT+C)8T*#Mb564OzVM?e9@uu#6XPlydiie(RrVp_<-$ z9k0;jCM3CS}((Pn)D)A+p0rRG{S3a1SjZn)d@eK>bhVaUYiJ_t7`gat(pUIR(n&xiRG41142$&5p3EEH z6NYgIOYbxehGtgM_m2*8T;Jo#5_HlM3ReR4-bbys`uy)Hf8wiM&}v+1F3Fil>@$8k zO{a8{>d!IlL_GJjQH^K+e^A2}aECIlg5{OhI`t6tk_ImFD__ICa_$M_ya@??a@7*A zh^wNXb^2kbG{Z*F49fEQYVPA6nxX%&7LU#7&>hmElJOAcFYrE7ZE1TSz|;3X!}2o! zK3J61M{kw?ohlgrW;^VIaHDp(dx2V|U{7r9vRK}?by0(^UN$JiJ89=;Q5J^g7@RLR z)3>2d*#1}34tpS(680Ioj8+Z3dPk%x;j$4zVdxs>NHH42tHxqNQVzp*hQRs9ih zGhEf$VNY$s9tfKCDgggG$HIhPZblv;^jCsCJ>pSudnRF&PM-BB@=_%M7DgMb8tq&+ zK73YQ!skQv9JsH!&^T2%tXxHdt7?BfSKVEcFn{)KQ2<)&_!_)-B^WZ@jflao8voW% zdEyhO$nocsRv=$AbpE}`V&mGp`Wmq6hh<{w`c);xMp6|2J1PbnqHx?}FajmRIzEAv zjoXqsQ2d$PVI(zYyA?B6pJ**%E^Q!qb2Z>(N~xLeHTKGssA2d%gCBi2p@ZtV6@q## z0$O+SNu+twGY;GqmFeI!)Zmc%DTy$c(9%wd!vdsfm}Vk3gT7F>P9aB4r^7 zxnw!apj!p;rk-aUBdCU*8cr;0k=;VTp~zkJ`-#DO`%<=7dmXtq%Cw_lUc zM?!dI`|g=a5{*p`GE(v6mN7OT1k}+tr4rqE3*}+kodmliII>-9cVQGFcjdWdnTVMl9Dx!KF@;_bZ+6 z!;J^Gpf)gpO6R#o>{mx){4&+s&f^n-#p*4FUN$nJW*%{l#cFqc@r*YSBP$)P*etLV zOMV@xkXJdRHTK~^;@^hVC*>`6^onU7v5a5OM`F!r;=6u;*jWYEKKb$D+E;j5PRgGx}?orey_>oPCY)`d978rU9W_vnx1OuBwj5 zLLk4%5SlE(@(->kXOr|- z*=DH@6U15dmFom-Tt#GtVyQoWYsg&q?*4@Tw9{G~NM}UVB``tJVq*i$>W}$`4xIO(&jKARW%ag^$^Yz`Oh>~Z6$c1_1eqYyp?BO5rcIe4V1_a@W z7_xNm!QWlb1a8+JkPp`yHy%lU z)}tM$%t1NFTfe0%u>#eq%Qyjs-`I@LwZt~bzgTxcHPeXrFxs^JS3NW=OMKUYs~V2V zcK04096NNH8+GszjyR&dz(!{EM%cmoUnLzg@s#JZhOwk9hcK0|y?k7FdKTGpJ`CjR zhjp^NGpopmOJA$sDAUFQJPuw2zMU3~$#1GC~q@cR2aO*}2%lxZOQn=jkr{9u=) z13qrj2Y+tz3AECm1bNAEEuihAvd$exCiYpOFmQ@UGpWVuvfTa=mxkZO$TORZyN|d^aCP%;Sy(DJ&2i?DedMtm#>?4W*D(~f@ zV3b5_WbP-A(zz=!;k;qQQS#HV0kx?5#|Aa7F6y?2gi_{g<0rDpO-c8wXVn+J>|OA8 zDNbj#eeTTnq2yV^9Lh7(Ca(9}SICCvp_sO$MuM9GZtDj~YG2s$u zj){>srs;;8$VCkUyo;-B^KbTUMbfYw!g`qW47CP&UEEh^b02kOy$U+>M zJ|j{2r|}v@(2(Arc{mFhbPY63{a|UWdyv&-O~_PKt?o6T{&~N;jF~2|m7GJE5I}i~ zXDMq=zY0WyMoqj+Dcf3w)NW=*53!VPjoWDl_cS2w{Hb5e)K<`I92$s#vTnd{h zeFNJF7`--7=oGaY=X$5*?G9$~Mf=_9^UeQ+fV8u$QAs#NgvFP_1Fy=?rrt^x-^XNt zWS0k%{?ei*@yLo=*5u1uc!*{;r||PaFhZ7;hEIK zx%bnhNlBo2;fXoofLDZ+^ER-ZeB$Q#R?X+6+miba;IsShLChZbEe$gGN_WJX<9A&t z@;HAOJZm6F-D*KV_*2+zrNuRo8=2~V9^XJwi8x)#i{y6o-kGNYpfBR;FWx`0jX-q&A9jGW&(pKmYPTFx=HQQog~6_!a`M{KmOcKrI=1}i;BOKfM3hN-)B7S{go8C8! zHsvwPOK;8iwjn=2%RVO)@UyTx$!FkHe&nWX-@s2d;sTpXp3M%7I9R>3H1|?&Di)J| zMH>I$N^`@kQ={_H9+p9lq|M<_>arA^?F!tdxp*pvYr4WdQa(!0W6s!x)GH1z+*pH| zPT_o>t=}-f?iGOi8yhMa{03^y-dkWof5}-0Ge7FzDt^;GvcwG3Z9BN{92vy#78(L> z#iA7I&d{lmN~XWfd~I(7iXjeNvy)IBnL`iwa9fBh>c;Lf(Jk<*+&I?rS89rqc5_I? zNt;1!%(Rv({$t~gROm1Ke-3&vW5)xFhvqy#fa#P}xpP(ZtgKwDT&uUD^o_0DZErk5zU;FctxoRXAsPgByMkR!4zh=(|s>S6&AyV6j`Ux*??yY#r^;1W;_$Iqo z3z6ZTHG~v%Rqir;UjyFjoHtV4(IDcTQD8U!MEr~4T+wdi@5ltCiCuddlfox+=o_1s z>4j`;EY^b}yTd0dw}>7Gvu6n& z6|`W+ZUTHe%`UYC71GGdrFzMA3GpcHRo%%wW6ocW$gjp z{O1Hg6If@mnf~*Vha#pxIn?0H{Z_|ih&&nkwWRm`z_xlvx0+ye!5yy^BldIXpuCYy zDD7#cR)6R&?kOtT^ZWH4eMkEXg2$>KVHq{2ufKvXnH<+kq$2yd@z(l18My0Nge=zM z&d5Ia0tI2Y>qg3z?^R&JD8{&!@>p=s&xFRCoxlj(DTdRUdynY^Y@cXx2>Kylxc?UA zsOtOiI1%{1KHJr6OA(C;s~VX7PUuK?7;Z_zUvmF}FAPe42s-cuO-V;+>3QP2d#14; zeq-JVJ&EeuyYcnIYN3OP^D(|dH8R4646$v-4Y8R}ym~by!Snp(ol`}m#cltG?;^54S&-r5ZDS;E^Z%qq?+F>u79Pb~O5ELW#78UAr zI-}l}e_83Wid*zL;195^Dz))9&G`=f^hLZ_iayNa|GJfa?m6m`xnh*vFsU}RYaOf* zF2W2=9(klJon4Bin%sx3n0r>@zcBNAOZMo!r0AR)GB<*cedob55D_ihPEcEEOI-`Y zq8-ICqv#Xi`TcxbQ_Wvy4ZRNe=z|HNMN|WnLl`49WLRiDsGuBe+`sMxzgQ!XwGN-R z!brOABV9TL`vp`gwko_}n2eU(ehXUYD>x>a}?P ztGnYcnJQGnqssj2vEsi>izycoobYP~Wisv$V=_0Z;4J>X`w|Ui{0j%?!(zrep#F(* zPmeg$Cpbp#aX{o^+4u4xE4q_O2?yPKMqvtLi*dUA2=d9U0Z;LZQ7h< zGgS>t2&?YAlE|QD|1T2NcBIJIxdV>+C$#`-^}Sf`j^$?b`fLT}s#%Y;`pPjEShoGs z&{tizl5Wqvxp_J6ip9SQ88FG8!QEfuU$tW+0*kBANalg@qhV#`$^PM_j$4aJ#ZhfI)LGj3)em3r9eTbu$l<2|M`sn@#9 z@aA~ynDYdz0%mGw*AUNMF*uD-<8$klR?eJS*R zfEr`m-fRHq@vk6Yb^m;Qu869f;*Gv5jfYCm9vdLM3#Y8~aP!UWi-&B%iV@F11JL)N z{N(dj?2;_|hQ7LI?F!6|$?mh$K>7{3=7|GgQ2`G;truQ0m?bI!sg@*&5dV+H*T;*0 z9-Txvfv9SiPM@)0ouYQV=$xPhN4ni?F13gqy-+mDC)?@jYaocqy+nj8(H{iw@oLL# zI?Z68*PYk3mqM^jB+9Wt@tDnVU~HX6}2maTg>a7xWq-=J!hQ zdN&KoR@i)a0ONv39424Vz}xL@6Y{Hldz!ztgZcUxf|e z%QI#g&86Mz*L&^b8wu02>l1l6;U-pHr~uJkq^y2_AD1$ zaI8ZL@2?Hh)s*Bdb&%CU#p$$%pTk0IJh^*IQGD8)1G)%(yTv_>-isCSgC=M@r9Fz2*by^%*@ zp#XR1L>aqBO-|5(z`%9oWVnYVKe&A zw5BG0{U&x}Lb?)F$V5^5G@;B>Nhr}nQ-9>CJHkg|y&K!Th#i9s3xzED{-pO&9ujNV z-9g2>l+`6cg-Yif@9pgwzA4!L-EM3|*`_a)Rkx%(P{zB?2Em9s>N{bw$+kC&Lk-RP zHx>>=dybS(Se2JZakJw&{)tFa2194I1{=%tdpoanDd8GAu{If$# z$}Q#F^w3I}Z1|+;s)Qu6Z$K-t+)bBBUlM=$35@aR3B%%WI+P~jN|1{Ni2Y%dSmH;J zLQ&PV{_-h9kQ0!7T1ee?2sBaYK8NQXX%5FnNFLwN6PU ze58}Y8!tiI&A#A}i3zW7@6-ktbeOOYlhV;_7H zGoaoKPZM_D5~Loqmy0}TtSd;BaY*9+P61;0DDuMxOI$b=Lz0i@4Haaf&1vGvF0&3U z*4?~|gs+8*=+|d+zD@Q@+?EBmlPVlV>J7Q?>h(jRBB4vkWNc>1)FDB95|=hVYebA> zHVT-u;4F~&ZtaxsFcWX46_yW5X>peh=%xl1zSVSPRELa!;k z7PN{+%*R=?qpV?V)-mOuHrrWw6X5kv;V}Onr|FJz$pefSxV-c{B3lz)Ll7nQ(W{`omPl;M)A40|JR z1)IWaT}ffWmy1k+$73)&DVkWEOD>u# z7JJ#_40jnGZhQ$Dcu1qee7w5BY)K<9E$KSVz1lxV2R>Y5dNy_n*ghX^6;MY=k5kwx z$PIzXRV2IVt$%C8vhnV$mxB!x$3fd;@J)KgQ5B>h@OtOahpnKGJx%()8dL0#=x$kH z^Qxzju>i;~+{u!96_ygPpYQ!(A`h#9 zlW%yRG&%J0hx`%`lc1I2aHaNel7Tn(PH7}<6!J(4ga{j51rX%fj4$3!Seojy$NW}5 zEQF(0TJkiBArsHcQGUD2ee&&x)pr!`z+S7LneY z^E$!RZqaH9{ccrHd8HwFJtTDxrl4=XWfSG+-SdxeB9j{63;$=`0L1=Y+h%xtx@R*< zu}y850DP&LfE!wUqmANF*t?oRePa8L2oRHAd3RuP^&U_c*TN8Rn!!%ywk=M;PB`|A zQ4UXwPHggB;PfPUKEGgR!L*cXP{Eqj36>@yYCy9t>+)fq1#<`7Zm$Pw6<2S|inu0h z$%nCoK6}fzO-VLJUZ8Gb2JCRx-shCx(__rof5n8crWosLdgzd_C@vqiupOn!n)9v8 zjbN)I8xsoD($zWI7$Lu-A!z;^<>D8cC)yMZh0ouSuN)LI#aXQ%%Wbss!Nd3qQ9-c1 ztM$|wt?oNgya>X{yXgO5o{%8Wwn4YbU6naP2}`{faXZZpjHKhX%{@?wL;Z_VblE;r z-*8RC>BQl3i?{RsXm25Yw8j!L!6%9VYV#NR3i`PUC%5(B;GQwJjY8`$u1a7kWLHGP zezMm>dYNc{?j?&D?_tHkFg0|_w(36(kAJQ+G&n@aUFvs@b-E{ z$38?VlKA_dV+aMZ8NkrXNy05L>t8J{JH!0r%za9q9jXCa&r2zl(2J>=l~Rqg@XxE>Kq;Mq<+Y zlf;}Zs!sg0AXXO>F~ys)d;NOJMY;2c0k-U}E0}mcI9CDx^IMwQY0=tkALBcT>5MdI#?<2@u$NOiNg|AiIO!!U!e$X({c5o`sQ06Ub}-_wt}vDP*!3OH*7CLTjg*e z+hi2dXB5tS>YS6;Y5}^d`-TBw_Bx~RqcZQcMNUTlBliAJ&9y=TN7l0<*U)RR!6$tG zYy=3;I>`Io+rKQ8a2jXj%F%o1*M<*?Ur}JLLL-hxp5Wjgz1s*mJ$oxaNJr)z*%UUl zJ*qE<;@;2ZvUgrglYo%tzE+LL^*5gmpDXmP)|dO_9zTCV7xu7jg*qmEbFz(|TG;+R zRoK|cA)#LvpuVUxTHvxjBky35L&3wu`#I#Hr9JwgB<>wWB(7var{88DrK14l69_*D z%t?A0`y@tImysP%TnI5gT|*Z{ijUPs8V%4y;~nvuA}8r9vtvUjcY^90nqC+@X{#)F z+OxUN3myt5ArWTiW5{8fK}RQ(CKsd_+Mq+E z85TBahJdhN$(_2W+k;WUYNs=8sobdXlbyo>T*{RO_i$vDc=2w49cfTI3xgb21&#yt zpWB#XOx&ed_$DlsE-ck_YH_B-PI;mT8yUZ3?7;S>`-QUSy17nb3;GcgBU9MRC}x@!;qw1tk7FtR1C#92Y;5 zizw%qJgn(ISQ1Bl_Ih;La3uC3mO2c!icJN_v&XBWK!w?H*~!OkgL%LOl+G8x@-Ek| z@fw++3X8r#7~&jGnsQLmeO{c_snATZtQC@JY4==Ou7mao_2WZDFHz-=m_|0ZL<}u~s&5DGtY{#W(U~3U*sd_In zlVOpjLuz5w`oZhACK7k?R@Q}UF<_NIrWqr^_O za=aHkQ*R-Z#PnPuPYeC>En*G%Yy?ai;iWo{gIRH~P>n$-7xb+MvyAi>PY#)fGV^8( zA!kfBSB{Jc=UdJcqo_BP@3Cfv-66kI_@c*c<~6)PII#5JI~#k6QT5Uv7QFL2-Z&%Ci2o^P;cVQ*64=yos8` z_`7J%!%_P+#+o@>*q~3#aw^hcKT#t1tFQHiE@kX*z{Ha|GsE*_6Yj^YPL67rgg}Iy zLhk^5hl^VHmMR)7+NvM*ZrA&gw+c=LWROvRvi zjuXgFd1w$qQC%cL-X4I78%uMUhWc;kJ1(vpGJacN70%xXcY%g$UBKFZ(!N5{~`*miS> zvDT_xJNv&a*H^i9(evjAp3MDpyoV6Vv5q_pxuq@Ihn&S9WJq->d)#evVjBWbJt5E2 z@B*unDtv*8L#B7}wg+K(ocU`dZr`B`lIOR7o4Sy9m}R}$#*RreJ=$krGRm(ea;nA8 zM1MQ!*?x@;!$d#vQ@2)9$XpcP6junRHJz7nDj0Q6ROgIgGsO7B5)=CCxNvo^g`22k z4%wpai!E1{gX6lRP7zGKnbKgPLAC$Lh1Fyp?UF zL>L~Uz%q#6oJ;FTW5vqewlKkD2GrL?rA?5*Xd+3~SxsPJ%S^aoeYeH1{Wm&CJ}hjl z9V#H1@0ga6Tm*1p4Ba(=YQiY^EBv`ezT(kFr z^$vd1#QPgGwWt(ubiL{;`I3J@VJWiLq1YR-dCApQ`0X#1#Onp=>XX#{$r$^nJi1XN zmGFzlPYMb@zF>XT*|Bj>_~1_ccHPi4IA~JlxavUJDerfT@i;0T^@Jf!2obbgKLj=v zNqe4Rco;M#uh03_3hrCm2lEmyb0FrOeh(KZ-BLH>#`_00@D)~mW|s)&2xN2Yzi)9= zK5H0*U}2WxuI}t;>Q zrU?NJyXHdmX5Y07+^38K?J%heQEab;LPQ8rRJWzB=f4a5E2{kZk`?J`+A2S@{AjV- zuxtUt#lW2Sp7~CgsM_XC^6pC$@ZoC`JsyHqRir%*NCeBMhnG0Fo!5?+kP_gFR`iX)(?EvOZC#z=n>fvp<=V ztku8#&6bUITrr?Ii>&pkJhs>;KXPUhh@}J>J3%dvOx8 z?c0VUl)%7*-EjNQ&m=ad4#zOUn%{z^w09u4u6tf0W}t=@#Y`eLh&tX}I-yic z%z}{LCd0ZG!ALu3BFFET0Vm8nFr7uCz-&wtw)2!O{wcM*jCiYxFz=XGQO)X-MtS?7 z{WI-pOY#bfZ>WDv1CWH7-briVVDd7l`?>58z!5mVEnD=pno{dt#N}bHh0-GberrV!M^xvw@GEwvOv^Kr2E?_|c@5-jgZ=}9k< zFT3vz65B3LbB#0=(=OmX&JM+$ZfXl@`^AnsyY|F&-gf_?_9WNv6+)TOg!5Y``K`2m zv}unPczR)7N&e@%OcTPIP-4kCyo+$Wch&@gQ{cBl>$P#3o&E7?-{HVaY~wPBhr3Q= zq<-N$Ev1TZrBbJIKPK33?vDB%x=v!dD@tqC0;!!`8{kZ}XV54ivK*m&n@oD>w4PGP z9`>r9GaK)*`UPV;HUGDfKr9ss@~>aTdVdy0;}T-&W)g8w{`7kjyG~a9qwiKYMSS~Z z%!a)5vEw#M>;@ZS*XLe-0Hi*+0ic|AN3g@iWZ}iZ8#TmN0ps1bjb!{52{QArcACaT=Dv=Z8(O$oUmezPmL8}=2AbL>b+wHb=k~b$&fGIf%Wo6Q6 z8_VkDn`jp~cmCr`vJ;Zm-7I2s6QTqrWU=yZ}T9y_W1)#uFp&omd^&XX}LrPE9vDB^5DPkRYQN}13Se;x`N)kiUeI0 z2pk@AXCW(%r#=W*M5OM|Z`>@O*Gd%*-F+B=G_xLMneOYD?pg8BjAZPoaB}`~6cX|6 z{&th|65;G~0c|K;B)dc=pIb~3bz6*(e~Q#?n((`$+r4%L#ZH;6!PYI)1uz`$KKPdL z2U{s)*g9B*rCp8>{N*MIr5N#FhVJY4D1vj)0IuM?d~3f!bHAce*R&?=F`1NLnVr|;rXGwUg0;qp*_FjES1 z6@I_^Oi@K}cV#cvb|q0~t}iJQS%Jg4DASn3Gx89p4KXp)*>#F=Sx*rz#2d57XrYbG zQbv==tH^(Jyc63^|CTulf*lv4J9VnnP_UV`tGQ_10J(1GCDD23(MPKBCj5&qW69WL z89t~1XBEtg<G@A;o+ZDE5g+Wq z&D_#aC*pdnnDzGLE^2B6DRNKDD|F@MM<|^xQo=9XsPHFzR#@~{7Pa@>4e8O&@C@ln zw8rHyHY05yT%uOOzEp`p+%C>&drP>{cx0%7vCTB5n2|t5f_v3)>kUO$8=B3m|DueV zdioNx#P3@TNtp?r+yK9Z%~ttrYr@=3_{6Y(T8vwJ$oD^ki|zzo-WlHTK?z^;#&(~g zJQDSe7Y?_(aHbZZ0$ZD}3magVMZFE13GBz-BGz<mTdt+T5#;fd8wf0v!1TDzLM&l_mltfYbER7qMBw{^6~T^cVKP z0<9SBtgpW)wS#wn?L#GRH#L1-tBZek9;vQG5(hsrDAwz>#Pi21S0`ZbN2SKQYVP~p z?a^ybsDv476Z1i#S6Wk05;$Y6+5+#==fu6Xis==<|J%5%v&j$oKVpV}V3RPCI1#F2h`<-4v%HIAryGpKWXj?|A{L~>ZCdNS z;+BEaFte+!^%%)g$akfcQz%`UD|`)pawSmMep7T@z_jXe_F|$uZ5kfPe;H*I@$QV{ z&4nIGVXPJUIe5VH{?71UkI}~+Zi4ylSu(<3tm(_Wz}v?#=!1Xua1@sCr1Sr)*%o@XZ&ZIq^GdO4j3^4XNXE_lIqwR8IiHFaU z5t4Ax#ws%+&^zbz=SYA6m35Ix&Xw6I_*5cU6%OpwBr>u*ezp{8^`uW%p-O$f@g>yR z2ly%IMe()j@C>rfu>;|3cc3&4d}g97z?KvEik}V4%x3v(^Xh>d>~`3rnbK#uXpS?g zYA{nqmX=*11CoFFs93h}9f}bpN@@90LK58FTRDDp$&ueGGOQ->AQ|@StVl89_uTJ( zr%WQCYH7NVFm~(UcZx_|Oj+>LcdPq$%&Vqxa1#jKCsx3PG*>!Crw1J=ugD*cK015& zvG{YtlcQV>wXfK#XjuFUVVaK! zb7dsd>zJCn zpdEM_cwk*3`w6vhmb%20h7PlT~ho|>92Fe<;#EKop8>wWt+-5$*53r zS>+7_4n>Uy)(>ScS?t|dDt0>Bfw!CO<3yX>Q3?G?Bg?sPnFX+_BtI>hg#|PZ2(nAy zqraw5U*z3x$c{W%2*&8}+KBEy*=LH=t@)}DynqybBON^)+I6Sz)S{=+B~ZF-J5wLrO4H9t9^lM z)Zr}ip7V$!?-aP5Y@d21dTSdZ zIhcb`jrmu0p*kwr1A@|q);H&1c#!%ZM>!!z*IxCU z3Xop+TdFhgM`I%ZU}Wy*!#ivZ-Iue>3D-!tP03b;{5{rY$qb5B zSfonnx{*eee;TQI><-SeoJKQI)N>^dtrC{kJyQIWv4bCpg=xWSlqSi=PSJHFSwb+% z9^!i>xZ|&r0Zz%T4upID*G3b%Vu?km$9$K@o7is49nL~{I`V!#CNq~Pdfh7GoPG?P|POT zDc_WUf=FzM!2(NYYaB=;xKtRPh2mmbU)Oo32;iMocw6KJz?n_}h(v7r)ClRzW^I$^ z%CD)`5YuDVdF}p!kH)jwBuRUPbi0eL1x;scNdiL0hIZC%)$@Mt%}~u_P9GkC>NIQWs(vkSo2Rk0xg{WD&|?*|~!CPlQ=- zTsmPyhV8N7<#yiXD%Po6=lpdyltg8n@`I1`=`h4}JBc==bm*ioU3>Bg*S&`K+hTwZ z(BpUGv;oPJqDn97s(c{*+AplEO{EMgl=Wr4Wtt5>G0%^o(F^GO=%EA|)Ds8rf1ry8 zJ&(!-ylIGIgA*rVDVL>I%%uvSvGt&>bgx-bMP9$y?6+w6DYaM`xs-bjds^QlpxtQ~ zBCHW+{y|8icXYS?)~>RjU0be^{oL zl1S0jDBSmS^D*FJ(Ar;}UW{=Od#zebnesRJ(`ntFxvknS2i4PCnNb0pvRT!NEDkUR;Uw5^!zd)R?C;*l`vWFVkSD4}9WHEQb$MJk4M@|X^ zdO`RYiE>831ryHEx6bbjaxZ)y7Zaj`S5ug3e5Y_@TL^xgA6b2h!J-M;b&^*Rz3yS<{8?DD@-6%^1{asf>`pn&1g=M&1CbzN@@0m*s#_&gH6?V^N1KsD9=&gSjF&36 zqdXg0_;~K)AKp=)KnH!9!I{EFr8ZY6fM#)jJZ}H0b6UAdVJ}Asxe8eVtPPEPUQtvW?c}GKg;H+3W(PYq+KH}g1i`^eA|0f~v$@XE03yqS{=S)`nXEu9o&TYyFZ z*t_!;yQy*IT(SH3tSKd1nvDLWCghC?VBTZbj&CIxdVv<}NMT3M6TxWVhM-C zyu8qW$cRilQa)>T85mmyXBJCiM=nTkmU((mrP;3H?Y8OaLBAFCQ8ebbZM?`6zEe2D zX2DLIq}@Bh@W+;EmE6CHq6oLWu;So5V#QbWJ^EPICSWo-Kh@|ZBMTt#(5AC!Gt|ME zTMP47|2J^h5K?{|aDFKIs=|oI>Ms(DGjb*hO>y#Mc^=WZcLd}Hku88vq({F5Q0zG45hb+ z91vHxQW{4K+6;%W+8wgfIUSb?^>bGnbmB+%9Zt68uB*2|p4(i$0Gf+yqA`x6qPbd9 zjg4tuqug%cAD*~^fr-Zv)az33ls&&|U>Am}TE`YWDu=FK2Cc=~c!ni;M^(ktiY=E| zu`012)&UFcq$}g4ac}}QWJI0kfY-K{&oV|aEwzxe+sRQW9%Y-UpU%XWBkAFV9gW1@ zUf%`!V#-{ErU|>E0Q96I{kOL4u@)B}81fgt4^7rF#5rkvJ1fwga4G`WAu}fx3I+My ziJb49uN{@Ag>3gh0^(lSADAKjCQjc zrA9~Kuzfde&4iICI4#40jkd7R)OQNSG%?n-NR6<6gOU@M;H6xRB>Do+diOwSt7G*W z+HXPgur@}#bv>fqhoHmnp#MYFSvJKLE!q|c?hZi{G{N27-Q5Wmf&_Qh0KtR1ySp~- z?%qJ-&@}GyxK*$2J?AIvFT3ViYtAtq!u0F{IS9$3-l_44fRc#rqw_E;+CK!k#^;j> z)7&@5y9O#}$z8km!aK+L7ND=&B)xKEV`YK#`X{cgM2Nq9hP{n1DmQbgbzdO=6@b1e zGr`8igbP^h)czdL=>iN7>4NQ_r=yuRd~b=NjTRDBg6(uuJrQEAiVOzWUX?Th>?&V-y;1}Gm9(W*ny2$}S` zU9nWRxgym00EzlQ=u!E#AlGN!qXj8SAy!3C!49=DnjcsrYI>cLP;+np_F@rb?C52p zImKWmqQ-w{7e?e%!WLAYrf^WEE<9tM6jFpLDFbB_UZ{KUp$`!$;5Q=(ifbG(kcgoa z%AGAxtA$31zI_+#9ECC-tK%>mbT$ZJxC#2zHE7Uy*y+Onr9cVDmo;TE+-u_~0 zme)9Y_(d_i4i59kh{ky>_-j`c)aH;gl-cZUC3~V=3v6DYhx?xjKp@PiC66t!y2S4K zQ4LK}SGO&STCPiBH1nG44u>2kDeafMqeskqL=TFM=^Mb|3tEc71 zHqzAID&6oQ(Jy;Uz#zcZsvN7S^{vWRtRwSiglUt}$h+zj9-1{5p}n35@F*WNZ3P;+A{nEM&B9*5V`+zUZ6+B5i$Gto zoh!`fKn-rc%7JytS3PdA3bc3?f5w+cF5=11C2JwfI5Wu~TRUGqV{@=V&!VcmSkI7X z;S|%jZ-+B?8ZPfFAStCgi7h<;L5nd@QRZD!hwt+6+-<<=pFtH48jUksGHgxQl;3D+t*oKR!=>2Rs zGS-i4$$!#s@JKI|YDEXRX1}(S%!yuBT({Yn|bp6B0^7q5Q z+{?`j5cKpX89akOoL|Oxc-$#TeET?@?NWaBaoB6{6Brg+BbVI)k@jJvz(O{uWnc8R zw$}-Opxf7sL@Q}FU2t9)sP(vI{h3|%<>U>#|4iH&=l$|<(NAst(n}^H(tWBw!er7c z394Vua5NQQ&mR~Npm`FwTaO)%NuuLR(XxTJQc(|vUCjE2UkPSrUt*}qgBnghR4rT zf7Y^K6GU|vbNOG>5rata#p-vfJ3#w+&hpR`BMW0z0Z`@l;yID+s~7m%(?$PDnJpHC z(&ftH9TrGBwo98_BIm8|uJyUb$lqQ)-^fCAeZ8rh>Px0*0;)C=BNvWJ$guZV@}9-@ z!|9O`_uDT7>ewAT@v3hp=Am3ED~sfAWC025x)9D>=Pht`d=sycxe z`pea^$sPp@pv1`T5=zu4in)C$neH?^O;)bo-XW0Hb(HY?!cRL-%oT9`k8nY65HH0SEbrf|E zBG)<2{BSdGO~yoq6aL%&CIiDKc`;+B0(9gYRVcuH*IOhEb$i9bBun%Vt<4G6jzK2# zPxqlv1x%&<;aHnYEL8kpi4PBDUP9o41s}6kdo^@HMisi!ff|vV zx`XGMlpv_}3TJLiDxtanJD+jS zK-P_EH%ielNY?oR&s&sX*ul@%Z`syp@(E}ygNHK$-E2NS1v{33;DYeF)2N{+Pr6s~ zt;wV7xgo#6)gup}Bh@Vv;DfHnnMi}pQlLyWZuh2Zw|s;1&ux8Qg{1+{!QR~-fnK?A zbqkwAaxF9+S3&8ZlOeEWJm%bc;riM7ALgiaxcsr(gP@X?oDXXi_xicO6E;VIs%5?h zPwc<;htG!?jIzMiA{pYy&ffW?SWkP0Etr6xIIR>l5#Z)4dDiMe&D(Iq4Yh#|8|#); z8NPF!N4-Gy&rvcftB0)yRnW8(Q=mBY37QNKgO%6bPe0p)CX>$iCA0o*qFLvc$^E+y zu>ltSd>zhKQ{3daedpOC%IqO+Z?_8LatG5*22Y*L4-{72HrFko88(6Ps0HU#xv|!N zpjo(;r>o7aezD)i;a^cbr1eJ(bah%`Eo5zf@ppG8aLUG@d1jh1uxhn9;0*1-8PX`c z#4Wt0(XM>&6hhwA`X|ue}3FOzeNImD5To|I?LihFh0drO?FFi z4K-baiz{=2)h5cA%)B#Uw%?dlF*)HIzW9E_{@F)dKgxCp;Us*GKf^?~uetgc)H&6i zJ#*XbhW76Gs9!$IT8kmn-TC6)vboBi!CpP{yzLDqwJUeTYxsk_>L$3cf4sZrw7c!k zJc>Z}tng96CBH3JQ;l|Y%A#c|o+5pznvjx0k=Ah|adD3CH0{zm%+2QFZ61GL-mU9@ z$_b*!&NQIrNUr?4{Ec7z?7N1C082n;>_x!s{RtTYT8=uO@7~ytYA?H&$4b@Wr*SHD zA1uol5=k{aon;l=ve(BT=MU$`J;xKty;la@OShkv6Ou1$umKrD=ZJR!X)lcX_Gpv2 z&_zC(6oygl7;1`V)2gzgr8Aal_K!Qq4qGK%I0Ms;Jz#|B-4bU^BvS7L`1@0$@oAst zPtk2By+>J>lPg@%7gOj_*Z$EOl-c#siMl@tD~r{^MB%gc>#4WO`xWdoTOZ-~)`MWe0>@4qh!W~}OJhXR& zKcouODn+&gBU~NX7nwbOppR_bGbl9bv{KflcfF6w44HfR5~(dKMAA3M9Sz?-TUJHn zQP4Gq;i#{E3Uk-Xlkh0=XG&VXh*Ey_k`?Dq#1btK!yb%GUhB<1uQOJ+0G#fIVVQ5_ zOL~6^l_DTols)`t&D{cr(==g{NgURflZ5KQyH886%} z{iCdQ|0Mx~uud5HA1B)BO1i5fSoFHY^nP4O#(+_cc<+gnW=CfO$@ZVR65g>H|?fW_!OrB zZFjKo;tsX1h!8fP7sl&!K~i`%PBir1sAyTuLkBGj)$*j6DPpdhr>%Me&T_USD4kJ)3k0>)N{$50im-i5qgwDWcT*^BI2 z$^+cxLdkrK6Qs`%^%=4LC61T0J+tK2zXEqAgz((65oo)pHPD_P4dUuJQ@}sbKJk*E zNnKw{A2LHhn`CW{fS>!BBH%)XvU>a>O#8jVe<@^M_f2~X#iRnwAb{79*~a>?;pYaZ zNx9^*9HK)B`p*+wMsmA~4iJJa1Dt#&p*`ST_UtS<5o~!!hn#T7ww*i^b$1!`7i>Xf zL;d{g95QT-9vQ2mnJ+4Wc`~Ojo@)N~F4r(HnfEub4gDl21+J0L$5@AyZEfTPEVVRm z@9<^r&1}q^#CW*zyh)m*R;R$Zp7cH%W2_~ee>^V5cE8v`r^2n5D#N12NOs0nqfzy} zs+Oany9&vbhMi*1STSW4zLh-roak$)Y^+# zjYGLWWePImMoL7;k65zEgGY~HxUt6~z{F*vflz+Wlwd$H#c$inj{Jqy!uQShu={y7 zWL@q(ZK{yK3>Doc`Yq@Uj*!8&s8L8&NPFXUuo=`R3ygc4Lf#KC0%Rrh1|BSk;~E56 zZ39U?CjEL`GF;mTOg(jGyN01%zEXB6pHMh`qDrgq{1Q@jV**7YN}K1_*Nagj&Sr4q zV2UXRR8yI<)&wb9XVI#zZ&L9Z^D__k74^`6J zx`mjx&&RvN@3UrWO&91VjQ0Crn9ZHaDB=6SmX4x^&!6Ev#tj1~M>+;c&=h*P(uJ{0 zB1zIxrR3vC-ROP=jspnvArLbLw_4qRRO7-@wPQe|45Cg7rrEWb?V*{B4xC0)6Tw=9 zF>s6V`#o&1RK^DMv0L4W#0u;94)dOpG4Qs}O%&uY2JgJScfYd41MejLS_Lk=o=z0<7W%3E_ZP3D z*mMDwE9GYrh0UQqMX`V-q_r=z4<=dU;s!oq}?n&@otMQ=EH{w z9F3SPG)TPfAgwsXr%>+5H9S~{pZaZQOCE<|S~S28X%+)K^$@9a`Zttiu2>L%=Lq~+ zmcw>3XDcE9TyRYSJp8&v`f+zsrXcTK{CEG z>*XITnq(gFq?ZB)=Nt>K^)tZmIc*HD%UW=5gE=bHW9AtwM;%WBWsoOXsJ1tql@fid z=vV6r?T&DTU3A>G;~~2PTVgSj6yAO9N5Zz+!t0wP>_eCe*UD4lCWF!f4`WWGinu7B zFhNCNp)_@u+!Y4C-KUVit!2S%>{*M17~xHZ$CvX5c0?u&jFd~E6Xrwo{~_8=J?Gq* z9YcOzIlkX+d`Mzkfwqu~xAP2j`0k?*3f>XqwCH^J+OTiy$=Es(!LkuZEyg4?J zTIzNFExs~rir-&?$afPXQKE8XuQGh5`vpAgJ&%{%tT%laoC<7Du4UGH{Q(fRRj#ES zjG2kr;?jNUSH`2k5T5X&I)q%p++Y2;K%oLG^C4a)5Bf6tDQ9UnZsXM=*5nX54gQW} z%hbQ!7Qab+6N~BPa)`-uI(GkeaBwnKGN%EI`zL$SPvob6Y?_PLRe~@GjrY10i-e#{6tx;WIoLrRieXxk2pkFNa9}&ex|KxF1Tb?TKj4uT}tG zIOGTOGd#h`*kY>eT&f1L&&3Rdxbo>Kj{MBkwaTrtt2J=%KaLBoxiO0CNah~ix?8{Z z5=Y%ey5H?YX^n=oE@HG8vmf<=oK}w_{8C;~>j}$Gnx%f|PW1K!T8-JkCj8Lt&^!C` zOea6Qpi05nd$38JnH0}An*kXPk}KDd{+-@y!N_wFD34^ru!W?!4}@KV_4_LbHN&Ph z0Q1#k?Sp3e#v-G5j@~v(8cW*e6ey^6EuUUZq*Y$R>@jiD6| z*WL`d*%kL&K6a;$M)I8OH>eXP3E2&32bj>{xWksvY|H#BFVo{J`eLEWuKx3bjxRNE z_)dp0>j3+8!3$DR+#br+ZNnUTz%M&Xr)7MITEdS2oWr_LH!&{JA0HwAlgNSer$=B=LdD%zRS-Zh zCcv$0jdHc4w}03SAx(|hyG~`RL6Bv}V+7+9Ite^@oWyk54TTLQ)qU^1A?=FNg7bLt zu5${(EZk0(%p+f&Wp?DTiX+>9bz=I`ZLGQW7)W*@TWa^l{?M#I@ef2e>q79&?O{U_ z3D*<3%UPKIETQnF^<%3by}N+JbY}JytUAkFPs~ONimV+BrYd9Cq+OLN5vZDojWY(Z zc(HvuE})D*yJ_my5&GcgCUlgWWqJ@W^gG7CgLv$d^4~Khz$XyD)iPnCFsc)rvLN)Y z+N!K8+K8{(koo6JSEU)p5+{ae^2g)(rsu@9XzwNtv{CBRbXv~-F!^1gLYg!czPXuyW@XeTK{9{SgeB)!>Qq{GF0qqD4 zBKGi{j4VU?My{KYt$OIWt+)FlWab_8Ix)@$-EoAe#GU(G6;%ds83)VOH%w{U~7?m*CSFw5ug?Z@nMxeWObu-4c`PUshRNM zOr$$Igx~yU1bVmDrB)?Z{yBEF))WFZQ<_tE5WMxheO_xCKCju14L!iQ9lE`SBsqR7 zjk7nk=1-^;^K}sHT?1#C$~eqxDz7x&EXp<(uR2#>*5^i>3D1AE3%uEFRm)Xb|G7~$ z$BAW+Zgjz7w2RIXNZ&bgE>CP!HVE5w92<<2%v+6SDJ5MUhZNs zB*5j?G2?K`1sYnVAn+?#NCl@=r5iHU%OCRxn;zsq{5Brk{*tC7)dYqWVDUH50P z12*z#a9zF>61^>+k8IpZ0BlLGJbi##TvDevQZ6IvF(u&+SS@-w`s`Rzi&}3x-tBp?X4x+!#T)(j=Fp+p1g51K!0S!rB9nT029J zah-xt1p2JvVStx;8^U%=e!(rFEAaA=MP3!5`LMl@v6>e@(?m6&d?z;oB*#bja6m=t zOa-q@22L~6B%A2YMQ~If@a!QarTvm+oPyOtD{Dw;!9;-R|Ru4BAi=E+i4D1=P@i*e;h|5Z_LuE}eqc;34QH;vCfpJ_# z$ByV)X5{fXQ2FhlKZ^#Kv1fmJg0okK=UCY=XC#kB(J-0_AzZ$B_H{R=@gQ;H+&p(< zI41P9)wF7iX4W5rt|1WILDUdb@;&0lyg=xXh-4_Lw#o266aAAoGV~03-aIfTO--{S zH*5+w`GTb1&~`}ZlHZGTFjX&nl4T}7hU<0XPIBu*0_S^nAy`ckp=<13sI?=2|0F|5 zUQ5m&2;2e)J6>)UFo0329&^^5kwu#?nDk|x2iMvVfZXEg#f3;N1 zj|~$D3#51(NMAz3Y>>m^u+YPXi%-bS>xlPbIK6_lxhu1iX>yg~)kZWde}0loXKd>)&iuz%41|e+;%olawej^# z0K|JP7e7eFILrMrGtxx}*1Wyt{51k7(*dpEV_`(#Ck!tvDo&_Ik^aN{IJ$gZF_@DOqnEh6d%h7)} z8%hwBe#lb1NC(H_CsRj6`uO(nn3y7)5J>FMv$Y#f1a(AVyIC%(InLdhA>JG1>dMfxau7dzVE&w*xYU9{NH>B0!jHxaoMoZNeMvxS&O1&^c%!uNzz;4D)Fe9ml7JiYPetJcEo1$u8bJU4Voy`1 z<_GVG+q!T@DQ3c?gqlKC9eXM)D%(6?XZ8viT{04Tm!>sikC}2J_0SGMCdpFFY(!?o z{r-eEOjeJ|xIYS=glNyVLkab3q)-4EY+r1yNn0;dku&m3xfh?T=i0_F6G8Vn3 z@E2olKa<@+*e81*>Lgx9=wo1DPe%(`g>WSp$3r=aQnVUQT^UY;_#pYDX7z&cJ;rf2 z#6Hu04|$RC+;<^m;C4+Vk&+EhV_ELGjD&?ri7oRZnttv86XA8oh=KF-#XI(|oKhRp zn~}lLA6+%qg`bY+-CEJB-`&L91?H3hag389Jk!oZPb0E5Xz|}Lzpj3jr%ZrMGY;Z> zlFf-%Sp)eP9X{I|9vsu8VUl{{@g`QafmYqZ6NHDk8oPWwsH|k)L4s?A6{h{7#l2p& z!z?iF;k_1DKEH1xey_XQOl*Tb%HGAs)+E^G?-y-?uc#JVSXsP|Swisx8`}aTUg>N5P34IZ6ac$;r%%|a~c~U*NGlW)}%c>2l zT;>#7xAh+sxr`S4Y8&AU_gs>G$GyEML9feVo@Y!&MB{I8Is7VKjc_!?%qNts;L~#w z;^2wsO+8X4CYxDfFC2{nZF7Q{YN-%@?c3=V(oCB>XfbGRqg{WETDk!5ZpXP`2+7`p~>lYS&d1NcA1}$YMQw{++|_NBep?n zkJ-8u{T=fDX2ZYt_h%O`dqM#84^u|t7Y;NbhfRpFkSp99iYM5LmP=Z)aFrP7uLl*-7tH>7wxHjM_`>3(K8WNSA!0zPdjd@(+qCn|V=2|*B6*sb@u*yllB z0}ww*4$Y@fw5An*>3|QLf6ev5Xh|UdXIML7LB0V{TA{(iPId&J+xNfB2(Fh$;^@^3 zLbC`M)Xe79wpm-kTIxe@>-FV0Do?8u*=jE_ZnbDU1A_kRhKM+2S7LJOK$F%&^S+GF z0{WeJn|?Ht-u0ouAFy=5d+SZ=CYHlK1iCMwF9M>PU%a|@r~>#>J$(ledWkw+%q6v^ z?7Q5ehgS*aV}(MW2ilbo#$$!)0>2-dl$b&2acf2)HsZP{O4Sa>#!j9)_H19&$$tXJ zn;ec>*!l#x775VpRRwjUWeQG`PT^=L%$_Kuo9CPrTi0(9|5er+_O|IDN(rytBSM)x z8s-Z#Iwx9vqi#w@r^>(!lCrtCxX zVWg%e@W=fLm#6I~pU7KQh-i=R9`&o9d5Xu1rezo;Tbra+U4euMhgn|v zHl6CPMn;xFYzgKjgx#j?3x)cA)y+m!Rf>S9?F=adu>0UubH%CrkX3oiN5QK*l_MZQ zOQWmqrmf;p0rfU}<+xTS%IWo38cJQr(Yegs`v2{Pj<>Xt?6+HmSsLxYlDtT1{Az!U&r7!$>uIaH5Xv$5wY2j@8NI|I%(TlFsx>B zPZPKzE!oO}$l-u=C#*6n*GB-%ZohoYUY*^-6_B5;laKg@^TW%PI$%-CW6jIi&|`?h zs=e9Rv7H_@q)-iBf()gd)OKm4>QRt_HO>-r5y=pDz-}$?@ZZv6Z~k!4-6tB;Rw=ww zl2>w$MEm%&^ivD~^t77&;}s;y^7zd?M~0hO@j>4%RB5*=4Yw-55W1Lwfc%lVXMSS6 zIgvke9iq5b89p_H0c4FUal;o{9ocqqd{jwfn=y)9cKIdaQRFNb{ra}y-3f0c2G2_R zTbv{`-)}N*j1}SkxXC$GK1?<%fKC5gZcAYIx<0ph5Ok;KA?wk!~@hFc?c+ar(By%rN5y=w z78<|GaQ#6Lb%y8o!~V#O-Z1`F+hJa##BbGXoX8b^9#MU}27dj(6M=3YtAQ<6?m1JG z=@}cuDBWkq7uWr*+Ay4j<=fp-f@TJUWMUq_U|8+$1TICjjtrk7wK`wD7FyPv_?>=0Qom zu-=wKwVJxO<{E9!l|IyooDQl@SWQ9`4+MbXTVeJDh9rlbp|u7Pln3|d7-=5Fnturk zvUZlw4<|q^QBB(aSJ#o&0uL8(P$;l?r)NBE_b#kn!+@dj78~uz7;vYd_S9za z;Hj259wJUm(nRX*ka^=e+z4v~EdXy1>0o%O1Ukkh%c*B+j#`L?66kp4c2>so8C|;g z2Cj51o9$4zWY!N*bOhjL1xeZQm~w`hPNVyxCPkHEqZyARH!=_XUN+NBK-R zuCk;n?(XhcU&%p#jXpK6D5m;)I$2fS^6IToW>p)``&TD|DsSJ*t~5B?uK3*!YaayW zQl1g$`D^QecID+DJZJq!?3WX}{q`4$FQ~45sm1=$Gt@0%>x0r4%JktQr)`_Er^tDH)#{Si${1`JR5z+R@A|9)CDJF(~VC-OdSn-=x1VqrCqR6tl# zgLhcSjhiWeY7at!+vZ+8FiY?VU_Mf?F9Ku10N1?e2l^0wJ#Ub%&DZ7Mi{P++3Z*jF zcjwCD#wHDfB0*#%Ns|vLhTT)XVh`?fO4L?b z$&@KcviJoAu)dgf2&gYJvCl+Gx2kp*4>C{ojpMF2?A>&Yjf%Q;u<8c)do9Uc<4qOC z!pBd__&^DN6yj|Riia1x8-jECR8xoRDPKl#mQgpQpxfKplz-XK$_=JD!CG*A<-2*9 zErnvhMm67t)cuU3=*sZTdqsBr29HMuDHh2QZF(NJ-Vyhckb5`EAdK3JS!SR3vcKl8 zH)3`#l!P2{K3&|CE68$< zFlcf!!`bRw^}fN6;q@?+quST&;g9hx!T(eiZ>h0f4&K0?jn^siFb~&njwBeqfrmRX zf=1osqreZ!k+MKc$aVN@it_{lDTKh!QI-(U;q5OA5BTgn#;V}S!?27l+HuA2+KA+~ zfU;iLs>icsrZ&os=X*E2Skwb*pNiWf+2)!zr!Z%*P#SN&b*`0EFGl@l_lGyjXyo;K z4Fa=Px9W&sp~;p4%WPKS{)=EPN@T0&2ts@+c~btC8;+MrNPtH*#+E$q?N{5RO=m-i zT2#2~+EBILq_D9jH8`jsU8jW$Q(;l6Cl|squBNPy;J9% zW4mnjJ5HU}bL3*1)|wMRS|mTTAsc|d*>9-qPyJ>$a@yL(p~LF6o=~v38{^)~4&cB@ zJS2%HE2c#pxHY4FQDO11dnqazUyWWO}A#p z_%#!g9z?8l2i$$hGR#22@pp0!DC|twrAZlFfMUb{)qQ>5K z5NZUz_ln=AsB6y3Gyi@ArOOaQyn$)myAU~E7`*IuJ+_~eC))njxjoYF;D~ z@{{LR+u47xc*DW22I+#bOf^FtFlxayeuo2$2&?Qg#jGjv^WNbRi5H|sTgPodZOT~so$I?@H|IG-c9OLhyw2yV2`^mtdSXc4=L$ICi+2>+Cbpu|{@m3NOLgF) zbV)+M1)&3m0f&j|zbtZd`940rc+Tu24!P&XfB*{peW(2CW({1R>ZIe?;0p6gM-Cufgh-L~!;^@9hCu3%=} z)z|5yh~|Ytnu2bAHIA*`Yc1uexh&n}>F#g=*Am&hf2h>(IsGX2D zGp3ryhE*FMyX}@)CVqA=dZcs=t&=Ujdt+JO+y@wvO%>#}DZNSrF7I33Wrdov*fGZ4 zZTObeiqCp`Td_WoOwxZc;q-UU+WTIR2sh@O#+ID=y+>t|t1zWqYyR;*$<2WFM&t0U zk4j|5-G&|2#Sr&@b&V}o@1AMFP_YPu)q=7<;59Qdql){?JJfM?kbq`33gm>Z|B}!s zOUcMC7lH8!m>R4ZgV!zQ}G_19akni z!uGG!MX4v8kC|5JHRUKo0@|87S{Fa*w`4^Kf~N~|*2L4L+5Yw5t$G!|36r-;JM4J6 zxlBZu1Ceh2)o?t`9Y4FiPP3Arx1+SMQhrVb-Mnel-d*BIQ4?zpuevj~-n`M<1}mLD z83B zzXf7<58UZLBSg9pG|UK*9MO^@F1ZXmCH*m+PpkB|BwJ$V6q-=Q6M zsgmHrE4l_>Pk1MCZ>}*6>JfX&Dty@wGNr!aV{y;4JZ;z?BVM38cI!rFM!c)o?F6$E z;mRkp{3wZjmdbu_Jq6Y&@Vy5vnQp5cR@G^Fw$A8pK(`;@UP0~zUknuA9zNlFuEJcE zpmspMQeCIY)kzAGV?c|y5GxS0R7tNsJY3C~QQ1}fPH8AF`UNRT+V@ESW;I(YQ}7b* zEn^0cBI7=%4$KhpTc5P@6RX9>ff2iFi;J%r_&bi(F)}di2}_m# zjB$QCL+W4p7l*dprcp4lfj{RWAddMv$BeZgp%BT5?=rMeN5$#0C76`~|Ui{?9b<~IkLz}T#I|HrGt1yV^N zlhePoo(D!oyBW_ArqOk7T6$K5~52quDaY%Le4!F)9xSMc6X`$M!! z@Hp2@rdraON;1w@V+9zvwE&$*1(lXRSQG-D1b$yhG5UM+Za%j_y&>9t|A$@H@6q5r#eUVK}>tr(%1Om{cchNPo??Rlrd{bC4>ST>i+2 zCjn(9Wx7y1_!4UbCFKD@C3L9 zt-PbTkW$BIajt86t$PlFNq>N|yv(Vr-5pX;GA`+cbK>+8OCp~>RkVul$EdoW*aD5C$qSmEp-(l+C%!XT&0k}a+JbaM#EKHmkLqEj3P~m9iZWL{aJ~yObW%h* zVUB#eamVtQT}|^rqk4=H3^lHi@dT)L=U!vkzzc&0OxnFuw5;hPLm6C!2-n{YS&FR2 zRc%x2(>0bKDFE{1XD4bIE7+)|Z#(sdJoOCJO|03Kk61vSE}nnE1E0+F=S+7552Euj z+>%UoGHcemH+|yPv$`7A_;trJz$XN#M9lkmIdp^_pj$bFb?G_xWSNrw&5hXx(&S#cWIzYQ>?bd~(8Kmx_;i6=bOKu2j_A19iiyyrS*2;*`($>f zxY4~JjwaR``ag^VjoYx`3oVj+xS@mx+8}05iFZt+N%Xv|9^-oPI(ZdI9uwU5D2~if z^oWGZ<4^xWH9mcBD@;ql$0z_H(&9I){{uEpy0Hx%dM+{wyihhLyCJ8Mw`cmIdFAMc ze`;+mzB9CyV?Z6c3Jc%XGdq}s;ywY~OCJH~R&ck8?`p^y{cl%xd|`6}k6eFsm*e&i z<{Fna!?a&X|roH=LCcM5%E7%noip1;I{j+60vH`M=&B+T4Qy z(eKw}E3Xv(k9R3Z2o@}^ytZ$bM(5Moad#g`vl2%#+E>UG_yHN1BUnwD^9~;Wyz%-d zNcdsjV3Gsqwv0t~ zZqVhJIhYj;wy9VS0y<3{u#AxK>l@UZlAQ(23{NezZ5S)nMm)(sP@^h{R^N|k zL&s|CmEr$M+R*z2__+J#U?#{Mt1<^XsRbJd;6#AtB1&x{%~4`ICV|xR7(xB^W{bEc z#2gSf#F8*?h|&ICHq^z(|D=#s@L1M=rqB-SQgzGlHM<2R+YesK_{@*%U9;9xdfH!G zOaPJ@S#xq`Iwl6{=239uX8EL4!%on~x>FHBPSCU@rL1t+xy7vHF^hVOM+3ghbYLo> zJdd5DjUihC=KK^+@Fd*j?lL=`D+qI@~rmqBTGI zyKbsRojt^@w9107x=ZMa+9ATpcT3%qhuPE<;!??1IG`W0d04|aJ<$1!etU<#@p#34 znE$l6GHITN%n;ptwlN3q=$rRHelyW`<~ZrP!vWJF3XMK{1m7PrC5D%)ymoUhZ`H-O zZW~4G*j2xUkjGDuE->B1tO5qoVx_qd{F&1mT_`3FP%oBZfQU}|XDqitb>nzw&niVw zvW*1Lwbwu>z6(8#2IYD~8Fm>DTThcP7wzZ9Yb=o;7s5dwy>1Bvp7WaA=s*6`pfP{q z-`T*d&ISF|>L2j=N*fdG6+W+C+6P0Vsa@~y1_kl*v!r?nkxql zAxVm9`MPdmjX|=`3^$u^wfZE(+Ko-&pD*1E{pohH7ff<&E`(van=g>uTe|nTZIHh7 zBEDig%6Du(*|Na#&~G!{6Mbyr5-r{Bjf0@dlzDmHE0hT*kAQu-2dB$Z_ea8Ii_+U) z77a9Gr?rhgi5&U&(Ch3z)eJh#axbgT3RDBIV=@vrh^(j$QO z+%bZkZV;!I#c1(X`s|R#^NmxCt_9FSMAkkTTVCiHEK7|FMf2#2P=l{V=HXhE)?$(Y z=l>XArd?uYjE7R_5e25Hzjq*)(rzyPRpl34{UJE_11fq1$!7l~edqUDeG-tay;t5@ zAs%gNnXqtWS&WPSz>C#|ekT9RAqUDl8ks2x7g&Dcx;E|y=emY|plOCO)WiQzErr4= zYl@jH7+E5Yfc4c&=T= z?L4K!vIir{HH!FFuQA(1(rkVFcP#}ZkXfp1W!kyV-{2U88kO(U4V`wsU+IK;{SH_2 z5poL0lQ^cj3pDs(H15<*1FvYjw1@7ZK6=Vj%BHONQJmJNg1MH&X;5!Q0NCEC}m<7Dv~z?))8t2`!*STy(GGr1{HOQx7WQ zQeqXtB7eGSx}5;Hi145bu*&aBN~O*VU7ZaqyY9Xkw^o1E{JS(M>`3-~#55pNl%pA* z$~0G*kOTyUcFkrNRQq>!X2JaT9ZrfQf1pLmO5$Ar!`oG6U~u+P=D}ToZBxPC_SWcT zOiT<4pfHF-Q9vbZ*>j4lWkh<-OV`fLhZI96CuoT&r^cbettlzZCHii1zi%3GSU$4G zO<{=up4#1-ge?}ki=;6eVKYAy_vN#BRYCH!wT>V6k_8(~J+FVdh>U-=Upiu~ZCuZ= zkE~pC=htzs+di_}@VGXGbz?WFU&BuD1p*J2WX6PejpC^#*~Wotm!yVRB%ecB#=hUp zkJ$CI40izBU-eslzD)dz8Hk6Rq;M+JL zwB*qbLc@rR$ek#X#*I^WAu}q@*|L=dbEK=hAv+|z$M6#J`qGlv6{4=CNa zq03e|#r>~0SMY46(w#kP-f7EoKEB5&Qb_dz>R@ zyPbwOzCAw*e(~`IxskkKhwk&>ItMpGvqDB1Y-qYzGLpX8tzvMx;X3`Xxh1~sK$;XS z$H2}YdS4gp{)U};n`@sATjq#+xP5b~yj5-3GrUnJ2hzGRUY*!OSy_AR9I<+ZKewJ{ z$LgCT;$Qy4RlFMNy*iWan4&SjaC^kjs0>8Lxl;UT#igCEd)H7tL zH$L8@G5Xm_Xq;3;OG)%Bkqq~HCTS2WP;N^+yYK=|Pn@Z!cc|LrN{e5T-v3*^%FwRf zBd;6r+@EjXn{2?V=;RWT4arRVa$I6k7D#ceXXj_vXq}t#Qn~gnq)I~{O*`kdz9Z$m#3>JHw55V>_`!1Xb@Vq)5UT-VBe~5`n0(PJ`{cU`w6*$v7mXH10JCsD@RnC z0J4^SVN+eK8}4{)MzVVvGZ``p{C`xPRa+cd7o>65;7)M20Kwe?K@(gWg1fsmkYK@G z8kgYi+7KKXcXxMdeDclQocRU&Ztb!O&s+sLBj z%@-#vW-D2fwu+zs<)b&MkfeGTvXk^@NR9vto;_p0O2boou;q*e^T+Qcy1uPFs9fS0 zaC{cyYz3H`W|CQ{WCg)=+$!s5J?f+-%eCMhgCz4%Jg#jrFsl9uA~PadTnb+vmcll^ z=|qqt^MQ&7arORXz_HILgh(S5z)N(u1BRpg-GW?{W{{$jeL-ux4 zOfV~cV&K;~aQBf14VR z=U0~p!)7XL^w~S`%AcN^)G0yjR}U|)*FU+;_ly?}+NI8LgYbEMx>Es(XVZ)3qx=N+ zj$I)j@c;mBR)t`TDjF{^j-4t|HL_4Nb3C@w{XfnU6E4RU+i%Y zTJI+s0FoEzerfIuHfcG#@{xTwm8dlkO*?{ab$n zO{HAk0kNts)^^zplf26Sn$msZ znoM{Aj{T>1#@c4gRVZ`k5Ov_K;Np;q>MZza>TQ%Zw={5dU1^-Nktm5cR-4?TMb-zd z=l|(7g^aK8c%0XE&lLy$Nc-n+b7tnvxxR>jL>-Tm2IBefS5Fw@RN%+wBL0xuldhT< zlvsai`VVaR%)Oy_r+4fJX(;)4n|zpv-NyZ*6DbEi*jLMv z&i0Q(#-w9+&cE!(P~OKskKo6Bzt%^r$<`zL>sRz4~Sh z{30NYWh9jd#5m${#%!1*d0siO9Z@ld3$+>fK zo~`c!$Fom&l3UT*5p@ckx6pT)Q%gJYQNJ60cP~OF2SqT_APV)w5Y2P*nTixHom>|MkQm*HV(3XgI^{;9&()p#~zl~iP0*naHfyX zYr{RMetkqQfhDG#UR20?d${xJf#5{}XOe2^O@#-^W~g@OI`+!7w< zBL=6rSvK1D%$VMgT3*kEBoh}`g-YuPM1Ue(0jD={ec$XKcjkH4LGNEJ6NOIgH7~$L=Q&6gjj592< zJTAiGXuLdby1bUo<7;z?5W>q5%tcgPl+*;@(YKK@4cLc9ZR5E+ zu~?w90Q(0>gv*Z3d05KPNk@wCc5f3$g9pDFCCFv#Act2VOPkAOdd-$IP;k)LIbg{qWc&DndE` z{02S&J_Hu`Vbt&}my*3kDFdF+U~NL47l$jUU))6>V@;(eQ(cc(BWbHxLXIKa{t5`! z1Wz=_36(f0rBD!=ZKYRE!0h*R!ZFdw#lHqa;PTe8wSAv8S4!}YO z*=t;JHgz>I>wp_rjWEfJ#Dp{`GC%AEt%2$+{4W_U9#zS)%t7i-^}vSV70Smq)a54Is%6Ui+mudTt0u z5rU9gRQFr`^Eet(6{0t?P?AfT2gNXZY752EX^^wGCUOyY1 zOtLLo;v{pQd&ZYxzph+U>xx9=wO<|qKXPU}MhT%S0h37D7dbQNh>==j*L9~>^|WnI z37Xn||B-6md%mj>dVF0?KHGb8I3 z>apkiqw*ji$K!{uKWbDBzVTMfRLm%aLsR8wOY@6?8T@ZVDnN%pqTOXrfA3ov61sgi zkxycC@&te1+>({hdvD^j$jBGfUJc1=5C^3-N5N)i%ul>)3E083xN-%-;JCD0K6Gt0 z7D3w%rg)w2%(;w>e^A3h;KuvYTq?$zQwo-x=oIw*NDnj6IJn{(!P=`NQfvqZlOSn8 znMLmky@Acnw$ifubk6IpOCFt!L_JZytR`-)zJxiahxdJqNjq}j`oh=lJ{iz;S1G-j z;6X6bZuOHtC5SABMgNE}VVMO_p6XsAJ+fhQ7=|>-{a2=h41K&zjQ%iNO+o^DOBJ?y zG8`vudmbCr7B7ZRPhPg0_tMb|nipCLD(`b}lNsyDSCTC@_usU`D1I~bD zce1~&=*;Tj$mD#;F5|09517Oz{nF&WQ%rMiNuUkei-a}tQ0;zvs`5Y_Wucy=X`*-y z5s5JHh=Z9Lj`9XfjAEUS%|s86Tq_EVPAH1a_k0cO9Knqlr4iZC4NUGYX;Vft0}v8_ zP2{lONG4dCOemIcv@*Ecjd7%Ss~R^1!Et!6S`X4@kM`aW3_2vLq~QkDu~iFprUPfa zMeO`OL08wppS(k7_-+9W`~2LHpn(0_3f)+)jxutm(^FK(^Ml%k7`|+k9wh(Y-&*qB zk&t_d>BmdYm___mG^#+Sw;U8nBEIb(8sCMM88`Md;6fHsgBKb?0x|HJVQaex# zoZvB?C2e~TB#Lfp0C~KXaCxD9GyhxW?V4U~yLJeGyL-k$o8F6wJUlu8CR3w(+3gQl z)|8!qrQ_|wzVJ*Z2Ax9?)w%I75I@(7^AX+^O+uhMj~tZA#fG|w7>EUZD-G&=NMSIf zY`{p5w?>;0mDi6YL+>sZUec10BK3;m}vmo&LQosRcnvv33TW}S1KxJu!kXVxwi6q_d zcdYG8$_Lz0BDn8rZ?F%z7H)LWP&lcIFJTJN?;nvn#~aA%X*Krgjar<2BnDm9%W)2s zjdVsvPKoK~_g>C~u9xF61c~8=2Df4$f1Zlgq8#MW3pJoTOB!!K*^f-!oeP5So#GwHzzK=V)THd#K*;1~b>c%&(T0@|pAMZp3UJo9EE~-xMex;aovpNdx%4E7G& za4l;*Hd5A%bOvAC>&^;y$@#Cj*mYZzQ+2K_RZXN>X_QQOT@-B2d72r6^FP%Olb`2X#D7UJ{vKSC)K(Q)5%WD7R=XDJQxIC7HREc`A3mc5GERE!p8 z6WyMT+Ol`qk}6I(^SMl=+}IL)T>kN4<%t^l6tZ=jHZ47A7(I$~mf zYWYAy2ViK_mnlh+5os_pf<>NKIO63TuR9@Db<@)p@F|8j#;Ckcq%z`w=ULRo!rPVI`0IPSQ9BeqOYtQP2iAg&%rw)Pgu3^fm635};g{Vt?zMVTDMcDv zr*$RvO=chR4a0t(nzGYpClLy+nCPhk+Tai=^YUqF$^#|Jx{X*;T4xN_+Ha`IAPlC~ z@SR>xJ$R&C1uP%jR7-k)6!H_OzP^{EaoP_oF3)4lAm|g)mHz1>2#kAUxcRNxPyPZ3 zt4W`Mv0o=`0VBvCO1hZ2PSo;?%^~&tVTS1snWn^NXEC7!B4*lNe(xV3OA4HBH`+mh zLRK;!njuBW2}+zyxl$u1CTTu%>mac<(MS+P&-LWR!^gSG3@X5ye!00Lw;=rSlx$k( zMz+L6qKEzGo1foq8gv1OaomRXPS!=>H&Dmfymv7UjN%{Ka z?IG3i-TiF!RXwmHIQ{_o(C5nqZQfb1Rjt-vKE|f7_WWkluQ#Ez9OroPqd9F6a3>Sok9@fbxCixf5S+4mk29WL2UYba-j$_gO?AT9Z8?dvdi3P1% zwX7y|U!Yk-AT-PFjLZLtZ(w?v|G@Yb*k3T3{XwNM&B{(|4^a-U{aD|&#=o^NK_w4V zVdUAwaqQu(!${#f0I6vQ46vRbi&0S4C>nTvWMRwp0w#BKOZZq?*J12Nb4dqEt*I{q1FCffht%PC>^d_&{h4mC_wbkHVN+Z%%hh50Avy9|X zV$T`n@_DtdQ_4v*)#Xp$3Av5Y#bXBx@iY#Pm}ehwoeybylKR|^VKp}$B_N4beJeBW z?Yg(fPHn@T&HYu zOg~#4*_mwl%NV!; zyno=n_NMw`e?#EhhXzXE*p2k8tmJkWuu=HAr^LD8PA3X@N z!58uQkB1--^v+QuY?He!lHwF&=ap{elZNG2JYLN9*~SrL&YKh^yc=Pk;v7#RDmQ$F+ilKYh7a`6II6Xz20S`^jA_dQOgxs^XOH zX4Xc#^*a~efq(``eYdLVOnU?M<;HvL8v2L^w?K`XBZ$L8&UZjEJSyGYg=`(@-3)&~ z8;3qORvS4Y8)X<6U^>QF*ID z)S+7;ED`_0(S8RgJ_L3EGdKhXoBP zCX)s(T;aXyrDjX6d5aV3jQX(Xb37%g$O;lrMe&=8EQ)AE77=_TwaRWPFQM@_YHWXF z>W9jQe}PR_GQTTF%Ct@QfkML%n^s&wbh1TK&+4 zJm8L}8@XhnA*C-C-ndx**{ryts|4q~2qdux{DqQs|?jeuPdMIWS4y><7z7Ge@!l8m@6 zCas$U@bUMSQgT;+DL?qlZi=x@YUsdlhHTReZMzg-5V&(d`pY!<3Sqk-DTchP| z{9#$2`;a&gDyV&#Ys)b?LIHb-!)3pr1hU->{1VScVMZ#?<51|5>}vh0Rx|2B1H)E4 zorzvt6K zRjD8L6du?8VeVQfb^itTyv%RNb01W75B`Sa9F7ee0zf#Nh)4jfMxC@}jQadecbM?Q z!kgGGNYRFI--MDq;{EuodjuVq^WKz3uH)DVq7MLCXZ^}NBSu1PT@RXw%!=(cl%oJY_u*)!`=H z^J_X^V)IcS!Ucl~J}S3;)}w~~^2Zeo`UP>5qQtH$@Dmj`dS`}$o!1beB; zh`|sfv8(oDy3?mdp-O(=KI26%PFG?Cp>=C;D(eS_2%B@ON|B=HuBPE09+so;`OA;O zG;yxSfcif|g|b*6tnya$Th!(9-QO$&jY=1o0FH2qm;~GAL!s;t1m${Tibs9d-)1#Q zZ%Gx}0llgQbncrrjIoBz?shIBG4T6&HaK5peKl5Vv~N)2wx-#Cp46d2UF0qW8ru+K zIIW^!1+>VsN|+0$no$c^=w_KWnJHtHe~oN`AG~&wf^7y#4uC#pKKGoPF2~X+`EmzA zlG=YbbE6V(8LF3JOTVu32?*g=buT$;XZ{md>;nDXg+qERYZ{HDoOL2xD7Hj=ZAM0Q z52^#4dhDbq{ADq!bEwj{ATDnI7oG+^BqOoDw z@-h<_h&kqvwZ5T}!WDA@dq3j^ABCn9)KVgsA;69km$BYD+(IBZwgD%&PKpB2pJ=Ew zp>|%tJJ6q2cQ&@aDg#X@41e~fj=)mLS^V@6Au#Q$$D|`=wzwAW0r#ZRmNFbcdyFN2 zvKZA!ZhcjKiO94rpvPgM=|p@9*&j7)`>qq<4x$x>-TWUI^FIyuEw2=NO!R$@`t8B$ z!1rY1?EGY}tK?q~T+ICWtl>uXiyv8z_d4U|8MDCWr=%nzXuNjRw{pY|&aVP#<(WP- zClwzqJk5>yGXo{{=U88okEam61@)fDRsW19O}e z2I*c==owm3X=+V3QB!DKCS)*Z8wk}{)f7fkz}SZ%`aGqkED01xmNZLLu-G?Is4H9gS(lxa^6BY$9 zvs?F^=px_0js}CUmg>sJtvh%7znV9NtMS%hPHgO~r?{dJAcOfWe@E?AXTHnSa$8pzZ)P~nEd@i)qSmGf57^bvPYB@C z!tFtF|1n8?*dFw2MyHZatKd%7fXZq|k}9lMfeJo&OG!>1Ze#{C7Z@km=h1jc5l~@u zI8Obn-7qcmcb{YMNz4)fZ>5F0?GOf{KP{%X6v--(ZSN}8skk(~bU_cF$ao{>0Yj-F zygVwV>21x4hrp3yXt?Je)_igOt+E!;eq+wFt6iH&h}>urwx-h@Dn61mn`X+O|B1B0 zz_b?Z*&yrTap{*-5(iD(%be2y{;CtD4pDKXJj-$$OTdj4eisimfqZXDG^YLAD4i8iKlz5MB~5jkc%$29A6lzA*@d5NrLR$qfWG{% zmeu9DYd=U}A73g@^&=~m@;~)_)^i#T-s*vUXahzL{KR@Kcf1^0lF1N3*v3Gkl%lFe zOz!w3Od_;7!y(lDEZnPt)s0LBt6+VJqe*+VT4p?~qMddkaQHBqv+?Feu_w~Kf&K*B zq0PN%u{xJ^Tk$~jeDmDj;<5i`{c`jqced~#!5({Gu;xodhkA$a89x(+LbK4dc_R$& z?t1t4bu{g0z6*i;8z&70lIp?;078{1_cTEW+H#qX(PNza4^ui?J8_0UpPHJ9R`vNW zSwTcVlPioZ$j*96TAr9Y$DoctQ_HE!qK*bx&No$$+w@6j&<^*qvk0njYSYHHyUU1{ zT+?X5NLf1<(v;E^-0S?UunDX^)!hNddrD5`e-{&EMmO@mck;mb3*hVV+Xdo7)mV81 z`t(bBo2Pf6s?plkG~=0l0E-Bo*}<2WZMcHt&Eut%`;m_&m7=&=vRZ;mNqyJ;E)`@i z`reo?D>S;Uzu2ZrCiGAY-W?^Y4KvWOj$A$W`FyDBDx@f^KH+R!aS(0>e8&?qL%1R^ zvfJ#~sPXUpi2CE{Ym;5oeX=o;oZ(`}-Y7<*WnXmmi@y)$cm|7|>P-In>7QH_K zk{hGbR875H)YNK+jhxP(5!Y$uDbbJ$u*(UFA3{umm8hC2xdhcl4YxBz)`4K2crUdU zKsto1!Y{?g;LHVOL$_g+fJSZ<3JwX|#hvpOBFQ^TdHdUlAo7GG8-A?Vh*c+)>}2Uu z;Uhvz=@Xm;?M=js!<6l?nPe4oU>Bogud{-HIJAb?Bd^QodX?LIol-zXBmLI}1G8=n zN@3#&LIdC;q4G@aIqF2cH-%KT-TVgQgc<`2vL+btWPo_`DZuBZVgjfTDOepF8y)ua zk*amqfpX3omBi>kq0Zn__8xvU%?Ua00OeO_giE2HVCn+3*QJ~*3H3 zkPX7VO3BmZj?xub(IOxWnVw~1WWA)4jqDev=p`yWj5eM9qS|g3{ZtAt3+?Yh%n6II z0ibe+8qP26!Humr{5DlTBqk{K26S$xI+K+i}xn_O?q#Guo~*y+J?LOPd%%%XC|eVAK9; zLW~9Z#GL#NO4(H!=%P8dcUXruY-@a$RT4SK9<$E;kCL1z&j{Lx;BR3)AIga;vF~Sq zufzOG4n0kTaKWZ2Q&7O(&tDyF+zanY6R~fRFpy!3PUeZp;!h#~KPQTzwdMVrsd5$n z4Zgc~p5TO6R_JxeWBnq~m!zJXl~N*XG<}w?*3AHYmQQ&el1lq5Oj0!#vV9e2V1Pui zF37i5gASm~F%BR!Q#_goz_d%y--K^Y0#PfXd0I|Y-!GKM-yH6La`HXjjV8*ddxP=! zG@u)-=&=zK_dLu7E}{%&zpGd|%Y5p}mSk;#Z8{+*8O;2vzSJs)D9lFV4cE8u5ZK*` zT>X!_GZ$We_a_lI;`N{6{8j;pCwXL`vG>^X!&i*LMC|;N9117;ub1QnE7e)TpFq|= zDRjMIc1n=LC}-#SQQ0E9T5pa)l<-NceaJRrN}TIvClN)iDFUc)#AnW8$azP|H9jO+ zDOT0*7crm3+T-`Dy|ph@{fBXnX#-iE{j=kE)PJW5eBpWFChGh~GblFujPTa;?)>=l z@`CG}9Jxb+WBp~_ZQ;CXT-*F@zClRIuD+?@sO?=(h<)*K<{8C%Acj3uTP2P_ylZd| z$kyEeP1VCI)^-5SabNk_?hz<5EnM^Mp)uj0St=!MT-KfYOSXQi*Y7yiaE4uTZq1IW zIGsrErpvFnAL?J+^RlkP5jb<|RDzW*|9LTGo7eBOdvsoQlLe;kl z-&tPi4U!On-_2h>q&sXaKbP9D9Y*ysqT8)6cQ;JhaccUJ^zLhfB$fK@mQ&Dde1qCC zv>sj}^@=Sw89sMTb5XPKx0;Yj(XjC%eBawt|9t8gCW=C}5AJn)>gU45$Hv2XNO7Sk zhfy&}0z()voh^gD@DIsyIQ`8>$eQ%i#58?QGGT*$WGGu@()dY;QuMRW%rC#mt~H`K z>?}KPQTSk^AEvRj@L1j;QvXchpA@ua?FJ0{DtG%#h~&Z4a?XW3@2u?Mr}B_Fyo ziM;YVQCw0MiKuifL>Bft3W5VLypRwL0MU)(*YD2ezNj&HdJtM7P`9i0tWW@xM3$4(Jny3w7oiLn10OQ69#G8lDN+W#_Zt^>OUyYTQIjh!PQ#(} z#!&`7(J65V;p_BpYQ8+eo~cP|+K$NM492Rv{swTLNQ`Bu7#{(b+43D<0DHN2G)+=^ zC^>2Cm+2TQj+T7*JnjJ^V3K#pMMGj|s&2qlZ+KbCe;TJIBP5@5Fb%G0= z$DExb)@d|h5OikxS{d#RL=ki|+KVrOnFJsV!MNT7qLoS1Jl0umeZ^mUP-I5~PB`KI zig+hzPq;`;PVZKm$6YP|6!Y0o$b^xA5hGP14^n>2w_LnJJy_OJY^t|=CFhr{CU`o@ z&lA(@IwtNmPUR}BUJH}hoe8VW%*DKQKNMC}J}e7bCzR~HbD|^@1{O`G@!(iKme1;G zmah4!V?Pg^gpSRbmBgjl!tXHL^wYc;y$%U2e~D(jaY1g#d_@rbq2-~}F<}L#E8aa^ zy>N5Fw0HAw`!FsuFx+FDBVOjEe}o7&gznWmJau>WJvmR`zg>uYc)~ym^mjZ6k4N5R zzho~rq5rHUGG_;CrqjYY0dxD?w|L|aIS)58hCt_UN{F{W+BaVTXs_VytXR>P(20MQ5b9&JK zP;b~O0$0y}R^`1tArabKV!hU302K?do@d|XXVKD`XWiw|;gaSW5A#-$N_Kwts`59P zeX}$o;TMtX3BYJm8OOSQZ;v6pW|(sYqF+wOhBBdW2a&mPo_@feIqq7Co`ZqS^8~5K zA}aFO*6@A3)=-||pAmmXJks$KkKX7aS%gG8(JJr!nBz9|%VgPAUP6>xt(sJd9%4_S zIK)Gg+M)FoL2W8Ke4_|L=Y$ye6rw7vbG_9G=DB6-*OmRVAWHo{#}al}X(#7m1BY(b zg#KhQy^UX0Kj|+ivLwS{kNeiE?6QGld!j>09E&ZL@ys8|)PxDl(h1g5K8lcj9nf^N zbym|u1l-68>Hy_a_yrKL*YN0s^LKL>r!~BHJ*6#^QeJZV@*9%}<@rGq zO(E>gm=X;;nYTzq6(wtY(kd`>RngS&nD0sLz0TaRuy`ajC?FnOlbWJrWPh-;99UpI zgL>(JQ*_1Hv=wBpMoJW1{TcSN)aLnP@vrsh_hh4HW@FEVtM>pOt(#vh3-)+9d3%~9 z?fzYv^>%cIPXc$OZylDx(KY!=$lNPwc+lD5&hj(<8bg6~6EYq1bCs3fMNT;-27d}Q zzfE?#6h3__h0)WM#1;uQbw;9>k0CY@FHhMsV9J_v{(JQ(;sGOw#X`4JW8VHBpAqWJ|pg;w)z6QO&biW7mr4aI;O8i$el** z)EnjUS~I8TvEK1M7n?c&s)7^EvKmn1^|I^B^=#H`RU)h_z#eqaK7D7Z4PS};`Wn3UM4ZF3 zCLS+fWJE%-eki3a4+tW5-EuR|$KOdwNB?XXrf8 zn)$Aj^KRRy%`4<0;Cbj}(?Ik@XU!Ndu1;((aODD%2PZ^+_V1&TwvW|V{DdP^ygHV` z2L8*-4L(`cqL4(l2Vjs9-*B{k%OWGa!$iBsFIVT02fsQ`B@3mz+Lz*4(_+7HI8GTu z0JA^qy!{<2Z-4ZiRzDSAJiY^B099?4xwjaLZ+9yIih}VM)_>ld#_z;~+A&M6M~tR7 zmzO=Xzi%RM>^TuNYxY5@IQ`icQB%4 z`Gs79)H(jGuF5#jm~weQjlHxsKPGr#EUIfO)Ham=msxBIcO{<^xHpkw5#0uNVw@Y(3G|@3wZ7FU?_AE!)^Ztja1; zxDA43_VHb_e~g(J^~0O~|6CUj_!o#^BiWdz`8fkNRpV>t1VEXmt7NRa&hxG*agH z7mO-zh>8$#`NU?PGexuwDaYlVcCU+qo|~iprC;v9meJ}ojVLeOKam-!a6#uEGVH)` z=LVN&TCrsg65qB%cOq&eC;aEyHgPF)b&O9IXZWXXKHoPUF6qIUFOO&=M2)*CqKv*p z|6$phS^v{TRL90Mr4`)o&*f@UTOozj6L4WZlH$~U2osUzf`n9YykQ3ZLERvEuDr&r zG#r8x<=)RP4Qbe!g61u1`5g4%!o(o6`r-^gaEkIXf>A!<(C~UN3;M}8R7MmegRz-5 zK*~R8JewwKFu!llex!f=&W4BMv(I9u4EwN4y|M5pFL~5o(WpA?Fx+uzq{#qNw4;_@>$*iY`8Q+Fo77CturK?E9JB_S0Nu`)>9l^}04uy?9iS{<+m)NJ1G$b;*sXGd8X zg-Pefc9{`KkfKT`OCoY{Cq6&zmH0XvtUt&MH-z8b*F!d$*(i)lBeFS$0)$BJ~y z*(@cp-jKSjI*IOrU;nJk=)ZW;Fn{Ng?udR*aN9VoDRYmue=kOmXY34+Hfe7@Ea&%M z13U=51{}=z{fBpzoPMP{?mBho5yzv7D9riwnjXlq7w zur|fC>lO(7(mT8V5&|;E-kDqR@h>BsC>M&^llxSid*96j+Zv_~k+sdD zBRj=qmprY;tM~ci2UBoDW>0J#@{I|HoWJm#K~}7cG_J=EqaZWfr@hbfB{@~+Km#ukU#^l$^PjIDinId@D{%$mxudl42MJhmxJ0^_0KLRNPm4Pa%g z`bf3+9rNq7v-UZ03egK(I2$mvY05_EZ~e~>tYGtx#|-exZqYgTRC&H8)1H7 zSs`i6Bld}?aHn+ocNR*tyi+Ln?P#RtXs5kUgM(*m#Zzn>9Rf*e>|f^ptLQp|hyYqX zAXrNM*gol#Scq9AN2pAA+F8iaOSh?*1R~&-Wc}@xTZm#(_W5$&ZP0UNcFJST#I{em z`D{-;Yf|gCs-`dQl9sj=M5i6!e8uA8`7t=5MHx%p{;~t^xA{nv(Jc7WLyHX-E)$t^ zRjci+U-ow&l52xOL3r`Cs;}+5H*)|kFJaG_CewUV1HpWXTw6sIL<|kBe}|2AMXPsA z<@opCs3@Q+Vnv3RaSR`jGhEDlz0~vhc48zeSl%CAQ7WhqMW=x6K$XN8-m{!YQ^@ zbgP6_!kQ$hTOF|n>z=?>D^8TZF&12e%-XyqV?<~M{ByC6$fBi!n&ealb>3I!l`#pi zJt*6WaY+Z4bo%v9+oW1>gD=qg_S>}t*xLIw#1z6@f z;Vu_M2=*q+RI3UgqTvL2xB>gVx}iXe-ys4F5+Ev!MrlkSw1~cB8YV_Jl{ZP8p)umBw6i08;v^hA3O5c z6nQqEC@-N$Lcx!rkARK0jXR#%$I30voij86)}HWMqvb5i-OqWo7mXvr;-e~;N)&ur zOFst*Fq*1~esf+k0MIcne~_wQ7$sHf<`n5)P2XtpfRf2ABV zJJPp{ifahrM08dhJaBF9T^?=6$@8%Y`snuxPFQ=_R%bh86su$syFoE1a5JJq7FDtn zf>ZnSTkVBqw)$nw=HhifHxmELy(-Prg}=x=Ze$WYZmjHEZoaXbUtDe|R~Vh0zfwY} z8uwJ2ycMzVLSA&J5mNuGoR)dFi0`T~#4QSK&}FhF_^h)VGJ_Dw4c!zL8NJK5JaMph59vz~>h?O* zfEw=gaFbJpUAoDRa@ALSZS@h8}~p)OFBZ@yN!GpD1)y| z-ryz>GOQzO%rCF6VrO3sIrW=5P6#)d5-t&p=OLK%yhC5$ZrQ3$XLD%?I%eA#<(o8w z^~11Dkh5k{aqa83(6O72@$;Ceiq?y#J~iYh?#;Kg9j$f}B$Au9ZZKRExUKK3*i)`} zAws?)2$+(WrG@4<-yYRPz#C3~`rJl!&Qxo=+t?=32$RSN)2sPk64f zjhkHjwWF8bBOD~PY5DVq6c=32fUwMF=4Dq5+pVz;w4qt zZpDU-!t%2eQ6F%z@K%RB12^=v&ns(GaRu1deKrnPlR<-%UC8WXAxzrFNS7z2-E1ik zZ{D9o=t=uEeicn9!pC#Eo8O@+&J<^|Q#^f1>+5X>^~%CAA@@{`Ec_f#8=FmK0TWPWt$2&s@(;9FrLIZ~@g6)#X{}8%7e)y~PUcRG|Gydn# zhv|CAX=Z`bhw)stUdY9u9$0}AnQh9xTkHL5R2BD+@=7uB*Tz-EOyT-9hCS|OxTny< zyFx$bVZ~D)55r;8n`DKt>umuGC)XtEKWIx=Y^)l*$#W%_!BUEIh-@mB#q3o+n z6sR~(Ld|+m`fyqzFSAq?b@1M6>)1xWOviCz2)s^dMHb&MI168F^bXAZp(Val6$$%1 z$mxzRRe!4e%y7{Ck1YcR`aJ(LST04Dw&I{MY!INV6MK&<5U>G1bfB_w^W6KtGlwf@ zgILTHsk`%C*mG}RNK-K^NicbWRok_N=@DE)A2r7*@-Etq_o5l-OSRN(c&F;8(ouCm z6qU2Ov9aF2Kd$*#%&NUgo@moZB_n{& zrj67lIpe*Bxr|89ydbcS=li_NsEFo?tYQBf1l(BAxWhTS@U&t-4HlHyefKP6gn9YD zu?GL#TPn6SKvkz3hq@=03xX;t(dScyE6wy+r<2ESOE`D!cY@V(1TVzTM2KBA zs|8x{qn4%Wc##b|8zemfop48@%Ai2oq9Lm;b|QLXsGke?(! z^349Wt6^_>y(`A4Dvs8PNW8(tk9QeA04!2jXn1cv!Cp`5h-5i|->rZfPl>7iQFco? zc<+(U+CY@(v;__2{5K8o%Q|@}GV=ymoQ}m*!EQVnl9)#%xZy0YJc~as97IX)ewa2G zM0Amlu?6>0dP?n}c6~=^6fu08UQ_+gpvAFb$gTL3%=E`3H$LH{4jfuW)MLcX zVk`paEvlN^cjR`+s1!feGlUarV~?9-m8uWY2xG)sZQpm2TvO+G!sGVNuNmAL=K|HU z;Yg&G?)*Qyo2zL{ zuG6d%yk!>^(O;ZnRnD@)bTayx+|0*d>_I)$lg;W}=R3Y-0`hHEqWRs)p=Z5cl0CGy z28S!E#aE&)oMxB`J2_D8RTWlJ1NOD zNt#)^<$)sb!HvW_G~uPZ`=xHeW?*|J-|@^XvON=X!c~rp9pba#(mxlFf>C}!#z~mJ zSN%rn*Rm^)1BI*}3MM%gh$zz))C-VZJNa^2S7jfaZ{#)H;Kfs-_{DzZ4a&hsO+P&7 z2xqo@H+qF87mm@u*dwDWW0Tbs97dI=k2Hg65R4f9&e}kpb6;YgT*!`y#AS`3a6LHd7G%`Vm5dV zu)dWAy8f3d`Tzoo|K`;0Y4uuPGOV%cGFG5Ow{EWUWL5+L*FWL-Q)-G*{qdXPba@ko zFN+KT#Uk^H2Z?>&R{j0CA05|Vfrp>hrtnSMbI-H8)2~@v9Z-5E=XxxyDW*{^!RSGt z&gi?5$T3@eU#qZE{a2u%`5_9k4QAmbY^yE%z?t#NYev2li5rP{?P418kDvYe|D_jf zBjzb!^ZpR*c*{oZx8qXWrL@y$t?j~J&7U4OJDa`d)5kR)<3vWj*%gIMFhRQNe_fiaGx2s+U7Hvde9gM z5zDb9jS&+X>xq*4i1a;5dr4s^&=e=2q`5!8l^`ZKf2>E9p7x9-Nd#zSl3$i+!dSE1!8$eOMZF-LRQO(Str=vDauQZK4o%3kisOOP zU5-RNxrt*A(#p}gX$YnMd80yhVFwTQtgQ}#P5+MA8SiT1BjX`5;OjYyHWJco4YU=& zlXv%#H%imy)e^7^%D%f=9P^rwRr+*ZAty2N>O4Nm7C~Ze$QON+Gpz zH#7CGAQ(#-*Tcr~JO3q#XisG`R+ZFVTuQGz9z@SGj;oKCgTQMcNJ>Eq+q##Gcyft1w3-X`rhH69rC zMd|1?K<;`QCyz%)*@+OM(<{*glfa`}%g*DN;0~Rm6UIfu3E{WY?;D>>XxASjj4xlh z4n}y;)V7ZvV_YgGHoQ{TcWGkcz3vmbbFmPX$9 zk#G>dIC@O?+O4#~*MI$H>&798%-FCM~e<|`UkbpoAeQbycC#7Dt;Oj^{m zq3gwp9*88*oPCVlLA-RO{O7NJTk)Gi>lTRS-{p=pTgz}TnuysXyB(b#jA0D8X<3AG zg%?rLlVMtfYjdAW8*|C<7!Nt*h5Ys&`#i-#?YOATe_-`Nn7=Z%gxo-EG*+D_mIAOb zLwQ+Ocrg>|{FhB75B6;@h#AJwtTUrqX=Eem!1N4I`H5zmX8%U_tEqo!|8txewi64v ztSz<1aE@1fuoo`M^B45xU|?BIl+L#*^%QBY9~_J%Ofj|>scR0ay)DX8_#`C32YW)! z8m^fcx9Unn9B*}_vv`%8x^6C@E5EhOo2Dmy*N5r`3$>DtepHJ-*AOD5ue^63wQ?*a zZoRM(a)iAmOfx5FGnu{Q94$iwW{Ju9p(`Xm{4W;pAYTR@2dlLsKE1F0B=Z_nA|_;; z%aBK8m!XZLrH-vjcUQPi0#eu+Attk4`Xhx@8-g#a7c>35u{GWW0=$Tty(G=vf9yWK zPj8SP77et1Y>^h?p3jduAn8|a$do;Z1gEdR^mA*N;kMp5|5GaOdqZWd9EcxSR>k$Y zG1+@=E&kO;B7TTI-OL923p9N|o{>8`S%A}8Kh4>Aq+Pb=E6`pq-F0xk7inf2|saWg+hh?3r69jlvL(vOIIj z5g}wvF~D#S|40iLE9kxnD)vG;)E83#*BPJak_QfhY)p1XJWNt{9OJhc+HO$%Za`ow zOkX~9(f{f+Rhk9(z@%KQw}Y;!;UNotG|!aCatQX|beq<@sorJSjUtyhVk)Ph`t#m3 zp}AlJQ)tYHnWId>agA)RGD7#;H)5q2;vjdqRA~I^IzZdOHQL9uxb~>M@w=_>jonn> zCfQOMqSkJ;(_L}2_7f+1C<{sZ@%xR9jKRAP6_PB zifZ6fiKAt`%(238J9j_~Ds5~bCaDva%a*k{FP};5yfbGA7%$U6Uu*WVS>D>XRCmh=;xPQQd+@mJ|QvYovgmqW?hy>!L2&<~u6}9gaKy8-@NbQ9zHyJ*R zpHm4)zFpRtO#H2jxJ>)1 zjHsByn+s-wt2lcE?uJ(vV3N4!)WJST%N}0YPxb$-mI-6nYl-HBQ4k}plKNoWMu>%b zC_g~JuRZvAD~NQ;F~PDeo5`=FtS9WE?SBpPUf813QO^!xw#1CLo){vFSk}p|H%!s} z`Re%Q4ej9P^-29ZklAk*2XTz=yf^6`V<@vrk3T?hT@Zks^L%&yHS*+x6=z=@U_jo~ z)mF|3=_H;%2G>H}Fn5J{^C)ge{cUA`dcW*o7laz_bH66DQJSpAlr$c&P4xehD|qgT z22xwmRA>G-#s)|p%ouSpU}nV>Q<=hK=mCQ1WN69!dx#st*0a^I|51(x&3idqwl;Zd zouxb`)@|~6>iXIKUpXd+Wu5PY>sgkiNM1$1(eco+xId8xgP-PvWQr2VQFjsb>ydS)#AAEfD9HJ5{n&%dXY0i+vft^)5PKiD0 zGC)vBwuGH+y%A{J5P;yW>jJ4KE}5@m#v_7I6_`xw|+rp5h9( z?U*`Uu95C93kLH+<&qNbi5}f{TraP(erzSsUr_pJ=DuAj{)diFmFwZB=N|~fH%@py zF9eUy6*Q`Kxdnf{%Z3!fmi1aR!kWT%Qj8WJMfauiXp}Pf5yc;qaz-9YB$7{b)8CIs zeSR^xSxlmD^F*1@z8bgQ$gOAr)}CNQLoNvwJ|qhyLKP5A< z*bIE&Q;N#k6QxT-4wlnk9Ie)C8f^8$9UKJX7~9HR7X4D{-w_~?WQ!GUBYn9ygOR(E z3gGkL?{X+j-&XtSbrXJv7_e{kuN+2wG&lVSld~&II7#@}{CC_Ig_?f>q3Hjq_gQr8 zcX0md7|T0XGxw=M3xRLt3%TsRk;Q&$unxJ;YTi}8Gs!0wu1^g;l5T?O9wFx&n0-l%0sX# z54}FoE-9m!&@^*!H1v|$!38Ic4_j?bqoM@~E^@1;AnNPbz`3&;zj+Dde@s^dqRc#@Sb+I28syv@$e zmm>*alAM?Pn&vsR>Z=xNUh&Bq{0A7-u9S%lvf=IH`Za4BXWA-v0An^M$^K}uf+2td+XW4dk%1q5LYuYc` zkLYS8*V!B{IbN&?cE`LXejLBQU`K$N&-tHz-pRX0INIxi&$EZWN%*Bn{d|=zybZCC z_n^WJwa$kgDt3(?R2G?iz&7ycRK=ojr?NsZf8OnTZ+TztDC}552<2Avj2o3U;y+aGH zZw9xYz2`NyWitoEZyCGyhwd`W4&e;DPn-1r^{0QEvl9&isfS&kdQFfQZ-gN;ht6Yn z0rrKQ{T9`SkAWLPqc0^f{7X5dUXR{6)Tv`<+;O8VwR% z&mndvqw+*M3MLV6wzR`9rZpGOwoUu0V=o9@-jeUNa%Uw7Yx?)XLe6&{#RSNPB^`99 zTPZA5|DNnlG0|_@f`B0nfw(D@nA+8u9$B{n>Yr^`!c;5qIaG6RI7j}pckjy$wHxY7 zpUWDYvC&%MKomT1iNDIDQ?-qJkn^0E{)7(KZ)<~JCR)VcgnBg}oBjt+;>i?9=E`20 zpkxJH7ezvp&Z&^A7CU_%3fM~i^SLo@FZBeTz;45>Q~o{@Nfps&)N+M-o(=aiU*B%6 zFK)R88e}=XMi^}FtOB2YKBfS&HuXm+4Olj(Z`w5pb^t-cJ%{2AZ?q4YL7Dd3rZgR`}Ko^&Z+$ za~6!!`h90tYA0rpm3m`?2E(LXu~|YWY4t9UsBD@fYgX{MRt22waaRgw)d96bJchLC}BCv zKyi2d6mw37^pr}hX{%}G_&}*gZ2{^&QO+vjY*F96SIS4c)6N|+75Hmiqf9)2`gTZ(j1@ZtmW}I=X&;k%jz{KY!1L zA-KCpUR`WzR#>HInU{8mPj!^VMiDaUOvU@;R2&UM*!AR>5ya@zr%Gw}nCz1`9|Kb% zPNOv&j7jJ}>!m&AI&R0vB7k-AU00Tg)b3%B1dciW&nmAPCnDpdXPfwRyH z3Iv5%jp)FD0U>owdfU#)t%yBiIz0SJPGoht8}nR?!SXEo)LKnwY=1b*xQu`dHlkQ)TWckUc5!*Z zu)-VIW-=NLz)VUB>G$kuM(|*u>C&GKIK&__m1nA_%s{FPSm*lR`cu=CEM5?0(3S{WtM zzhAO^?4YX_Kv?aCoAt#DPiYx$32hp7 zV1aD+N=e@gz)TRk9qq#<=yzl_H1jtqNO(Y8s_Ra^D$>2iKAzg0-lw z(~h1Zj9J8)G_gOYW2C*N?e2(q?zCViHzue^;yo~Uj{~O&==xrIjc_;|wwV2#nzet# z<$MV6E<)ONKasp`TKqO+6ECK8*~J4dC=1hHl})r7mGV z{F0m?FU5|zRKcw{48d0!3* z@4UXW0L@}T_2a+>N8_=$XQ}aI8&^SLkCLi>@ahBp4c!i1QpwG8b*obk_8pBQzpg`s z0AFX%nvHy|wDByOTo%=7OJLKN^>cAk1B4Hk0Ek`?TwhnmE-6j@E7TMcN8xF}2{00vHJPIfOS6%&aT<{HH z!;eGRgVV}`6Wmkn6O)Lz_o?Kp>dj*Iv2T6<@@U7be z2m|I4ie-$Hqk;UOCv+_pk;3nJNufNGY4RFa#t*k-e<3jK^fUQZ!YPmNEpAVSr_lk8 zb{oY}xg><*^^@}!b@-#>^rAQjH|}?QWLp6O5gb+!(uh#9Yp*m8{bCqH3clI8!OMs; z(ps}<9MJlgD)NMqpq3c|01nRjR=x07OKg4hc6wZgG;f;S-JiTg%(kDizA%-tsEC2j zPz3~r^&d+|FOi~vvxD2@kbHUYdGNx5gd^j0EF+=fDo*NXBm6Dt2);&V(G0@*c_9w6 ze({uwTst<`r64F3T$kktkM(=Ah0Cd$vZy=CZ@J@C6XTw0Qrh?xK}G;qj9*nh^O(zl z1**ED;5D`h^7Gg?Ow20G#v1a?m3`rz)tT!9MCw8Z90Ar9y0hbk1 zoB5g4$<&IQ8_8On8F05Jcp~nl?86`+DS|7>y z;%fv$7#4gl3cQ$3m1!&b7>;s5d%`^1?az`oj4E^qJwysx-VZQ|{~HQ3F(clzB1ZxJ zLh24BKp`t|Ix9=iw|l3-|D}42$L>-K67jrqbr;hM>+*|qKVRRU z;t}Dg$1Qs6`qVB#+CIT8>1!QsHxjA-$aPn`awd5A;Hx6f?|!kuX1e9-#(kp_OJmSk zi3`mELrMcgP-fwf8m_8wzhN-0ig+if#ex&oosX3~HVVaqcXN2D8u4V_oxoXI{&~@D zSWTH)BvizC{OEY>{dDoPH~4g{{J&C(!q1eu87Rn{PsYS}(87DC?OWxQpJIEpVfI(w z&N2J`<;`2fG~Mq2%yaSO(<&^AV^x*1{>h$v#>-2KiJH&}*K+}53#LQVUv~L$Qqkbv zB(@77o=ElS*irl@eT@XGcXAgkO}k|;5Cj)iW1y&MU2q&8@Mr*}(No^S7?|F(R@Y4B zPeCVYv~{BoT&pf-4Fp}6opblGQd6^J`T#R)=G~5EfBE4owj|8txNA&cfb)+TQSp0< zZ2f9i!}%~G78;)WXsqWI3cL(i0sS()L-4JR*YHYzL3E#@sj~(!+_yhTP7v=folG>Y z^yy2)0E7drDa0;8D!PTdbRX`E5RI+Rwl2=hg1Fd#1~uC;+E%x3Jds$#5mny50C($S z%xf#z3}S@LsZFqP&Da7yv~|kn#r1)80WHA{-;RF?q`NKDE9-ObLo7kn&*tRK*|qev zs=xGDs_TE5x`ni#oB72Fu~RbT4LC*XLg-(GMq0(~yZie+#$|Q<68l7HR2;ZUV|8pW zO*bE?P@X%ljH%13Eg^`Oscof>%qO&5%BdI5Tt;=vYMNJ7Cs~tj#8==JhW&CW;XzE< z;FTj2j(TOA)G{ejKgb!wa@dskz&pS)p~;h?82Q^r(-|;LxiH3b^q;`mtqeitapx^V zpQ10y0taA3Bdv3sTeyn!i~zN&9rmDRd;3KDVddWW=ZTFRq-Qrxy99i9c*HGt-Yb)j zxb-lB@XJbd7SD?_=tRujh#O$3eHAs2xVXP`4>+L|a_n1E@gpTrx#ka;1G?xd$@yE}ja251MtyMyg6xX!|WRJ&|$Ma=eD=M$+?$s|i8Hno9?3>IMJ*H^D^exLQn%i#ZK zk`UHf>D+!yKh>}=Kd-v}P|M~g5Qc=rF8^8~WL^XzZ>D~BUIF&iwfTfO{J2pIH#Sur z>i+FmDD>1;fy)JxGbeC%>}3!R_woH1gkYu~yAH;BfO*{SXdQcy@mb^6T^`P-kK`y_ zXj<|=X>Y=+TTkDjKUs1lnLN%{SAai}sjhBw^dDvif1A#mS78tUh-OxVd6ISDkazWV zHhsn4bH@}h%FZDUH6wBHojj;bUM<#PNYW97Zy+{b-P~$k?Ufe249&N6dRm zA=TQac%?3j<0;q@CCvV!1)6cZ-y%rQXtWjmHxhYG$F78nvg-3gp@^cpq~Fd)^`?S zkECKbLY^65PYje-vhao(+Hh{^8Ec@GeZ#t#bSV_=vb9MLut}_lvh`lGc{G+2*j|{~ zveB_E*qmt!v|F2n&4_Gb^0)3^McvrnvNgHFq=CmYh78lQ*knwJF%?N?#M>pl< zq4Gdq6Kf?h_|*s7RzZU!`u*TC%YDzjdO4Hd5AiKZcnrh=1AITnFHi=Jk8_viQOc=K z^g0tiFFpk>PR#{_U|Ys@5A*E4ymSr9u^ItM~2~YS;Uq7L-|{-@Q9+lUz^+YpHK7003n^b*A9`ndo|xg;(MuQqc?}%e4(lt zaR)+HqvROkjXc|i`_0_ykAdM|q>;*)4QJ^CIJ)ncT)2m*mX~D%uF`jdsW{!$wQC38 zP+F!)5Lt9i{)PVep@DQJu~RZA^9Nr_bz|6vsifg0z6*GPDBGFZ6Y#sZvr`rd;KB8| z_-c`F#he#8r@wzGt191_$^Ql_0uh|N|F5Mg@dLYvh@-Jd>1mF`qj{qXqApL@lK-O_kL0+7c zPo5zZ{%wI>FSpSz%oST7@(xYle9=DJ1a?FUwB>Bh{qJ*b>YG{;Nrvgwy(sfr0~a1s z{02j%uy0*RJq1~4SBqv+m;~|>105@Q;cbk;*V*KoE~dx<)k|MXPXbq=^Vt2(T9?He z4k4Ip#qZ;o(*5q#ISlS_u_~yFS3%N+5FGB zOJJU-XzT8{5N@*0eZ8q^`A1bf)vKcw7Nbr)@}do5IC9IvQGmbrASl{)$E+JzVPckb z7-AugYPOrTqZlTm%ED6aMy=cTxLx6IS6bpX%q;sH`>8ObAXBgihO(?lz`^siZ z6n?AJ>p`5<{O8gKZPz<8CdB03aLuI3fj=iv;?v3?;VH56|uK*+%CH|+JZyqyB%DC+rW;1 z_OTTDW2sa>NFaN&p#jhS3XsJ9@$|rW3nI+8eeLqG$an$@S&x0=LOA;>c6&x<#q4eD zui!l01B3)^MhVqTP4i^*8Muc`#10A}9M=X^*7IC^zY+jGB_py8UzlSMaF=;QB~DpK z@dgq{@OLXC^1ZyR@7M8w*CJ7&n^RzlVjD<- zJdcJYRgzgFqz48(A%=EAdO4aP{>T@#t7#q(j16T{pG+0~Wl1nkP&d9}c9_r$#TyOU zJ78KCeLP@eIRvl&yqk>m%YmTBe1chr`^dt6-T{j)8nreyYdr7Z64uT@GK?nfUqwU1 znPXa@O<@pZ!A&PWHZb%mzaxeI=Z8khcW{4AwDtzF|D@dnR^L#+b3bnj%q|ZHE=dq` z(QAX<`=J1Rlm93CmR)zq9b(Ny#rxTYoWEGQ$@78vtjZ*dUx%#{9XwQ<>t8(=S|S}X zrq`7xcou6z{hIKObzJTF`FM^9ShaVKzIwa$KRWg59mLJ^NNKLkybW7VBP+ShWh6E5tUhh5uv^vz+skjubgP~JUIsjtO-Zo`1->h{cZZ?mSlt%1bu$mzJk4_| zsE1&E)IJ%%p!qWC!Ku$9E!E}khy1Q>NY~@fsMQ>+qkH|%GX{~51>N-&ZBH+8rPkS{ z+)o~>^VbG5U|M;9hCN=pjx*Xa4}v~LGV183Wu3xazeVj;hcCGLu%*`i>WidziXz_Q zc>(=*>{i{f#nJ7{#g(p@#C^PAc+n3pE`&Z$aE=S=uW{r>XC`t+)kP8g89k#YHU$gz(P+_TTpE^t> zV;3YT7$@M8K&!YuIrjwluS}|1veNzilw)vE`#!$eg{z zy(k0I*ikNzt-|jzTql=J7nXc@Z?I8jdf6_uig1a8PJD2%7k3n1Dhl>`U{f#U82sk^ zYpQx&CTk;?{VRy5VT2b=RxRv2v3`?K0s58xuFC;F?6zP^8-6>qpPLP%(_(mp1$tU&7d&`+tT(^4&<$SAtB}=BZAPbe} zcFLe;O;ok4_vj756s&xK_eKmIb5(8OCUF%u2-F*35oMm~@jaK!5nZVUIx=nOWpsOt zo#MhYnXX~y>3j)oCuaA=2njdN(RUqFm4@^yvpw{Q#QlAtQu84je$|C{L9tXLo#R9r zE+oDrp~j{0iM+rO;5cHtM-03sU+0I1$c5FEN&ji_f-xB;LH%bobEw~ZAY5f|-3M{w zDy~HQlvzh10EC9jsL^Fh+k{G)^`g7*Ny{%OH1Ou)bV-Pa}XxLAGSd{+E?Ccb(A=BdJ8J@^5{;NIw`Ti;ScaeZB za-E6~;>*RZ@HNp2O!be19+|w?hc?Y!xD#Dg@|Rn+AD%GYVcdb6=1u$9{qwFL;AH4- ztV5xAi=?8&p}ISO@_2g>lm~SeNb9huik2^c6yZp<Qf_DR<@KkFxNbWO#G zAdQ2}US{*kAE~y2{v5o65HV|8rXZu%77a@(w?t_^pZp3kJa^DWz&nL-Rb%Rm721x^(_tUhn_-#lMeQhew!Q?xo>Z0C2p`(7nEXg5!tDf3 zCxeclky@{5n*SEYM4P|R{fvOH>+ogzh6W*Kx9ELvI_mFH;K5SiG2FC&*O&i&{v_%Z zMGkof{}p^^3G7bO?JCI ze#2~q{>N`IBssvC_eS&3zUNB4q2AHIh4Hh)*cZ+t$O<(4w88`hgfdEbKZxIcPP+(U zly;>FU>%U}MRe4`B^xxbh3bzT@T$$`*3oUeFS4=W@pxDz^O(mm=;-nWDsoEx`q=)qu zW+nV9k4<&1E>$eMblSI{Dcz6jLL2lgfcmcJG>qBKX;2vR!CR(qDT9s>{`7Tr-pKo1)Qw(0McZ4ngfJoSiWTd+#b^2z^f zKH3-BvN~!54>TkCx0{k;a&P9>?O~{%Kbc$6P}?onEL$bi)!r-|A%yf?)?r6Cz5(f% zaxFr!;9+hCD!hg}yZfs)Ap^0V^L*BTr~` zdFR#^rkmdC-1|%KmO1=bKhyMsg4e@s`>=iDbhU+sK14A~C5|Ke2-yhI)~uV)q-H#- znWWUJI=^d1`GV&oUZw_a4PB=*_G-U48IVYYc3=mlF-D)bFMtl&Dzu818Y39%{NY3d zTPfVV+PaGuYs3BlZ8w8`xY>&F6n4GaO8melx$@mT@h(ho*tY_CX_?fzt*>R^voV?1 z^i*S+qUpY=;fu%}T!ZXO29kmfm9RIgebY@1THVGLq_F)P?oR@4gH&!qBB$h2amPS2 z3SSKp^~@KkcXOw*bQl}zNz3PHY8FyY-aP$$l`8sAo6QIyL^_%-}St)~d4Gx`Y0<%i)Ksz|dl* z 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 z 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

    Release notes

    Sourced from google.golang.org/protobuf's releases.

    v1.28.0

    Overview

    The release provides a new unmarshal option for limiting the recursion depth when unmarshalling nested messages to prevent stack overflows. (UnmarshalOptions.RecursionLimit).

    Notable changes

    New features:

    • CL/340489: testing/protocmp: add Message.Unwrap

    Documentation improvements:

    • CL/339569: reflect/protoreflect: add more docs on Value aliasing

    Updated supported versions:

    UnmarshalOption RecursionLimit

    • CL/385854: all: implement depth limit for unmarshalling

    The new UnmarshalOptions.RecursionLimit limits the maximum recursion depth when unmarshalling messages. The limit is applied for nested messages. When messages are nested deeper than the specified limit the unmarshalling will fail. If unspecified, a default limit of 10,000 is applied.

    In addition to the configurable limit for message nesting a non-configurable recursion limit for group nesting of 10,000 was introduced.

    Upcoming breakage changes

    The default recursion limit of 10,000 introduced in the release is subject to change. We want to align this limit with implementations for other languages in the long term. C++ and Java use a limit of 100 which is also the target for the Go implementation.

    Commits
    • 32051b4 all: release v1.28.0
    • 3992ea8 all: implement depth limit for unmarshaling
    • e5db296 all: update supported versions
    • 3a9e1dc all: gofmt all
    • 26e8bcb all: remove unnecessary string([]byte) conversion in fmt.Sprintf with %s
    • 5aec41b testing/protocmp: add Message.Unwrap
    • 05be61f reflect/protoreflect: add more docs on Value aliasing
    • b03064a all: start v1.27.1-devel
    • See full diff in compare view

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google.golang.org/protobuf&package-manager=go_modules&previous-version=1.27.1&new-version=1.28.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 2bc717ea5f3..372b65ce148 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/tendermint/tm-db v0.6.4 google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa google.golang.org/grpc v1.45.0 - google.golang.org/protobuf v1.27.1 + google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index cb1b3b22474..38008de3b95 100644 --- a/go.sum +++ b/go.sum @@ -1433,8 +1433,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 146838200c0096a3b3c56149ca62b7ca2ebfb53e Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 28 Mar 2022 13:31:37 +0200 Subject: [PATCH 051/275] fix typos in the controller params (#1172) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- .../apps/27-interchain-accounts/controller/keeper/params.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/params.go b/modules/apps/27-interchain-accounts/controller/keeper/params.go index d199b8b554d..dce72c0c491 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/params.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/params.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" ) -// IsControllerEnabled retrieves the host enabled boolean from the paramstore. +// IsControllerEnabled retrieves the controller enabled boolean from the paramstore. // True is returned if the controller submodule is enabled. func (k Keeper) IsControllerEnabled(ctx sdk.Context) bool { var res bool @@ -14,12 +14,12 @@ func (k Keeper) IsControllerEnabled(ctx sdk.Context) bool { return res } -// GetParams returns the total set of the host submodule parameters. +// GetParams returns the total set of the controller submodule parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { return types.NewParams(k.IsControllerEnabled(ctx)) } -// SetParams sets the total set of the host submodule parameters. +// SetParams sets the total set of the controller submodule parameters. func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramSpace.SetParamSet(ctx, ¶ms) } From 46b2720687c3c34282002d8e50bb4f3262c5f035 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 28 Mar 2022 13:34:21 +0200 Subject: [PATCH 052/275] add versions for new releases (#1175) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- docs/.vuepress/config.js | 22 +++++++++++++++++++++- docs/versions | 5 +++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 8e83c7c7cd3..bdd58cd8d72 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -42,10 +42,30 @@ module.exports = { "label": "v1.2.0", "key": "v1.2.0" }, + { + "label": "v1.3.0", + "key": "v1.3.0" + }, + { + "label": "v1.4.0", + "key": "v1.4.0" + }, { "label": "v2.0.0", "key": "v2.0.0" - } + } , + { + "label": "v2.1.0", + "key": "v2.1.0" + }, + { + "label": "v2.2.0", + "key": "v2.2.0" + }, + { + "label": "v3.0.0", + "key": "v3.0.0" + } ], topbar: { banner: true diff --git a/docs/versions b/docs/versions index 45d6f133c48..e568f9a716f 100644 --- a/docs/versions +++ b/docs/versions @@ -1,4 +1,9 @@ +release/v3.0.x v3.0.0 +release/v2.2.x v2.2.0 +release/v2.1.x v2.1.0 release/v2.0.x v2.0.0 +release/v1.4.x v1.4.0 +release/v1.3.x v1.3.0 release/v1.2.x v1.2.0 release/v1.1.x v1.1.0 main main From b132515858cff499a0466f4328ca672889635724 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 30 Mar 2022 13:55:26 +0200 Subject: [PATCH 053/275] fix: link checker reporting broken milestone link (#1200) --- docs/roadmap/roadmap.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/roadmap/roadmap.md b/docs/roadmap/roadmap.md index e425e4630aa..ceb301740c6 100644 --- a/docs/roadmap/roadmap.md +++ b/docs/roadmap/roadmap.md @@ -59,7 +59,6 @@ During this quarter we will also probably release versions that bump the Cosmos ### H2 January -- [`v2.0.a`](https://github.com/cosmos/ibc-go/milestone/14) - [`v3.0.0-beta1`](https://github.com/cosmos/ibc-go/milestone/12): Beta 1 release of `v3.0.0` including Interchain Accounts, an update of Golang from `v1.15` to `v1.17`, and some core improvements. This is a Go-API breaking release because of [#472](https://github.com/cosmos/ibc-go/issues/472) and [#675](https://github.com/cosmos/ibc-go/pull/675). ### H1 February From 92cedb19f2f2b6c68c4cc6c2b85a87f2af649701 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 31 Mar 2022 13:20:11 +0200 Subject: [PATCH 054/275] update roadmap for q2 2022 and deleted history roadmap (don't think we'll need it) --- docs/roadmap/history.md | 44 ----------------- docs/roadmap/roadmap.md | 106 ++++++++++++---------------------------- 2 files changed, 30 insertions(+), 120 deletions(-) delete mode 100644 docs/roadmap/history.md diff --git a/docs/roadmap/history.md b/docs/roadmap/history.md deleted file mode 100644 index 575ed5099e6..00000000000 --- a/docs/roadmap/history.md +++ /dev/null @@ -1,44 +0,0 @@ - -# Past roadmap ibc-go - -History of the roadmap for past quarters. - -## Q4 - 2021 - -### Interchain accounts - -- Finalize the issues raised during the internal audit. -- Prepare codebase & specification for two external audits. -- Write developer documentation. -- Integration with hermes relayer and end-2-end testing. -- Create alpha release. - -### Relayer incentivisation - -- Finalize implementation. -- Update specification and write documentation. -- Do internal audit and write issues that may arise. - -### Align implementation with ICS02 - -We will work to bring the ibc-go implementation in line with [ICS02](https://github.com/cosmos/ibc/tree/master/spec/core/ics-002-client-semantics): [#284](https://github.com/cosmos/ibc-go/issues/284), [#285](https://github.com/cosmos/ibc-go/issues/285), [#286](https://github.com/cosmos/ibc-go/issues/286), [#594](https://github.com/cosmos/ibc-go/issues/594) and [#599](https://github.com/cosmos/ibc-go/issues/599). The support for Wasm-based light clients relies on these issues as well. - -### Release schedule - -|Release|Milestone|Date| -|-------|---------|----| -|[`v1.1.0`](https://github.com/cosmos/ibc-go/releases/tag/v1.1.1)||Oct 04, 2021| -|[`v1.2.1`](https://github.com/cosmos/ibc-go/releases/tag/v1.2.1)||Oct 04, 2021| -|[`v2.0.0-rc0`](https://github.com/cosmos/ibc-go/releases/tag/v2.0.0-rc0)|[Link](https://github.com/cosmos/ibc-go/milestone/3)|Oct 05, 2021| -|[`v1.1.2`](https://github.com/cosmos/ibc-go/releases/tag/v1.1.2)||Oct 15, 2021| -|[`v1.2.2`](https://github.com/cosmos/ibc-go/releases/tag/v1.2.2)||Oct 15, 2021| -|[`v1.1.3`](https://github.com/cosmos/ibc-go/releases/tag/v1.1.3)||Nov 09, 2021| -|[`v1.2.3`](https://github.com/cosmos/ibc-go/releases/tag/v1.2.3)||Nov 09, 2021| -|[`v2.0.0`](https://github.com/cosmos/ibc-go/releases/tag/v2.0.0)|[Link](https://github.com/cosmos/ibc-go/milestone/3)|Nov 09, 2021| -|[`v1.1.4`](https://github.com/cosmos/ibc-go/releases/tag/v1.1.5)||Dec 06, 2021| -|[`v1.2.4`](https://github.com/cosmos/ibc-go/releases/tag/v1.2.4)||Dec 06, 2021| -|[`v2.0.1`](https://github.com/cosmos/ibc-go/releases/tag/v2.0.1)|[Link](https://github.com/cosmos/ibc-go/milestone/11)|Dec 06, 2021| -|[`v1.1.5`](https://github.com/cosmos/ibc-go/releases/tag/v1.1.5)||Dec 15, 2021| -|[`v1.2.5`](https://github.com/cosmos/ibc-go/releases/tag/v1.2.5)||Dec 15, 2021| -|[`v2.0.2`](https://github.com/cosmos/ibc-go/releases/tag/v2.0.2)|[Link](https://github.com/cosmos/ibc-go/milestone/20)|Dec 15, 2021| -|[`v3.0.0-alpha1`](https://github.com/cosmos/ibc-go/releases/tag/v3.0.0-alpha1)|[Link](https://github.com/cosmos/ibc-go/milestone/12)|Dec 21, 2021| \ No newline at end of file diff --git a/docs/roadmap/roadmap.md b/docs/roadmap/roadmap.md index ceb301740c6..3ddc67399c7 100644 --- a/docs/roadmap/roadmap.md +++ b/docs/roadmap/roadmap.md @@ -4,101 +4,55 @@ order: 1 # Roadmap ibc-go -_Lastest update: Dec 22, 2021_ +_Lastest update: March 31, 2022_ -This document endeavours to inform the wider IBC community about plans and priorities for work on ibc-go byt the team at Interchain GmbH. It is intended to broadly inform all users of ibc-go, including developers and operators of IBC, relayer, chain and wallet applications. +This document endeavours to inform the wider IBC community about plans and priorities for work on ibc-go by the team at Interchain GmbH. It is intended to broadly inform all users of ibc-go, including developers and operators of IBC, relayer, chain and wallet applications. This roadmap should be read as a high-level guide, rather than a commitment to schedules and deliverables. The degree of specificity is inversely proportional to the timeline. We will update this document periodically to reflect the status and plans. -The release tags and timelines are educated guesses based on the information at hand at the moment of updating this document. Since predicting the final version number (specially for minor and patch numbers) can be challenging (since we might need to release unforeseen security vulnerability patches or urgent bug fixes), we are using alphabet letters as placeholders. Once we get closer to the release date, the placeholder will be replaced with the right number. An example for clarification... - -Let's assume that the planned release schedule looks like the following: -- At time `t0`: - - The first planned patch release for the `v2.0.x` release series with release tag `v2.0.a`. The placeholder is `a` since this is the first patch release in the planning. - - The first planned minor release for the `v2.x` release series with release tag `v2.a.0`. The placeholder is `a` since this is the first minor release in the planning. -- At time `t0 + delta`: - - The second planned patch release for the `v2.0.x` release series with release tag `v2.0.b`. The placehoder is `b` since this is the next patch release of this release series after `v2.0.a` in the planning. - - The first planned patch release for the new `v2.a.x` release series with release tag `v2.a.a`. The patch version placeholder is `a` because this is the first planned patch release of the `v2.a.x` release series. - -## Q1 - 2022 - -## Features - -### Interchain accounts - -- Work on any issues that may come out of the two external audits. -- Create beta, release candidate and final releases. - -### Relayer incentivisation - -- Work on issues that may arise from internal audit. -- External audit (issues may arise that we need to work on before release). -- Create alpha, beta, release candidate and final release. - -### Align implementation with ICS02 - -- Finalize work for: [#284](https://github.com/cosmos/ibc-go/issues/284), [#285](https://github.com/cosmos/ibc-go/issues/285), [#286](https://github.com/cosmos/ibc-go/issues/286), [#594](https://github.com/cosmos/ibc-go/issues/594) and [#599](https://github.com/cosmos/ibc-go/issues/599). - -### Interchain security - -- Testnet testing of [V1](https://github.com/cosmos/gaia/blob/main/docs/interchain-security.md#v1---full-validator-set). - -### Backlog issues - -- [#545](https://github.com/cosmos/ibc-go/issues/545): Remove the `GetTransferAccount` function, since we never use the ICS20 transfer module account (every escrow address is created as a regular account). -- [#559](https://github.com/cosmos/ibc-go/issues/559): Changes needed to support the migration to SMT storage. This is basically adding a new proof spec that will be used during connection handshake with a chain that has migrated to SMT to verify that the light client of the counterparty chain uses the correct proof specs to be able to verify proofs for that chain. -- And more to be added later! - -## Release schedule - -|Release|Milestone|Date| -|-------|---------|----| -|[`v3.0.0-alpha2`](https://github.com/cosmos/ibc-go/releases/tag/v3.0.0-alpha2)||Jan 07, 2021| - -During this quarter we will also probably release versions that bump the Cosmos SDK to `v0.45` and Tendermint to `v0.35`, but at the moment of writing it is difficult to estimate when. Check our roadmap regularly for updates. - -### H2 January - -- [`v3.0.0-beta1`](https://github.com/cosmos/ibc-go/milestone/12): Beta 1 release of `v3.0.0` including Interchain Accounts, an update of Golang from `v1.15` to `v1.17`, and some core improvements. This is a Go-API breaking release because of [#472](https://github.com/cosmos/ibc-go/issues/472) and [#675](https://github.com/cosmos/ibc-go/pull/675). - -### H1 February - -- [`v3.0.0-rc0`](https://github.com/cosmos/ibc-go/milestone/12): Release candidate 0 of `v3.0.0` including Interchain Accounts, an update of Golang from `v1.15` to `v1.17`, and some core improvements. This is a Go-API breaking release because of [#472](https://github.com/cosmos/ibc-go/issues/472) and [#675](https://github.com/cosmos/ibc-go/pull/675). - -### H2 February +## Q2 - 2022 -- [`v3.a.0-alpha1`](https://github.com/cosmos/ibc-go/milestone/16): Alpha release of `v3.a.0` including Relayer Incentivisation. This release will include fixes to issues that surfaced during the internal audit. +At a high level we will focus on: -### H1 March +- Finishing the implementation of [relayer incentivisation](https://github.com/orgs/cosmos/projects/7/views/8). +- Finishing the [refactoring of 02-client](https://github.com/cosmos/ibc-go/milestone/16). +- Finishing the upgrade to Cosmos SDK v0.46 and Tendermint v0.35. +- Implementing and testing the changes needed to support the [transtion to SMT storage](https://github.com/cosmos/ibc-go/milestone/21) in the Cosmos SDK. +- Desiging the implementation and scoping the engineering work for [channel upgradability](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md). +- Improving the project's documentation and writing guides for [light client](https://github.com/cosmos/ibc-go/issues/59) and middleware implementation. +- Working on [core backlog issues](https://github.com/cosmos/ibc-go/milestone/8). +- Spending time on expanding and deepening our knowledge of IBC, but also other parts of the Cosmos stack. +- And last, but not least, onboarding new members to the team. -- [`v3.0.0`](https://github.com/cosmos/ibc-go/milestone/12): Final release of `v3.0.0` including Interchain Accounts, an update of Golang from `v1.15` to `v1.17`, and some core improvements. This is a Go-API breaking release because of [#472](https://github.com/cosmos/ibc-go/issues/472) and [#675](https://github.com/cosmos/ibc-go/pull/675). -- [`v3.a.0-beta1`](https://github.com/cosmos/ibc-go/milestone/16): Beta release of `v3.a.0` including Relayer Incentivisation. This release will include fixes to issues that surfaced during the external audit. +For a detail view of each iteration's planned work, please check out our [project board](https://github.com/orgs/cosmos/projects/7). -### H2 March +### Release schedule -- [`v3.a.0-rc0`](https://github.com/cosmos/ibc-go/milestone/16): Release candiate 0 `v3.1.0` including Relayer Incentivisation. +#### **April** -## Q2 - 2022 +In the first half of the month we will probably cut: -### Features +- Alpha/beta pre-releases with the upgrade to SDK 0.46 and Tendermint v0.35. +- [Alpha](https://github.com/cosmos/ibc-go/milestone/5) pre-release with the implementation of relayer incentivisation. -> Full scope still TBD. +In the second half, and depending on the date of the final release of Cosmos SDK 0.46, we will probably cut the final release with the upgrade to SDK 0.46 and Tendermint v0.35, and also a [beta](https://github.com/cosmos/ibc-go/milestone/23) pre-release with the implementation of relayer incentivisation. -### Support for Wasm-based light clients +In the second half of the month we also plan to do a second internal audit of the implementation of relayer incentivisation, and issues will most likely will be created from the audit. Depending on the nature and type of the issues we create, those would be released in a second beta pre-release or in a [release candidate](https://github.com/cosmos/ibc-go/milestone/24). -There is an open [PR](https://github.com/cosmos/ibc-go/pull/208) that implements support for Wasm-based light clients, but it needs to be updated after the finalization of the [ICS28](https://github.com/cosmos/ibc/tree/master/spec/client/ics-008-wasm-client) specification. The PR need thorough review, more tests and potentially implementation changes. +#### **May** -## Release schedule +In the first half we will probably start cutting release candidates with relayer incentivisation and the 02-client refactor. Final release would most likely come out at the end of the month or beginning of June. -During this quarter we will also probably release versions that bump the Cosmos SDK to `v0.46` and to `v1.0`, but at the moment of writing it is difficult to estimate when. Check our roadmap regularly for updates. +#### **June** -### H1 April +We will probably cut at the end of the month or beginning of Q3 patch or minor releases on all the supported release lines with the [small features and core improvements](https://github.com/cosmos/ibc-go/milestone/8) that we work on during the quarter. -- [`v3.a.0`](https://github.com/cosmos/ibc-go/milestone/16): Final release of `v3.a.0` including Relayer Incentivisation. -- [`v4.0.0-rc0`](https://github.com/cosmos/ibc-go/milestone/16): Release candidate 0 of `v4.0.0` including the work for the issues to bring ibc-go implementation in line with ICS02 (which are Go-API breaking changes). +## Q3 - 2022 -### H2 April +We will most likely start the implementation of [channel upgradability](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md). At the end of Q2 or maybe beginning of Q3 we might also work on designing the implementation and scoping the engineering work to add support for [ordered channels that can timeout](https://github.com/cosmos/ibc/pull/636), and we could potentially work on this feature also in Q3. -- [`v4.0.0`](https://github.com/cosmos/ibc-go/milestone/16): Release candidate 0 of `v4.0.0` including the work for the issues to bring ibc-go implementation in line with ICS02 (which are Go-API breaking changes). +We will also probably do an audit of the implementation of the [CCV application](https://github.com/cosmos/interchain-security/tree/main/x/ccv) for Interchain Security. +### Release schedule +In this quarter we will make the final release to support the migration to SMT storage. \ No newline at end of file From ccc4cb804843f1a80acfb0d4dbf106d1ff2178bb Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 31 Mar 2022 21:09:57 +0200 Subject: [PATCH 055/275] requirements document for ICA (#1173) * add requirements document for interchain accounts * fix branch * added number in tittle. * apply suggestions from review Co-authored-by: Aditya * review comment Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya --- docs/apps/interchain-accounts/requirements.md | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 docs/apps/interchain-accounts/requirements.md diff --git a/docs/apps/interchain-accounts/requirements.md b/docs/apps/interchain-accounts/requirements.md new file mode 100644 index 00000000000..fff919f8088 --- /dev/null +++ b/docs/apps/interchain-accounts/requirements.md @@ -0,0 +1,119 @@ +# Business requirements + +> **TL;DR**: Rather than creating an IBC application to expose cross-chain access to every module's features, the Interchain Accounts feature would allow to leverage the capabilities of an account to access a blockchain's application-specific features. + +## Problem + +Without Interchain Accounts, cross-chain access to chain-specific features (such as staking, sending, voting, etc) has to be built as separate applications on top of the IBC TAO (Transport, Authentication, Ordering) layer. Creating new IBC application standards and implementations for each application-specific feature requires considerable time and resources. Interchain Accounts will allow new chain-specific features to be immediately available over IBC. + +## Objectives + +Provide a way to programmatically create accounts on a destination blockchain (called the host) and control them via transactions over IBC. An IBC packet will take a message from the controller blockchain to the host blockchain where it will be executed. This will allow new features on a blockchain to be immediately supported as IBC transactions, since the (destination blockchain) native messages are encapsulated in an IBC packet in an agnostic way. This will allow all of the modules on a chain to take advantage of the network effects created by the IBC ecosystem. + +## Scope + +| Features | Release | +| --------- | ------- | +| Deterministically create a new interchain account over IBC on the host chain. | v1 | +| Send over IBC a packet that contains the message to be executed by the interchain account on the host. | v1 | + +# User requirements + +## Use cases + +### Injective <> Band Chain + +Currently, Injective sends an IBC transaction to Band Chain via their custom IBC oracle module, which is a data request. When this IBC packet is executed on Band Chain, validators on Band Chain fetch prices for 10 different markets. A random selection of validators will post this selection on-chain. Once a minimum quorum has been reached, an IBC packet is sent to Injective with the prices of markets. The roundtrip latency of this flow is around 30 seconds when things go well (no packet timeouts or delays in validation). + +However, Injective wants to minimise as much as possible the latency between real world price updates and price updates on Injective. They can simplify this two-transaction flow to a single transaction using Interchain Accounts: Injective opens an interchain account on Band Chain, which would be able to pay for a continuous set of update transactions and maintain a standing request for the prices of marke. This would simplify the transaction flow to a single transaction, and introduce a simple flow to update the standing request if necessary. + +### Umee <> Cosmos Hub + +Users on the Hub would send their ATOM to Umee. In return, the user gets equivalent amount of meTokens (this token would be a form of a liquid staking token), which could then be staked on the Hub, in some other liquidity pool, etc, in addition to other business logic which Umee could perform on behalf of the users in return for the ATOM. + +Umee then stakes these ATOM tokens on the Hub on behalf of Umee (ATOMs get inflation rewards, etc). Without Interchain Accounts, Umee would have to use validator controlled multisig, because for this flow Umee needs an account on the Hub which can be controlled externally in a decentralised way. With Interchain Accounts, Umee can register an interchain account on the Hub and then receive the staking rewards for the ATOM, figure out distribution back to Umee chain, and send back to the corresponding existing account on Umee. + +### Hub custodial services + +The problem the Cosmos ecosystem faces is fragmentation of services. When a new chain goes live, they need to talk to custodial solutions and exchanges to integrate. Many exchanges and custodial solutions don't want to integrate tens of chains unless paid in advance. + +An alternative is offering the custodial service through the Hub. When a new chain goes live, the tokens of the chain are transferred through IBC to the Hub. This means that the custodial service would just have to integrate with one chain (the Hub), rather with an arbitrary number of them. + +Using Interchain Accounts, a service could be built in which a user sends tokens to an interchain account address on chain `X`, which corresponds to the registered interchain account of chain `X` on the Hub. This account would handle the token transfer to the Hub and then further on to the custodial wallet. + +# Functional requirements + +## Assumptions + +1. Interchain account packets will rarely timeout with application-set values. +2. Cosmos-SDK modules deployed on a chain are not malicious. +3. Authentication modules may implement their own permissioning scheme. + +## Features + +### 1 - Configuration + +| ID | Description | Verification | Status | +| --- | ----------- | ------------ | ------ | +| 1.01 | A chain shall have the ability to enable or disable Interchain Accounts controller functionality in the genesis state. | The controller parameters have a [flag](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/types/host.pb.go#L30) to enable/disable the controller submodule, and this flag [is stored during genesis initialization](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/params.go#L24). | `Implemented` | +| 1.02 | A chain shall have the ability to export the Interchain Accounts controller genesis state. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go#L47) | `Implemented` | +| 1.03 | A chain shall have the ability to initialize the Interchain Accounts controller genesis state. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go#L10) | `Implemented` | +| 1.04 | A chain shall have the ability to set the Interchain Accounts controller parameters when upgrading or via proposal. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/module_test.go#L33) | `Implemented` | +| 1.05 | A chain shall have the ability to enable or disable Interchain Accounts host functionality in the genesis state. | The host parameters have a [flag](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/types/host.pb.go#L30) to enable/disable the host submodule, and this flag [is stored during genesis initialization](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/params.go#L31) | `Implemented` | +| 1.06 | A chain shall have the ability to export the Interchain Accounts host genesis state. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go#L46) | `Implemented` | +| 1.07 | A chain shall have the ability to initialize the Interchain Accounts host genesis state. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go#L10) | `Implemented` | +| 1.08 | A chain shall have the ability to set the Interchain Accounts host parameters when upgrading or via proposal. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/module_test.go#L33) | `Implemented` | +| 1.09 | The host chain shall have the ability to whitelist what types of messages or transactions that it chooses to facilitate (e.g. it can decide that registered interchain accounts cannot execute staking messages). | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/params_test.go#L5) | `Implemented` | + +### 2 - Registration + +| ID | Description | Verification | Status | +| --- | ----------- | ------------ | ------ | +| 2.01 | The controller chain can programmatically create interchain accounts on the host chain that shall be controlled only by the owner account on the controller chain. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/account_test.go#L10) | `Implemented` | +| 2.02 | An interchain account shall be created by any actor without the approval of a third party (e.g. chain governance). | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/account_test.go#L10) | `Implemented` | + +### 3 - Control + +| ID | Description | Verification | Status | +| --- | ----------- | ------------ | ------ | +| 3.01 | The controller chain can programmatically control the interchain account by submitting transactions to be executed on the host chain on the behalf of the interchain account. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go#L29) | `Implemented` | +| 3.02 | Under no circumstances shall the owner account on the controller chain irretrievably lose control over the registered interchain account on the host chain. | If the channel between controller and host closes, then [a relayer can open a new channel on the existing controller port](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/account.go#L16-L17). | `Implemented` | + +### 4 - Host execution + +| ID | Description | Verification | Status | +| --- | ----------- | ------------ | ------ | +| 4.01 | Transactions shall be executed by an interchain account on the host chain in exactly the same order in which they are submitted by the controller chain. | IBC packets with SDK messages will be sent from the controller to the host over an [ordered channel](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/account.go#L60). | `Implemented` | +| 4.02 | The host shall execute only messages in the allow list. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/relay_test.go#L340) | `Implemented` | +| 4.03 | The controller chain shall know how the host chain will handle the transaction bytes in advance. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go#L109-L133) | `Implemented` | +| 4.04 | Each transaction submitted by the controller chain shall be executed only once by the interchain account on the host chain. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/relay_test.go#L248) | `Implemented` | + +# Non-functional requirements + +## 5 - Security + +| ID | Description | Verification | Status | +| -- | ----------- | ------------ | ------ | +| 5.01 | There shall be no means for the interchain account to execute transactions that have not been submitted first by the respective owner account on the controller chain. |[Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/relay_test.go#L361) | `Implemented` | +| 5.02 | Every interchain account on the host chain shall have one and only one respective owner account on the controller chain. | The interchain account on the host [is generated using the host connection ID and the address of the owner on the controller](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/handshake.go#L73-L76). | `Implemented` | +| 5.03 | The owner account on a controller chain shall not be able to control interchain accounts registered by other owner accounts on the same controller chain. | Before the host logic executes the received messages, it [retrieves the interchain account associated with the port ID](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/keeper/relay.go#L94) over which it received the message. For owner address B to be able to execute a message with the interchain account registered with owner address A, it would need to send the messages over a channel that binds to a port ID that contains the owner address A, and since we have assumption number 3, this should not be allowed by applications. | `Implemented` | +| 5.04 | A controller chain shall not be able to control interchain accounts registered by owner accounts on different controller chains. | Same as 5.03. | `Implemented` | | +| 5.05 | Each interchain account on the host chain is owned by a single owner account on the controller chain. It shall not be possible to register a second interchain account with the same owner account on the controller chain. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/account_test.go#L42) | `Implemented` | + +# External interface requirements + +## 6 - CLI + +| ID | Description | Verification | Status | +| -- | ----------- | ------------ | ------ | +| 6.01 | There shall be a CLI command available to query the host parameters. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/client/cli/query.go#L22) | `Implemented` | +| 6.02 | There shall be a CLI command available to query the receive packet events on the host chain to check the result of the execution of the message on the host. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/host/client/cli/query.go#L51) | `Implemented` | +| 6.03 | There shall be a CLI command available to query the controller parameters. | [Acceptance tests](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/client/cli/query.go#L15) | `Implemented` | + + +## 7 - Application developers + +| ID | Description | Verification | Status | +| -- | ----------- | ------------ | ------ | +| 7.01 | An IBC application developer shall be able to develop an Interchain Accounts authentication module that can register interchain accounts. | The [`RegisterInterchainAccount` function](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/account.go#L18) is the entry point to registering an interchain account. | `Implemented` | +| 7.02 | An IBC application developer shall be able to develop an Interchain Accounts authentication module that can send messages from the controller to the host. | The [`SendTx` function](https://github.com/cosmos/ibc-go/blob/v3.0.0/modules/apps/27-interchain-accounts/controller/keeper/relay.go#L18) takes pre-built packet data containing messages to be executed on the host chain from an authentication module and attempts to send the packet. | `Implemented` | \ No newline at end of file From ffa98962f9833703b8cd83acf29c3dbfa165701b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Wed, 6 Apr 2022 00:49:21 +0200 Subject: [PATCH 056/275] imp: improve Logger performance (#1160) * fix: Logger marshal errors * changelog * update --- CHANGELOG.md | 2 ++ modules/core/04-channel/keeper/packet.go | 7 ++++--- modules/core/04-channel/keeper/timeout.go | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b655f7c6d4..a393565403b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. + ### Features ### Bug Fixes diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index 51b02f9bece..c3e8e45b89c 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -2,6 +2,7 @@ package keeper import ( "bytes" + "strconv" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -129,7 +130,7 @@ func (k Keeper) SendPacket( k.Logger(ctx).Info( "packet sent", - "sequence", packet.GetSequence(), + "sequence", strconv.FormatUint(packet.GetSequence(), 10), "src_port", packet.GetSourcePort(), "src_channel", packet.GetSourceChannel(), "dst_port", packet.GetDestPort(), @@ -284,7 +285,7 @@ func (k Keeper) RecvPacket( // log that a packet has been received & executed k.Logger(ctx).Info( "packet received", - "sequence", packet.GetSequence(), + "sequence", strconv.FormatUint(packet.GetSequence(), 10), "src_port", packet.GetSourcePort(), "src_channel", packet.GetSourceChannel(), "dst_port", packet.GetDestPort(), @@ -494,7 +495,7 @@ func (k Keeper) AcknowledgePacket( // log that a packet has been acknowledged k.Logger(ctx).Info( "packet acknowledged", - "sequence", packet.GetSequence(), + "sequence", strconv.FormatUint(packet.GetSequence(), 10), "src_port", packet.GetSourcePort(), "src_channel", packet.GetSourceChannel(), "dst_port", packet.GetDestPort(), diff --git a/modules/core/04-channel/keeper/timeout.go b/modules/core/04-channel/keeper/timeout.go index b446aa7ea4c..5a14ef85b6b 100644 --- a/modules/core/04-channel/keeper/timeout.go +++ b/modules/core/04-channel/keeper/timeout.go @@ -2,6 +2,7 @@ package keeper import ( "bytes" + "strconv" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -159,7 +160,7 @@ func (k Keeper) TimeoutExecuted( k.Logger(ctx).Info( "packet timed-out", - "sequence", packet.GetSequence(), + "sequence", strconv.FormatUint(packet.GetSequence(), 10), "src_port", packet.GetSourcePort(), "src_channel", packet.GetSourceChannel(), "dst_port", packet.GetDestPort(), From 4271027a5ab1e6faaa2edbc2b9840209c315afab Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 6 Apr 2022 17:35:20 +0200 Subject: [PATCH 057/275] ICS 29: Fee Middleware (#276) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * scaffolding for 29-fee (#274) * scaffolding for 29-fee * fix build * update keeper test * remove module test * feat: adding proto files for fee payment middleware (#272) * feat: adding proto files for fee payment middleware * grammar * fix: remove generated .pb files * fix: comment * feat: adding PacketId type * refactor: fee / genesis * refactor: escrowed fees map * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update proto/ibc/applications/middleware/fee/v1/tx.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update proto/ibc/applications/middleware/fee/v1/tx.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update proto/ibc/applications/middleware/fee/v1/tx.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: use packetID + minor changes * feat: adding query for all incentivized packets + some fixes * feat: adding pagination to incentivized query * fix: removing generated ibc directory + adding import/yaml * fix: naming * increase max depth for proto file searching and make proto all * Update proto/ibc/applications/middleware/fee/v1/fee.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * refactor: remove file imports/add yaml/add argument for requests * refactor: updating IdentifiedPacketFee * fix: remove hidden file * removing middleware dir & adding query * remove junk file and update query rpcs * Apply suggestions from code review * Apply suggestions from code review * remove query yaml, make proto-all Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya Sripal * fix: removing unncessary fields MsgEscrow & adding query params (#300) * fix: removing unncessary fields MsgEscrow & adding query params * fix: grammar * fix: add yaml * feat: #258 Register Counterparty Address (#376) * feat: adding MsgServer for RegisterCounterPartyAddress & EscrowPacketFree * test: adding test for ValidateBasic * fix: removing validate basic check * fix: removing empty file * Update modules/apps/29-fee/keeper/msg_server.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/types/msgs.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/types/keys.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/keeper/keeper.go Co-authored-by: Aditya * fix: fixing typos, variable names, comments * fix: updating import comments * test: adding test for KeyRelayerAddress * update: comments & key_test * Update modules/apps/29-fee/keeper/msg_server.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: error message * docs: updating RegisterCounterpartyAddress fn description Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya * fix: remove comments for imports (#385) * feat: Add handshake logic to ics29 (#307) * do handshake logic, create test file * do cap logic and fix build * open handshake implementation and tests * remove prints * Update modules/apps/29-fee/module.go Co-authored-by: Sean King * debugging progress * fee enabled flag * cleanup handshake logic * fix tests * much cleaner simapp * split module.go file * cleanup and docs * assert IBC interfaces are fulfilled in middleware * Update modules/apps/transfer/module.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix unnecessary crossing hello logic * fix version negotiation bugs and improve tests * cleanup tests * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * address rest of colin comments Co-authored-by: Sean King Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Fee Middleware: Escrow logic (#465) * fix: adding second endpoint for async pay fee + renaming types * feat: adding escrow logic * feat: updating proto types & escrow logic * fix: stub fn & proto comment * feat: adding PayFee & PayFeeTimeout & escrow_test * test: adding happy path for EscrowPacketFee * fix: comments, error handling * fix: comments & grammar * test: adding unhappy path for escrow * tests(escrow): adding hasBalance check for module acc * test(PayFee): adding happy path for PayFee tests * tests(PayFee, PayFeeTimeout): adding tests * fix: adding relayers back to IdentifiedPacket * fix: removing refund acc from key * fix: storing IdentifiedPacketFee in state instead of Fee * feat: adding msg_server test for registerCPAddr, wiring for codec + stubs for sdk.Msg interface * test: adding msg_server test for PayPacketFee * test: adding PayPacketFeeAsync msg_server test * chore: updating PayFee -> DistributeFee & minor nits * nit: removing unnecessary nil check * refactor: add portId to store key & use packetId as param * fix: add DeleteFeeInEscrow & remove fee on successful distribution * tests: adding validation & signer tests for PayFee/Async & updating proto to use Signer sdk standard * chore: adding NewIdentifiedPacketFee fn * fix: getter/setter for counterparty address + fix NewIdentifiedPacketFee * fix: updating EscrowPacketFee with correct usage of coins api * test: adding balance check for refund acc after escrow * fix: remove unncessary errors * test: updating escrow tests + miscellaneous fixes * nit: updating var names * docs: godoc * refactor: IdentifiedPacketFee & Fee no longer pointers * fixes: small fixes * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: Aditya * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: Aditya * Update modules/apps/29-fee/keeper/keeper.go Co-authored-by: Aditya * Update modules/apps/29-fee/keeper/msg_server.go Co-authored-by: Aditya * Update modules/apps/29-fee/keeper/msg_server.go Co-authored-by: Aditya * Update modules/apps/29-fee/types/msgs.go Co-authored-by: Aditya * nit: proto doc & error fix * fix: escrow test * test: updating distribute fee tests * test: adding validation check for fee and updating tests * test: allow counterparty address to be arbitrary string * fix: message validation should pass if one fee is valid * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: nits * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * test: adding isZero check for msgs Co-authored-by: Aditya Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * feat: update protos, grpc queries (#488) * store refund address in IdentifiedPacketFee (#546) * 29-Fee: Genesis (#557) * proto: adding genesis state * feat: add GetAllIdentifiedPacketFees * feat: adding genesis.go & updating proto + app.go * fix: removing PortId from genesis * feat: adding GetAll for relayer addr/fee enabled chan + update genesis * test: TestExportGenesis * feat: update type + hook up to module.go * fix: remove PortKey * fix: imports + remove scoped keeper * nit: using NewPacketId helper and updating helper def to have correct params * feat: adding genesis validation + tests (#561) * feat: adding genesis validation + tests * fix: imports * Update modules/apps/29-fee/types/genesis.go * fix: nit * Update modules/apps/29-fee/types/genesis_test.go Co-authored-by: Aditya * nit: imporve default gen val test * chore: move packetId + val to channeltypes and use validate fn Co-authored-by: Aditya * feat: add incentivised ack proto (#564) * proto file * incentivized ack proto * Fee Closing Handshake (#551) * add iterate logic * add closing logic with tests * add comments for panic * change invariant breaking recovery to disabling middleware rather than panicing * docs, tests, minor refactor * Fee Middleware: Add ICS4 wrapper (#562) * chore: add ICS4 wrapper * fix: remove channelKeeper sender packet * chore: add WriteAck * feat: ics 29 packet callbacks (#357) * update imports to v3 * regenerate proto files * fix build * fix: event caching for fee distribution (#661) * proto file * initial impl * apply self review suggestions Deduplicate fee distribution code. Rename DistributeFee to DistributePacketFees. Rename DistributeFeeTimeout to DistributePacketFeesOnTimeout * fixup tests rename validCoins. DistributePacketFeesOnTimeout no longer has a valid error case Add test case for invalid forward relayer address on DistributePacketFees. * partially fix tests timeout fee is still being distributed depsite WriteFn() not being called * fix tests * address code nit Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> * ics4 callbacks fee middleware (#580) * feat: adding WriteAcknowledgement * updating genesis & relayer prefix * fix: comment * fix: comments * Update modules/apps/29-fee/keeper/relay.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * feat: add DeleteForwardRelayerAddr helper + use Set in ack * fix: SetForwardAddr * chore: add panic * fix: remove fmt * test: add WriteAcknowledgement test * Update modules/apps/29-fee/ibc_module.go Co-authored-by: Aditya * fix: remove print * fix: WriteAck * fix: use constructor * Update modules/apps/29-fee/keeper/keeper.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: nits * fix: remove found var not used * test: adding check that forward relayer address is successfully deleted if set * fix: merge issues Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya * chore: making PacketId non nullable (#737) * nits: proto spacing + naming (#739) * nits: proto spacing + naming * nit: update comment * fix: go.mod * nit: option above import proto * fix: spacing * sean/fix-proto-identified-fee-not-null (#746) * nits: more ics29 nits (#741) * nits: remove capital from error + add godoc * nit: add Wrapf * nit: use strings.TrimSpace * nit: add err type for MsgPayPacketFee * refactor: app version + add comment (#750) * chore: remove error * test: add test for whitespaced empty string * nit: update err syntax (#747) * nit: update err syntax * nit: more * nit: err syntax * feat: adding Route, Type, GetSignBytes for all messages (#743) * feat: adding Route, Type, GetSignBytes for all messages * tests: adding tests for Route/Type/GetSignBytes * hygiene: add validate fn for Fee (#748) * hygiene: add validate fn for Fee * Update modules/apps/29-fee/types/msgs.go Co-authored-by: Damian Nolan * fix: error message * test: move Validate to fee.go & abstract out test * chore: remove test cases Co-authored-by: Damian Nolan * fix: app.go (#789) * refactor: ics29 json encoded version metadata (#883) * adding metadata type to ics29 protos * updating ics29 handshake handlers to support json encoded metadata * updating tests to support json encoded metadata * Update modules/apps/29-fee/ibc_module.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/ibc_module.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * renaming metadata version to fee_version Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: return nil on OnRecvPacket for async pay (#911) * nit: ics29 comments (#910) * fix: comments * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: Aditya * chore: Add transfer test for ics29 (#901) * begin writing transfer test for ics29 * finish writing transfer test * refactor: ics29 OnChanOpenInit callback tests now use mock module (#924) * refactor: OnChanOpenInit callback tests now use mock module * Update modules/apps/29-fee/fee_test.go * feat: allow multiple addrs to incentivize packets (#915) * [WIP] allow multiple addresses to incentivize a packet * distribute multiple fees, fix broken tests * use NewIdentifiedPacketFees in EscrowPacketFee * cleanup var naming * removing commented out code and adding test case * Update modules/apps/29-fee/ibc_module.go Co-authored-by: Aditya * fix: refund RecvFee if ForwardAddr is invalid * test: update tests to distribute multiple identified fees * refactor: clean up DistrPacketFees * refactor: using .Empty() helper func for code hygiene Co-authored-by: Aditya Co-authored-by: Sean King Co-authored-by: Sean King * chore: remove spec directory from ics29 (#934) * refactor: use mock module for ics29 closing handshakes (#926) * refactor: use mock module for closing handshakes in ics29 * self-review fix * refactor: use mock module for ics29 grpc_query_test.go (#933) * refactor: readjust keeper_test.go to use mock module (#930) * fix: fields for genesis should be non nullable (#938) * refactor: use mock module for ics29 escrow_test.go (#932) * refactor: use mock module for ics29 genesis_test.go (#931) * ics29:feat: emit event escrow (#914) * feat: emit EventTypeSendIncentivizedPacket event on EscrowPacket * fix: string conversion * refactor: add helper fn for emit event * chore: godoc * nit: use .String()) * refactor: OnRecvPacket to use mock module (#927) Co-authored-by: Sean King * refactor: ics29 OnChanOpenTry/Ack use mock module for testing instead of ics20 (#925) Co-authored-by: Sean King * refactor: use mock module for OnAcknowledgePacket callback testing (#929) Co-authored-by: Sean King * refactor: OnTimeoutPacket to use mock module (#928) Co-authored-by: Sean King * chore: add packet id arg to EscrowPacketFee (#951) * adding packet id arg to EscrowPacketFee * updating tests * review adaptations * chore: remove legacy testing functions (#954) * fix:ics29: WriteAck update + adding success bool to IncentivizedAck (#952) * fix: updating WriteAck & adding Success boolean to IncentivizedAcknowledgement * feat: adding check of is fee enabled * nit: change successful to underlying_application_success * test: adding seperate test for fee disabled write async * Update modules/apps/29-fee/ibc_module_test.go Co-authored-by: Aditya * test: adding check to compare hash of acks * fix: var name Co-authored-by: Aditya * chore: add cli cmd to incentivize existing packet (async) (#965) * chore: add cli to incentivize existing packets * Update modules/apps/29-fee/client/cli/cli.go * Update modules/apps/29-fee/client/cli/cli.go Co-authored-by: Aditya * chore: update cli example Co-authored-by: Aditya * ics29:fix: counterparty addr must contain channelID (#937) * fix: counterparty address must chain channelID * nit: updating var name * test: adding validation check for channelID * nit: fn names * chore: fix err msg (#971) * ics29:fix: store source address for query later on WriteAck (#912) * fix: for async WriteAck store source address for query later * ics29:fix: update genesis type (#913) * fix: adding ForwardRelayerAddresses to genesis * fix: trimspace on string check * nit: err + trimspace error case * refactor: updating WriteAck + keeper fn name * Update modules/apps/29-fee/keeper/relay.go Co-authored-by: Damian Nolan * chore: remove legacy testing functions (#954) * fix:ics29: WriteAck update + adding success bool to IncentivizedAck (#952) * fix: updating WriteAck & adding Success boolean to IncentivizedAcknowledgement * feat: adding check of is fee enabled * nit: change successful to underlying_application_success * test: adding seperate test for fee disabled write async * Update modules/apps/29-fee/ibc_module_test.go Co-authored-by: Aditya * test: adding check to compare hash of acks * fix: var name Co-authored-by: Aditya Co-authored-by: Damian Nolan Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya * refactor: make fee storage more efficient (#956) * adding new proto types and codegen * refactoring ics29 fees for more efficient storage * updating tests * fixing typo in protodoc comments * chore: update ics29 genesis state to support multiple packet fees (#957) * adding new proto types and codegen * refactoring ics29 fees for more efficient storage * updating tests * updating genesis protos to use IdentifiedPacketFees * updating init/export genesis state functionality and tests * chore: update MsgPayPacketFeeAsync fields (#979) * adding new proto types and codegen * refactoring ics29 fees for more efficient storage * updating tests * fixing typo in protodoc comments * updating protos and codegen * updating MsgPayPacketFeeAsync handler and tests * chore: add ParseKeyFeesInEscrow helper function (#998) * chore: update grpc queries to handle multiple fees (#967) * adding new proto types and codegen * refactoring ics29 fees for more efficient storage * updating tests * updating protos and existing queries * updating grpc queries and refactoring tests * format error correct in favour of proto string() method * leveraging ParseKeyFeesInEscrow to obtain packet id in query * feat: CLI cmd for MsgRegisterCounterpartyAddress (#987) * feat: CLI cmd for MsgRegisterCounterpartyAddress * fix: examples * Update modules/apps/29-fee/client/cli/tx.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/apps/29-fee/client/cli/tx.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * chore: remove print * nit: update address for counterparty Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix: ics29: switch source with destintion for chan/port IDs (#961) * fix: switch source with destintion for chan/port IDs * fix: blunder * test: adding tests in case of incorrect channel/port id * test: moving check to WriteAcknowledgement * add test case for Get/Set counterparty address * nit: path name * Update modules/apps/29-fee/keeper/msg_server_test.go * test: cleanup 29-fee/types tests (#1006) * feat: grpc query total recv packet fees (#1015) * adding query for total packet recv fees to proto query server * adding total packet recv fee query impl and tests * updating doc comments * chore: switch code ordering (#1025) * feat: Add ParseKeyFeeEnabled and rename FeeEnabledKey -> KeyFeeEnabled (#1023) * chore: add ParseKeyFeesInEscrow helper function * feat: add ParseKeyFeeEnabled function and rename FeeEnabledKey to KeyFeeEnabled * feat: ics29 cli for query total recv fees (#1035) * feat: grpc query total ack fees (#1032) * adding query for total packet recv fees to proto query server * adding total packet recv fee query impl and tests * updating doc comments * adding protos and codegen * adding total ack fees query and tests * fixing protodoc comment * feat: grpc query total timeout fees (#1033) * adding query for total packet recv fees to proto query server * adding total packet recv fee query impl and tests * updating doc comments * adding protos and codegen * adding total ack fees query and tests * adding protos and codegen * adding query total timeout fees and tests * fixing protodoc comment * fixing protodoc comment * feat: adding clis for total ack and timeout queries (#1043) * add ParseKeyForwardRelayerAddress function + test (#1046) * chore: remove unused ics29 keeper funcs (#1044) * removing keys, adding additional test, moving event attribute keys * removing unused code and updating tests * removing unused IdentifiedPacketFee type * chore: add gRPC for querying incentivized packets for a specific channel (#983) * generate proto files * feat: add gRPC for querying incentivized packets for a specific channel * test: add gRPC test for incentivized packets for channel query * fix build * partially fix tests * chore: fix tests * deduplicate code * chore: code cleanup * fix build * remove changes from merge conflict * nit: rename c to goCtx * add function EscrowAccountHasBalance (#1042) * add function EscrowAccountHasBalance * change API to use sdk.Coins * feat: ParseKeyCounterpartyRelayer function (#1047) * chore: adding queries to cmd builder (#1057) * chore: update ics29 protodocs (#1055) * updating protodocs comments and regen code/docs * Update proto/ibc/applications/fee/v1/tx.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * updating incentivized ack doc Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * add counter party channel ID to argument list of on channel open ack (#1159) Co-authored-by: Carlos Rodriguez * ADR 004: Fee module locking in the presence of severe bugs (#1060) * add adr 004 * add to README * Update docs/architecture/adr-004-ics29-lock-fee-module.md Co-authored-by: Aditya * Update docs/architecture/adr-004-ics29-lock-fee-module.md Co-authored-by: Aditya Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya * nit: packetID var name (#1214) * ics29: update with changes from main (#1221) * add banner image (#1158) Co-authored-by: Carlos Rodriguez * Add alpha, beta, and rc release definitions (#1151) ## Description The proposed definitions for each phase of our release cycle. Please feel free to adjust my wording closes: #881 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * build(deps): bump google.golang.org/protobuf from 1.27.1 to 1.28.0 (#1164) Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.27.1 to 1.28.0.
    Release notes

    Sourced from google.golang.org/protobuf's releases.

    v1.28.0

    Overview

    The release provides a new unmarshal option for limiting the recursion depth when unmarshalling nested messages to prevent stack overflows. (UnmarshalOptions.RecursionLimit).

    Notable changes

    New features:

    • CL/340489: testing/protocmp: add Message.Unwrap

    Documentation improvements:

    • CL/339569: reflect/protoreflect: add more docs on Value aliasing

    Updated supported versions:

    UnmarshalOption RecursionLimit

    • CL/385854: all: implement depth limit for unmarshalling

    The new UnmarshalOptions.RecursionLimit limits the maximum recursion depth when unmarshalling messages. The limit is applied for nested messages. When messages are nested deeper than the specified limit the unmarshalling will fail. If unspecified, a default limit of 10,000 is applied.

    In addition to the configurable limit for message nesting a non-configurable recursion limit for group nesting of 10,000 was introduced.

    Upcoming breakage changes

    The default recursion limit of 10,000 introduced in the release is subject to change. We want to align this limit with implementations for other languages in the long term. C++ and Java use a limit of 100 which is also the target for the Go implementation.

    Commits
    • 32051b4 all: release v1.28.0
    • 3992ea8 all: implement depth limit for unmarshaling
    • e5db296 all: update supported versions
    • 3a9e1dc all: gofmt all
    • 26e8bcb all: remove unnecessary string([]byte) conversion in fmt.Sprintf with %s
    • 5aec41b testing/protocmp: add Message.Unwrap
    • 05be61f reflect/protoreflect: add more docs on Value aliasing
    • b03064a all: start v1.27.1-devel
    • See full diff in compare view

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google.golang.org/protobuf&package-manager=go_modules&previous-version=1.27.1&new-version=1.28.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    * fix typos in the controller params (#1172) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * add versions for new releases (#1175) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes * fix: link checker reporting broken milestone link (#1200) * update roadmap for q2 2022 and deleted history roadmap (don't think we'll need it) * requirements document for ICA (#1173) * add requirements document for interchain accounts * fix branch * added number in tittle. * apply suggestions from review Co-authored-by: Aditya * review comment Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya * imp: improve Logger performance (#1160) * fix: Logger marshal errors * changelog * update Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Damian Nolan Co-authored-by: Aditya Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Sean King Co-authored-by: Charly Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez Co-authored-by: Luke Rhoads <51463884+lukerhoads@users.noreply.github.com> Co-authored-by: Damian Nolan Co-authored-by: Dev Ojha Co-authored-by: Jack Zampolin Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Leo Pang <34628052+allthatjazzleo@users.noreply.github.com> Co-authored-by: Barrie Byron Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com> Co-authored-by: technicallyty <48813565+tytech3@users.noreply.github.com> Co-authored-by: Barrie Byron Co-authored-by: Marko Co-authored-by: Marko Baricevic Co-authored-by: Aleksandr Bezobchuk Co-authored-by: nir1218 Co-authored-by: Carlos Rodriguez Co-authored-by: Assaf Morami Co-authored-by: Dan McCandless Co-authored-by: Ramiro Carlucho Co-authored-by: frog power 4000 Co-authored-by: Sean King --- docs/architecture/README.md | 1 + .../adr-004-ics29-lock-fee-module.md | 55 + docs/ibc/proto-docs.md | 1551 ++++++--- modules/apps/29-fee/client/cli/cli.go | 42 + modules/apps/29-fee/client/cli/query.go | 151 + modules/apps/29-fee/client/cli/tx.go | 124 + modules/apps/29-fee/fee_test.go | 65 + modules/apps/29-fee/ibc_module.go | 275 ++ modules/apps/29-fee/ibc_module_test.go | 815 +++++ modules/apps/29-fee/keeper/escrow.go | 145 + modules/apps/29-fee/keeper/escrow_test.go | 313 ++ modules/apps/29-fee/keeper/events.go | 25 + modules/apps/29-fee/keeper/genesis.go | 36 + modules/apps/29-fee/keeper/genesis_test.go | 113 + modules/apps/29-fee/keeper/grpc_query.go | 175 + modules/apps/29-fee/keeper/grpc_query_test.go | 428 +++ modules/apps/29-fee/keeper/keeper.go | 327 ++ modules/apps/29-fee/keeper/keeper_test.go | 202 ++ modules/apps/29-fee/keeper/msg_server.go | 65 + modules/apps/29-fee/keeper/msg_server_test.go | 136 + modules/apps/29-fee/keeper/relay.go | 44 + modules/apps/29-fee/keeper/relay_test.go | 103 + modules/apps/29-fee/module.go | 179 ++ modules/apps/29-fee/transfer_test.go | 72 + modules/apps/29-fee/types/ack.go | 27 + modules/apps/29-fee/types/ack.pb.go | 423 +++ modules/apps/29-fee/types/codec.go | 42 + modules/apps/29-fee/types/errors.go | 18 + modules/apps/29-fee/types/events.go | 10 + modules/apps/29-fee/types/expected_keepers.go | 40 + modules/apps/29-fee/types/fee.go | 92 + modules/apps/29-fee/types/fee.pb.go | 1182 +++++++ modules/apps/29-fee/types/fee_test.go | 123 + modules/apps/29-fee/types/genesis.go | 81 + modules/apps/29-fee/types/genesis.pb.go | 1273 ++++++++ modules/apps/29-fee/types/genesis_test.go | 215 ++ modules/apps/29-fee/types/keys.go | 133 + modules/apps/29-fee/types/keys_test.go | 176 + modules/apps/29-fee/types/metadata.pb.go | 378 +++ modules/apps/29-fee/types/msgs.go | 164 + modules/apps/29-fee/types/msgs_test.go | 319 ++ modules/apps/29-fee/types/query.pb.go | 2845 +++++++++++++++++ modules/apps/29-fee/types/query.pb.gw.go | 944 ++++++ modules/apps/29-fee/types/tx.pb.go | 1544 +++++++++ modules/apps/transfer/ibc_module_test.go | 14 +- modules/core/04-channel/types/channel.pb.go | 360 ++- modules/core/04-channel/types/packet.go | 22 + modules/core/04-channel/types/version.go | 2 +- proto/ibc/applications/fee/v1/ack.proto | 17 + proto/ibc/applications/fee/v1/fee.proto | 56 + proto/ibc/applications/fee/v1/genesis.proto | 52 + proto/ibc/applications/fee/v1/metadata.proto | 16 + proto/ibc/applications/fee/v1/query.proto | 144 + proto/ibc/applications/fee/v1/tx.proto | 85 + proto/ibc/core/channel/v1/channel.proto | 14 + scripts/protocgen.sh | 3 +- testing/simapp/app.go | 54 +- testing/values.go | 2 + 58 files changed, 15865 insertions(+), 447 deletions(-) create mode 100644 docs/architecture/adr-004-ics29-lock-fee-module.md create mode 100644 modules/apps/29-fee/client/cli/cli.go create mode 100644 modules/apps/29-fee/client/cli/query.go create mode 100644 modules/apps/29-fee/client/cli/tx.go create mode 100644 modules/apps/29-fee/fee_test.go create mode 100644 modules/apps/29-fee/ibc_module.go create mode 100644 modules/apps/29-fee/ibc_module_test.go create mode 100644 modules/apps/29-fee/keeper/escrow.go create mode 100644 modules/apps/29-fee/keeper/escrow_test.go create mode 100644 modules/apps/29-fee/keeper/events.go create mode 100644 modules/apps/29-fee/keeper/genesis.go create mode 100644 modules/apps/29-fee/keeper/genesis_test.go create mode 100644 modules/apps/29-fee/keeper/grpc_query.go create mode 100644 modules/apps/29-fee/keeper/grpc_query_test.go create mode 100644 modules/apps/29-fee/keeper/keeper.go create mode 100644 modules/apps/29-fee/keeper/keeper_test.go create mode 100644 modules/apps/29-fee/keeper/msg_server.go create mode 100644 modules/apps/29-fee/keeper/msg_server_test.go create mode 100644 modules/apps/29-fee/keeper/relay.go create mode 100644 modules/apps/29-fee/keeper/relay_test.go create mode 100644 modules/apps/29-fee/module.go create mode 100644 modules/apps/29-fee/transfer_test.go create mode 100644 modules/apps/29-fee/types/ack.go create mode 100644 modules/apps/29-fee/types/ack.pb.go create mode 100644 modules/apps/29-fee/types/codec.go create mode 100644 modules/apps/29-fee/types/errors.go create mode 100644 modules/apps/29-fee/types/events.go create mode 100644 modules/apps/29-fee/types/expected_keepers.go create mode 100644 modules/apps/29-fee/types/fee.go create mode 100644 modules/apps/29-fee/types/fee.pb.go create mode 100644 modules/apps/29-fee/types/fee_test.go create mode 100644 modules/apps/29-fee/types/genesis.go create mode 100644 modules/apps/29-fee/types/genesis.pb.go create mode 100644 modules/apps/29-fee/types/genesis_test.go create mode 100644 modules/apps/29-fee/types/keys.go create mode 100644 modules/apps/29-fee/types/keys_test.go create mode 100644 modules/apps/29-fee/types/metadata.pb.go create mode 100644 modules/apps/29-fee/types/msgs.go create mode 100644 modules/apps/29-fee/types/msgs_test.go create mode 100644 modules/apps/29-fee/types/query.pb.go create mode 100644 modules/apps/29-fee/types/query.pb.gw.go create mode 100644 modules/apps/29-fee/types/tx.pb.go create mode 100644 proto/ibc/applications/fee/v1/ack.proto create mode 100644 proto/ibc/applications/fee/v1/fee.proto create mode 100644 proto/ibc/applications/fee/v1/genesis.proto create mode 100644 proto/ibc/applications/fee/v1/metadata.proto create mode 100644 proto/ibc/applications/fee/v1/query.proto create mode 100644 proto/ibc/applications/fee/v1/tx.proto diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 091ba899dc6..edfbea4f0c8 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -30,6 +30,7 @@ To suggest an ADR, please make use of the [ADR template](./adr-template.md) prov | [001](./adr-001-coin-source-tracing.md) | ICS-20 coin denomination format | Accepted, Implemented | | [002](./adr-002-go-module-versioning.md) | Go module versioning | Accepted | | [003](./adr-003-ics27-acknowledgement.md) | ICS27 acknowledgement format | Accepted | +| [004](./adr-004-ics29-lock-fee-module.md) | ICS29 module locking upon escrow out of balance | Accepted | | [015](./adr-015-ibc-packet-receiver.md) | IBC Packet Routing | Accepted | | [025](./adr-025-ibc-passive-channels.md) | IBC passive channels | Deprecated | | [026](./adr-026-ibc-client-recovery-mechanisms.md) | IBC client recovery mechansisms | Accepted | diff --git a/docs/architecture/adr-004-ics29-lock-fee-module.md b/docs/architecture/adr-004-ics29-lock-fee-module.md new file mode 100644 index 00000000000..5b17717e669 --- /dev/null +++ b/docs/architecture/adr-004-ics29-lock-fee-module.md @@ -0,0 +1,55 @@ +# ADR 004: Lock fee module upon escrow out of balance + +## Changelog +* 03/03/2022: initial draft + +## Status + +Accepted + +## Context + +The fee module maintains an escrow account for all fees escrowed to incentivize packet relays. +It also tracks each packet fee escrowed separately from the escrow account. This is because the escrow account only maintains a total balance. It has no reference for which coins belonged to which packet fee. +In the presence of a severe bug, it is possible the escrow balance will become out of sync with the packet fees marked as escrowed. +The ICS29 module should be capable of elegantly handling such a scenario. + +## Decision + +We will allow for the ICS29 module to become "locked" if the escrow balance is determined to be out of sync with the packet fees marked as escrowed. +A "locked" fee module will not allow for packet escrows to occur nor will it distribute fees. All IBC callbacks will skip performing fee logic, similar to fee disabled channels. + +Manual intervention will be needed to unlock the fee module. + +### Sending side + +Special behaviour will have to be accounted for in `OnAcknowledgementPacket`. Since the counterparty will continue to send incentivized acknowledgements for fee enabled channels, the acknowledgement will still need to be unmarshalled into an incentivized acknowledgement before calling the underlying application `OnAcknowledgePacket` callback. + +When distributing fees, a cached context should be used. If the escrow account balance would become negative, the current state changes should be discarded and the fee module should be locked using the uncached context. This prevents fees from being partially distributed for a given packetID. + +### Receiving side + +`OnRecvPacket` should remain unaffected by the fee module becoming locked since escrow accounts only affect the sending side. + +## Consequences + +### Positive + +The fee module can be elegantly disabled in the presence of severe bugs. + +### Negative + +Extra logic is added to account for edge cases which are only possible in the presence of bugs. + +### Neutral + +## References + +Issues: +- [#821](https://github.com/cosmos/ibc-go/issues/821) +- [#860](https://github.com/cosmos/ibc-go/issues/860) + +PR's: +- [#1031](https://github.com/cosmos/ibc-go/pull/1031) +- [#1029](https://github.com/cosmos/ibc-go/pull/1029) +- [#1056](https://github.com/cosmos/ibc-go/pull/1056) diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index abcc6597743..539b8bb2c77 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -4,6 +4,89 @@ ## Table of Contents +- [ibc/applications/fee/v1/ack.proto](#ibc/applications/fee/v1/ack.proto) + - [IncentivizedAcknowledgement](#ibc.applications.fee.v1.IncentivizedAcknowledgement) + +- [ibc/core/client/v1/client.proto](#ibc/core/client/v1/client.proto) + - [ClientConsensusStates](#ibc.core.client.v1.ClientConsensusStates) + - [ClientUpdateProposal](#ibc.core.client.v1.ClientUpdateProposal) + - [ConsensusStateWithHeight](#ibc.core.client.v1.ConsensusStateWithHeight) + - [Height](#ibc.core.client.v1.Height) + - [IdentifiedClientState](#ibc.core.client.v1.IdentifiedClientState) + - [Params](#ibc.core.client.v1.Params) + - [UpgradeProposal](#ibc.core.client.v1.UpgradeProposal) + +- [ibc/core/channel/v1/channel.proto](#ibc/core/channel/v1/channel.proto) + - [Acknowledgement](#ibc.core.channel.v1.Acknowledgement) + - [Channel](#ibc.core.channel.v1.Channel) + - [Counterparty](#ibc.core.channel.v1.Counterparty) + - [IdentifiedChannel](#ibc.core.channel.v1.IdentifiedChannel) + - [Packet](#ibc.core.channel.v1.Packet) + - [PacketId](#ibc.core.channel.v1.PacketId) + - [PacketState](#ibc.core.channel.v1.PacketState) + + - [Order](#ibc.core.channel.v1.Order) + - [State](#ibc.core.channel.v1.State) + +- [ibc/applications/fee/v1/fee.proto](#ibc/applications/fee/v1/fee.proto) + - [Fee](#ibc.applications.fee.v1.Fee) + - [IdentifiedPacketFees](#ibc.applications.fee.v1.IdentifiedPacketFees) + - [PacketFee](#ibc.applications.fee.v1.PacketFee) + - [PacketFees](#ibc.applications.fee.v1.PacketFees) + +- [ibc/applications/fee/v1/genesis.proto](#ibc/applications/fee/v1/genesis.proto) + - [FeeEnabledChannel](#ibc.applications.fee.v1.FeeEnabledChannel) + - [ForwardRelayerAddress](#ibc.applications.fee.v1.ForwardRelayerAddress) + - [GenesisState](#ibc.applications.fee.v1.GenesisState) + - [RegisteredRelayerAddress](#ibc.applications.fee.v1.RegisteredRelayerAddress) + +- [ibc/applications/fee/v1/metadata.proto](#ibc/applications/fee/v1/metadata.proto) + - [Metadata](#ibc.applications.fee.v1.Metadata) + +- [ibc/applications/fee/v1/query.proto](#ibc/applications/fee/v1/query.proto) + - [QueryIncentivizedPacketRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketRequest) + - [QueryIncentivizedPacketResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketResponse) + - [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) + - [QueryIncentivizedPacketsForChannelResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse) + - [QueryIncentivizedPacketsRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsRequest) + - [QueryIncentivizedPacketsResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsResponse) + - [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) + - [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) + - [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) + - [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) + - [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) + - [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) + + - [Query](#ibc.applications.fee.v1.Query) + +- [ibc/applications/fee/v1/tx.proto](#ibc/applications/fee/v1/tx.proto) + - [MsgPayPacketFee](#ibc.applications.fee.v1.MsgPayPacketFee) + - [MsgPayPacketFeeAsync](#ibc.applications.fee.v1.MsgPayPacketFeeAsync) + - [MsgPayPacketFeeAsyncResponse](#ibc.applications.fee.v1.MsgPayPacketFeeAsyncResponse) + - [MsgPayPacketFeeResponse](#ibc.applications.fee.v1.MsgPayPacketFeeResponse) + - [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress) + - [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse) + + - [Msg](#ibc.applications.fee.v1.Msg) + +- [ibc/applications/interchain_accounts/controller/v1/controller.proto](#ibc/applications/interchain_accounts/controller/v1/controller.proto) + - [Params](#ibc.applications.interchain_accounts.controller.v1.Params) + +- [ibc/applications/interchain_accounts/controller/v1/query.proto](#ibc/applications/interchain_accounts/controller/v1/query.proto) + - [QueryParamsRequest](#ibc.applications.interchain_accounts.controller.v1.QueryParamsRequest) + - [QueryParamsResponse](#ibc.applications.interchain_accounts.controller.v1.QueryParamsResponse) + + - [Query](#ibc.applications.interchain_accounts.controller.v1.Query) + +- [ibc/applications/interchain_accounts/host/v1/host.proto](#ibc/applications/interchain_accounts/host/v1/host.proto) + - [Params](#ibc.applications.interchain_accounts.host.v1.Params) + +- [ibc/applications/interchain_accounts/host/v1/query.proto](#ibc/applications/interchain_accounts/host/v1/query.proto) + - [QueryParamsRequest](#ibc.applications.interchain_accounts.host.v1.QueryParamsRequest) + - [QueryParamsResponse](#ibc.applications.interchain_accounts.host.v1.QueryParamsResponse) + + - [Query](#ibc.applications.interchain_accounts.host.v1.Query) + - [ibc/applications/interchain_accounts/v1/account.proto](#ibc/applications/interchain_accounts/v1/account.proto) - [InterchainAccount](#ibc.applications.interchain_accounts.v1.InterchainAccount) @@ -42,15 +125,6 @@ - [Query](#ibc.applications.transfer.v1.Query) -- [ibc/core/client/v1/client.proto](#ibc/core/client/v1/client.proto) - - [ClientConsensusStates](#ibc.core.client.v1.ClientConsensusStates) - - [ClientUpdateProposal](#ibc.core.client.v1.ClientUpdateProposal) - - [ConsensusStateWithHeight](#ibc.core.client.v1.ConsensusStateWithHeight) - - [Height](#ibc.core.client.v1.Height) - - [IdentifiedClientState](#ibc.core.client.v1.IdentifiedClientState) - - [Params](#ibc.core.client.v1.Params) - - [UpgradeProposal](#ibc.core.client.v1.UpgradeProposal) - - [ibc/applications/transfer/v1/tx.proto](#ibc/applications/transfer/v1/tx.proto) - [MsgTransfer](#ibc.applications.transfer.v1.MsgTransfer) - [MsgTransferResponse](#ibc.applications.transfer.v1.MsgTransferResponse) @@ -60,17 +134,6 @@ - [ibc/applications/transfer/v2/packet.proto](#ibc/applications/transfer/v2/packet.proto) - [FungibleTokenPacketData](#ibc.applications.transfer.v2.FungibleTokenPacketData) -- [ibc/core/channel/v1/channel.proto](#ibc/core/channel/v1/channel.proto) - - [Acknowledgement](#ibc.core.channel.v1.Acknowledgement) - - [Channel](#ibc.core.channel.v1.Channel) - - [Counterparty](#ibc.core.channel.v1.Counterparty) - - [IdentifiedChannel](#ibc.core.channel.v1.IdentifiedChannel) - - [Packet](#ibc.core.channel.v1.Packet) - - [PacketState](#ibc.core.channel.v1.PacketState) - - - [Order](#ibc.core.channel.v1.Order) - - [State](#ibc.core.channel.v1.State) - - [ibc/core/channel/v1/genesis.proto](#ibc/core/channel/v1/genesis.proto) - [GenesisState](#ibc.core.channel.v1.GenesisState) - [PacketSequence](#ibc.core.channel.v1.PacketSequence) @@ -271,23 +334,24 @@ - +

    Top

    -## ibc/applications/interchain_accounts/v1/account.proto +## ibc/applications/fee/v1/ack.proto - + -### InterchainAccount -An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain +### IncentivizedAcknowledgement +IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `base_account` | [cosmos.auth.v1beta1.BaseAccount](#cosmos.auth.v1beta1.BaseAccount) | | | -| `account_owner` | [string](#string) | | | +| `result` | [bytes](#bytes) | | the underlying app acknowledgement result bytes | +| `forward_relayer_address` | [string](#string) | | the relayer address which submits the recv packet message | +| `underlying_app_success` | [bool](#bool) | | success flag of the base application callback | @@ -303,130 +367,138 @@ An InterchainAccount is defined as a BaseAccount & the address of the account ow - +

    Top

    -## ibc/applications/interchain_accounts/v1/genesis.proto +## ibc/core/client/v1/client.proto - + -### ActiveChannel -ActiveChannel contains a connection ID, port ID and associated active channel ID +### ClientConsensusStates +ClientConsensusStates defines all the stored consensus states for a given +client. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `connection_id` | [string](#string) | | | -| `port_id` | [string](#string) | | | -| `channel_id` | [string](#string) | | | +| `client_id` | [string](#string) | | client identifier | +| `consensus_states` | [ConsensusStateWithHeight](#ibc.core.client.v1.ConsensusStateWithHeight) | repeated | consensus states and their heights associated with the client | - + -### ControllerGenesisState -ControllerGenesisState defines the interchain accounts controller genesis state +### ClientUpdateProposal +ClientUpdateProposal is a governance proposal. If it passes, the substitute +client's latest consensus state is copied over to the subject client. The proposal +handler may fail if the subject and the substitute do not match in client and +chain parameters (with exception to latest height, frozen height, and chain-id). | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `active_channels` | [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) | repeated | | -| `interchain_accounts` | [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) | repeated | | -| `ports` | [string](#string) | repeated | | -| `params` | [ibc.applications.interchain_accounts.controller.v1.Params](#ibc.applications.interchain_accounts.controller.v1.Params) | | | +| `title` | [string](#string) | | the title of the update proposal | +| `description` | [string](#string) | | the description of the proposal | +| `subject_client_id` | [string](#string) | | the client identifier for the client to be updated if the proposal passes | +| `substitute_client_id` | [string](#string) | | the substitute client identifier for the client standing in for the subject client | - + -### GenesisState -GenesisState defines the interchain accounts genesis state +### ConsensusStateWithHeight +ConsensusStateWithHeight defines a consensus state with an additional height +field. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `controller_genesis_state` | [ControllerGenesisState](#ibc.applications.interchain_accounts.v1.ControllerGenesisState) | | | -| `host_genesis_state` | [HostGenesisState](#ibc.applications.interchain_accounts.v1.HostGenesisState) | | | +| `height` | [Height](#ibc.core.client.v1.Height) | | consensus state height | +| `consensus_state` | [google.protobuf.Any](#google.protobuf.Any) | | consensus state | - + -### HostGenesisState -HostGenesisState defines the interchain accounts host genesis state +### Height +Height is a monotonically increasing data type +that can be compared against another Height for the purposes of updating and +freezing clients + +Normally the RevisionHeight is incremented at each height while keeping +RevisionNumber the same. However some consensus algorithms may choose to +reset the height in certain conditions e.g. hard forks, state-machine +breaking changes In these cases, the RevisionNumber is incremented so that +height continues to be monitonically increasing even as the RevisionHeight +gets reset | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `active_channels` | [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) | repeated | | -| `interchain_accounts` | [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) | repeated | | -| `port` | [string](#string) | | | -| `params` | [ibc.applications.interchain_accounts.host.v1.Params](#ibc.applications.interchain_accounts.host.v1.Params) | | | +| `revision_number` | [uint64](#uint64) | | the revision that the client is currently on | +| `revision_height` | [uint64](#uint64) | | the height within the given revision | - + -### RegisteredInterchainAccount -RegisteredInterchainAccount contains a connection ID, port ID and associated interchain account address +### IdentifiedClientState +IdentifiedClientState defines a client state with an additional client +identifier field. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `connection_id` | [string](#string) | | | -| `port_id` | [string](#string) | | | -| `account_address` | [string](#string) | | | +| `client_id` | [string](#string) | | client identifier | +| `client_state` | [google.protobuf.Any](#google.protobuf.Any) | | client state | - - + - +### Params +Params defines the set of IBC light client parameters. - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `allowed_clients` | [string](#string) | repeated | allowed_clients defines the list of allowed client state types. | - -

    Top

    -## ibc/applications/interchain_accounts/v1/metadata.proto - + -### Metadata -Metadata defines a set of protocol specific data encoded into the ICS27 channel version bytestring -See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning +### UpgradeProposal +UpgradeProposal is a gov Content type for initiating an IBC breaking +upgrade. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `version` | [string](#string) | | version defines the ICS27 protocol version | -| `controller_connection_id` | [string](#string) | | controller_connection_id is the connection identifier associated with the controller chain | -| `host_connection_id` | [string](#string) | | host_connection_id is the connection identifier associated with the host chain | -| `address` | [string](#string) | | address defines the interchain account address to be fulfilled upon the OnChanOpenTry handshake step NOTE: the address field is empty on the OnChanOpenInit handshake step | -| `encoding` | [string](#string) | | encoding defines the supported codec format | -| `tx_type` | [string](#string) | | tx_type defines the type of transactions the interchain account can execute | +| `title` | [string](#string) | | | +| `description` | [string](#string) | | | +| `plan` | [cosmos.upgrade.v1beta1.Plan](#cosmos.upgrade.v1beta1.Plan) | | | +| `upgraded_client_state` | [google.protobuf.Any](#google.protobuf.Any) | | An UpgradedClientState must be provided to perform an IBC breaking upgrade. This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the previous version of the chain. This will allow IBC connections to persist smoothly across planned chain upgrades | @@ -442,137 +514,150 @@ See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel- - +

    Top

    -## ibc/applications/interchain_accounts/v1/packet.proto +## ibc/core/channel/v1/channel.proto - + -### CosmosTx -CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. +### Acknowledgement +Acknowledgement is the recommended acknowledgement format to be used by +app-specific protocols. +NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental +conflicts with other protobuf message formats used for acknowledgements. +The first byte of any message with this format will be the non-ASCII values +`0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: +https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `messages` | [google.protobuf.Any](#google.protobuf.Any) | repeated | | +| `result` | [bytes](#bytes) | | | +| `error` | [string](#string) | | | - + -### InterchainAccountPacketData -InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. +### Channel +Channel defines pipeline for exactly-once packet delivery between specific +modules on separate blockchains, which has at least one end capable of +sending packets and one end capable of receiving packets. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `type` | [Type](#ibc.applications.interchain_accounts.v1.Type) | | | -| `data` | [bytes](#bytes) | | | -| `memo` | [string](#string) | | | - - - - - - +| `state` | [State](#ibc.core.channel.v1.State) | | current state of the channel end | +| `ordering` | [Order](#ibc.core.channel.v1.Order) | | whether the channel is ordered or unordered | +| `counterparty` | [Counterparty](#ibc.core.channel.v1.Counterparty) | | counterparty channel end | +| `connection_hops` | [string](#string) | repeated | list of connection identifiers, in order, along which packets sent on this channel will travel | +| `version` | [string](#string) | | opaque channel version, which is agreed upon during the handshake | - -### Type -Type defines a classification of message issued from a controller chain to its associated interchain accounts -host -| Name | Number | Description | -| ---- | ------ | ----------- | -| TYPE_UNSPECIFIED | 0 | Default zero value enumeration | -| TYPE_EXECUTE_TX | 1 | Execute a transaction on an interchain accounts host chain | - + - +### Counterparty +Counterparty defines a channel end counterparty - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | port on the counterparty chain which owns the other end of the channel. | +| `channel_id` | [string](#string) | | channel end on the counterparty chain | - -

    Top

    -## ibc/applications/transfer/v1/transfer.proto - + -### DenomTrace -DenomTrace contains the base denomination for ICS20 fungible tokens and the -source tracing information path. +### IdentifiedChannel +IdentifiedChannel defines a channel with additional port and channel +identifier fields. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `path` | [string](#string) | | path defines the chain of port/channel identifiers used for tracing the source of the fungible token. | -| `base_denom` | [string](#string) | | base denomination of the relayed fungible token. | - +| `state` | [State](#ibc.core.channel.v1.State) | | current state of the channel end | +| `ordering` | [Order](#ibc.core.channel.v1.Order) | | whether the channel is ordered or unordered | +| `counterparty` | [Counterparty](#ibc.core.channel.v1.Counterparty) | | counterparty channel end | +| `connection_hops` | [string](#string) | repeated | list of connection identifiers, in order, along which packets sent on this channel will travel | +| `version` | [string](#string) | | opaque channel version, which is agreed upon during the handshake | +| `port_id` | [string](#string) | | port identifier | +| `channel_id` | [string](#string) | | channel identifier | - -### Params -Params defines the set of IBC transfer parameters. -NOTE: To prevent a single token from being transferred, set the -TransfersEnabled parameter to true and then set the bank module's SendEnabled -parameter for the denomination to false. + + +### Packet +Packet defines a type that carries data across different chains through IBC | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `send_enabled` | [bool](#bool) | | send_enabled enables or disables all cross-chain token transfers from this chain. | -| `receive_enabled` | [bool](#bool) | | receive_enabled enables or disables all cross-chain token transfers to this chain. | +| `sequence` | [uint64](#uint64) | | number corresponds to the order of sends and receives, where a Packet with an earlier sequence number must be sent and received before a Packet with a later sequence number. | +| `source_port` | [string](#string) | | identifies the port on the sending chain. | +| `source_channel` | [string](#string) | | identifies the channel end on the sending chain. | +| `destination_port` | [string](#string) | | identifies the port on the receiving chain. | +| `destination_channel` | [string](#string) | | identifies the channel end on the receiving chain. | +| `data` | [bytes](#bytes) | | actual opaque bytes transferred directly to the application module | +| `timeout_height` | [ibc.core.client.v1.Height](#ibc.core.client.v1.Height) | | block height after which the packet times out | +| `timeout_timestamp` | [uint64](#uint64) | | block timestamp (in nanoseconds) after which the packet times out | - - + - +### PacketId +PacketId is an identifer for a unique Packet +Source chains refer to packets by source port/channel +Destination chains refer to packets by destination port/channel - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | channel port identifier | +| `channel_id` | [string](#string) | | channel unique identifier | +| `sequence` | [uint64](#uint64) | | packet sequence | - -

    Top

    -## ibc/applications/transfer/v1/genesis.proto - + -### GenesisState -GenesisState defines the ibc-transfer genesis state +### PacketState +PacketState defines the generic type necessary to retrieve and store +packet commitments, acknowledgements, and receipts. +Caller is responsible for knowing the context necessary to interpret this +state as a commitment, acknowledgement, or a receipt. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `port_id` | [string](#string) | | | -| `denom_traces` | [DenomTrace](#ibc.applications.transfer.v1.DenomTrace) | repeated | | -| `params` | [Params](#ibc.applications.transfer.v1.Params) | | | +| `port_id` | [string](#string) | | channel port identifier. | +| `channel_id` | [string](#string) | | channel unique identifier. | +| `sequence` | [uint64](#uint64) | | packet sequence. | +| `data` | [bytes](#bytes) | | embedded data that represents packet state. | @@ -580,6 +665,35 @@ GenesisState defines the ibc-transfer genesis state + + + +### Order +Order defines if a channel is ORDERED or UNORDERED + +| Name | Number | Description | +| ---- | ------ | ----------- | +| ORDER_NONE_UNSPECIFIED | 0 | zero-value for channel ordering | +| ORDER_UNORDERED | 1 | packets can be delivered in any order, which may differ from the order in which they were sent. | +| ORDER_ORDERED | 2 | packets are delivered exactly in the order which they were sent | + + + + + +### State +State defines if a channel is in one of the following states: +CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| STATE_UNINITIALIZED_UNSPECIFIED | 0 | Default State | +| STATE_INIT | 1 | A channel has just started the opening handshake. | +| STATE_TRYOPEN | 2 | A channel has acknowledged the handshake step on the counterparty chain. | +| STATE_OPEN | 3 | A channel has completed the handshake. Open channels are ready to send and receive packets. | +| STATE_CLOSED | 4 | A channel has been closed and can no longer be used to send or receive packets. | + + @@ -588,129 +702,155 @@ GenesisState defines the ibc-transfer genesis state - +

    Top

    -## ibc/applications/transfer/v1/query.proto +## ibc/applications/fee/v1/fee.proto - + -### QueryDenomHashRequest -QueryDenomHashRequest is the request type for the Query/DenomHash RPC -method +### Fee +Fee defines the ICS29 receive, acknowledgement and timeout fees | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `trace` | [string](#string) | | The denomination trace ([port_id]/[channel_id])+/[denom] | +| `recv_fee` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | the packet receive fee | +| `ack_fee` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | the packet acknowledgement fee | +| `timeout_fee` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | the packet timeout fee | - + -### QueryDenomHashResponse -QueryDenomHashResponse is the response type for the Query/DenomHash RPC -method. +### IdentifiedPacketFees +IdentifiedPacketFees contains a list of type PacketFee and associated PacketId | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `hash` | [string](#string) | | hash (in hex format) of the denomination trace information. | +| `packet_id` | [ibc.core.channel.v1.PacketId](#ibc.core.channel.v1.PacketId) | | unique packet identifier comprised of the channel ID, port ID and sequence | +| `packet_fees` | [PacketFee](#ibc.applications.fee.v1.PacketFee) | repeated | list of packet fees | - + -### QueryDenomTraceRequest -QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC -method +### PacketFee +PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `hash` | [string](#string) | | hash (in hex format) of the denomination trace information. | +| `fee` | [Fee](#ibc.applications.fee.v1.Fee) | | fee encapsulates the recv, ack and timeout fees associated with an IBC packet | +| `refund_address` | [string](#string) | | the refund address for unspent fees | +| `relayers` | [string](#string) | repeated | optional list of relayers permitted to receive fees | - + -### QueryDenomTraceResponse -QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC -method. +### PacketFees +PacketFees contains a list of type PacketFee | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `denom_trace` | [DenomTrace](#ibc.applications.transfer.v1.DenomTrace) | | denom_trace returns the requested denomination trace information. | +| `packet_fees` | [PacketFee](#ibc.applications.fee.v1.PacketFee) | repeated | list of packet fees | + - + -### QueryDenomTracesRequest -QueryConnectionsRequest is the request type for the Query/DenomTraces RPC -method + + + + + + + +

    Top

    + +## ibc/applications/fee/v1/genesis.proto + + + + + +### FeeEnabledChannel +FeeEnabledChannel contains the PortID & ChannelID for a fee enabled channel | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| `port_id` | [string](#string) | | unique port identifier | +| `channel_id` | [string](#string) | | unique channel identifier | - + -### QueryDenomTracesResponse -QueryConnectionsResponse is the response type for the Query/DenomTraces RPC -method. +### ForwardRelayerAddress +ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `denom_traces` | [DenomTrace](#ibc.applications.transfer.v1.DenomTrace) | repeated | denom_traces returns all denominations trace information. | -| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | +| `address` | [string](#string) | | the forward relayer address | +| `packet_id` | [ibc.core.channel.v1.PacketId](#ibc.core.channel.v1.PacketId) | | unique packet identifer comprised of the channel ID, port ID and sequence | - + -### QueryParamsRequest -QueryParamsRequest is the request type for the Query/Params RPC method. +### GenesisState +GenesisState defines the ICS29 fee middleware genesis state +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `identified_fees` | [IdentifiedPacketFees](#ibc.applications.fee.v1.IdentifiedPacketFees) | repeated | list of identified packet fees | +| `fee_enabled_channels` | [FeeEnabledChannel](#ibc.applications.fee.v1.FeeEnabledChannel) | repeated | list of fee enabled channels | +| `registered_relayers` | [RegisteredRelayerAddress](#ibc.applications.fee.v1.RegisteredRelayerAddress) | repeated | list of registered relayer addresses | +| `forward_relayers` | [ForwardRelayerAddress](#ibc.applications.fee.v1.ForwardRelayerAddress) | repeated | list of forward relayer addresses | - -### QueryParamsResponse -QueryParamsResponse is the response type for the Query/Params RPC method. + + + +### RegisteredRelayerAddress +RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `params` | [Params](#ibc.applications.transfer.v1.Params) | | params defines the parameters of the module. | +| `address` | [string](#string) | | the relayer address | +| `counterparty_address` | [string](#string) | | the counterparty relayer address | +| `channel_id` | [string](#string) | | unique channel identifier | @@ -722,250 +862,842 @@ QueryParamsResponse is the response type for the Query/Params RPC method. - - - -### Query -Query provides defines the gRPC querier service. - -| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | -| ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `DenomTrace` | [QueryDenomTraceRequest](#ibc.applications.transfer.v1.QueryDenomTraceRequest) | [QueryDenomTraceResponse](#ibc.applications.transfer.v1.QueryDenomTraceResponse) | DenomTrace queries a denomination trace information. | GET|/ibc/apps/transfer/v1/denom_traces/{hash}| -| `DenomTraces` | [QueryDenomTracesRequest](#ibc.applications.transfer.v1.QueryDenomTracesRequest) | [QueryDenomTracesResponse](#ibc.applications.transfer.v1.QueryDenomTracesResponse) | DenomTraces queries all denomination traces. | GET|/ibc/apps/transfer/v1/denom_traces| -| `Params` | [QueryParamsRequest](#ibc.applications.transfer.v1.QueryParamsRequest) | [QueryParamsResponse](#ibc.applications.transfer.v1.QueryParamsResponse) | Params queries all parameters of the ibc-transfer module. | GET|/ibc/apps/transfer/v1/params| -| `DenomHash` | [QueryDenomHashRequest](#ibc.applications.transfer.v1.QueryDenomHashRequest) | [QueryDenomHashResponse](#ibc.applications.transfer.v1.QueryDenomHashResponse) | DenomHash queries a denomination hash information. | GET|/ibc/apps/transfer/v1/denom_hashes/{trace}| - - +

    Top

    -## ibc/core/client/v1/client.proto +## ibc/applications/fee/v1/metadata.proto - + -### ClientConsensusStates -ClientConsensusStates defines all the stored consensus states for a given -client. +### Metadata +Metadata defines the ICS29 channel specific metadata encoded into the channel version bytestring +See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `client_id` | [string](#string) | | client identifier | -| `consensus_states` | [ConsensusStateWithHeight](#ibc.core.client.v1.ConsensusStateWithHeight) | repeated | consensus states and their heights associated with the client | +| `fee_version` | [string](#string) | | fee_version defines the ICS29 fee version | +| `app_version` | [string](#string) | | app_version defines the underlying application version, which may or may not be a JSON encoded bytestring | + - + -### ClientUpdateProposal -ClientUpdateProposal is a governance proposal. If it passes, the substitute -client's latest consensus state is copied over to the subject client. The proposal -handler may fail if the subject and the substitute do not match in client and -chain parameters (with exception to latest height, frozen height, and chain-id). + + -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `title` | [string](#string) | | the title of the update proposal | -| `description` | [string](#string) | | the description of the proposal | -| `subject_client_id` | [string](#string) | | the client identifier for the client to be updated if the proposal passes | -| `substitute_client_id` | [string](#string) | | the substitute client identifier for the client standing in for the subject client | + +

    Top

    +## ibc/applications/fee/v1/query.proto - + -### ConsensusStateWithHeight -ConsensusStateWithHeight defines a consensus state with an additional height -field. +### QueryIncentivizedPacketRequest +QueryIncentivizedPacketRequest defines the request type for the IncentivizedPacket rpc | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `height` | [Height](#ibc.core.client.v1.Height) | | consensus state height | -| `consensus_state` | [google.protobuf.Any](#google.protobuf.Any) | | consensus state | +| `packet_id` | [ibc.core.channel.v1.PacketId](#ibc.core.channel.v1.PacketId) | | unique packet identifier comprised of channel ID, port ID and sequence | +| `query_height` | [uint64](#uint64) | | block height at which to query | - - -### Height -Height is a monotonically increasing data type -that can be compared against another Height for the purposes of updating and -freezing clients + -Normally the RevisionHeight is incremented at each height while keeping -RevisionNumber the same. However some consensus algorithms may choose to -reset the height in certain conditions e.g. hard forks, state-machine -breaking changes In these cases, the RevisionNumber is incremented so that -height continues to be monitonically increasing even as the RevisionHeight -gets reset +### QueryIncentivizedPacketResponse +QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPacket rpc | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `revision_number` | [uint64](#uint64) | | the revision that the client is currently on | -| `revision_height` | [uint64](#uint64) | | the height within the given revision | +| `incentivized_packet` | [IdentifiedPacketFees](#ibc.applications.fee.v1.IdentifiedPacketFees) | | the identified fees for the incentivized packet | - + -### IdentifiedClientState -IdentifiedClientState defines a client state with an additional client -identifier field. +### QueryIncentivizedPacketsForChannelRequest +QueryIncentivizedPacketsForChannelRequest defines the request type for querying for all incentivized packets +for a specific channel | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `client_id` | [string](#string) | | client identifier | -| `client_state` | [google.protobuf.Any](#google.protobuf.Any) | | client state | +| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| `port_id` | [string](#string) | | | +| `channel_id` | [string](#string) | | | +| `query_height` | [uint64](#uint64) | | Height to query at | - + -### Params -Params defines the set of IBC light client parameters. +### QueryIncentivizedPacketsForChannelResponse +QueryIncentivizedPacketsResponse defines the response type for the incentivized packets RPC | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `allowed_clients` | [string](#string) | repeated | allowed_clients defines the list of allowed client state types. | +| `incentivized_packets` | [IdentifiedPacketFees](#ibc.applications.fee.v1.IdentifiedPacketFees) | repeated | Map of all incentivized_packets | - + -### UpgradeProposal -UpgradeProposal is a gov Content type for initiating an IBC breaking -upgrade. +### QueryIncentivizedPacketsRequest +QueryIncentivizedPacketsRequest defines the request type for the IncentivizedPackets rpc | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `title` | [string](#string) | | | -| `description` | [string](#string) | | | -| `plan` | [cosmos.upgrade.v1beta1.Plan](#cosmos.upgrade.v1beta1.Plan) | | | -| `upgraded_client_state` | [google.protobuf.Any](#google.protobuf.Any) | | An UpgradedClientState must be provided to perform an IBC breaking upgrade. This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs, so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the previous version of the chain. This will allow IBC connections to persist smoothly across planned chain upgrades | +| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| `query_height` | [uint64](#uint64) | | block height at which to query | - - + - +### QueryIncentivizedPacketsResponse +QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPackets rpc - +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `incentivized_packets` | [IdentifiedPacketFees](#ibc.applications.fee.v1.IdentifiedPacketFees) | repeated | list of identified fees for incentivized packets | - -

    Top

    -## ibc/applications/transfer/v1/tx.proto - + -### MsgTransfer -MsgTransfer defines a msg to transfer fungible tokens (i.e Coins) between -ICS20 enabled chains. See ICS Spec here: -https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures +### QueryTotalAckFeesRequest +QueryTotalAckFeesRequest defines the request type for the TotalAckFees rpc | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `source_port` | [string](#string) | | the port on which the packet will be sent | -| `source_channel` | [string](#string) | | the channel by which the packet will be sent | -| `token` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | the tokens to be transferred | -| `sender` | [string](#string) | | the sender address | -| `receiver` | [string](#string) | | the recipient address on the destination chain | -| `timeout_height` | [ibc.core.client.v1.Height](#ibc.core.client.v1.Height) | | Timeout height relative to the current block height. The timeout is disabled when set to 0. | -| `timeout_timestamp` | [uint64](#uint64) | | Timeout timestamp in absolute nanoseconds since unix epoch. The timeout is disabled when set to 0. | +| `packet_id` | [ibc.core.channel.v1.PacketId](#ibc.core.channel.v1.PacketId) | | the packet identifier for the associated fees | - + -### MsgTransferResponse -MsgTransferResponse defines the Msg/Transfer response type. +### QueryTotalAckFeesResponse +QueryTotalAckFeesResponse defines the response type for the TotalAckFees rpc +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `ack_fees` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | the total packet acknowledgement fees | - - - + - +### QueryTotalRecvFeesRequest +QueryTotalRecvFeesRequest defines the request type for the TotalRecvFees rpc -### Msg -Msg defines the ibc/transfer Msg service. -| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | -| ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `Transfer` | [MsgTransfer](#ibc.applications.transfer.v1.MsgTransfer) | [MsgTransferResponse](#ibc.applications.transfer.v1.MsgTransferResponse) | Transfer defines a rpc handler method for MsgTransfer. | | +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `packet_id` | [ibc.core.channel.v1.PacketId](#ibc.core.channel.v1.PacketId) | | the packet identifier for the associated fees | - - -

    Top

    -## ibc/applications/transfer/v2/packet.proto + +### QueryTotalRecvFeesResponse +QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees rpc - -### FungibleTokenPacketData -FungibleTokenPacketData defines a struct for the packet payload -See FungibleTokenPacketData spec: -https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `recv_fees` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | the total packet receive fees | + + + + + + + + +### QueryTotalTimeoutFeesRequest +QueryTotalTimeoutFeesRequest defines the request type for the TotalTimeoutFees rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `packet_id` | [ibc.core.channel.v1.PacketId](#ibc.core.channel.v1.PacketId) | | the packet identifier for the associated fees | + + + + + + + + +### QueryTotalTimeoutFeesResponse +QueryTotalTimeoutFeesResponse defines the response type for the TotalTimeoutFees rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `timeout_fees` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | the total packet timeout fees | + + + + + + + + + + + + + + +### Query +Query defines the ICS29 gRPC querier service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `IncentivizedPackets` | [QueryIncentivizedPacketsRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsRequest) | [QueryIncentivizedPacketsResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsResponse) | IncentivizedPackets returns all incentivized packets and their associated fees | GET|/ibc/apps/fee/v1/incentivized_packets| +| `IncentivizedPacket` | [QueryIncentivizedPacketRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketRequest) | [QueryIncentivizedPacketResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketResponse) | IncentivizedPacket returns all packet fees for a packet given its identifier | GET|/ibc/apps/fee/v1/incentivized_packet/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| +| `IncentivizedPacketsForChannel` | [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) | [QueryIncentivizedPacketsForChannelResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse) | Gets all incentivized packets for a specific channel | GET|/ibc/apps/fee/v1/incentivized_packets/{port_id}/{channel_id}| +| `TotalRecvFees` | [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) | [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) | TotalRecvFees returns the total receive fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_recv_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| +| `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| +| `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| + + + + + + +

    Top

    + +## ibc/applications/fee/v1/tx.proto + + + + + +### MsgPayPacketFee +MsgPayPacketFee defines the request type for the PayPacketFee rpc +This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be +paid for + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `fee` | [Fee](#ibc.applications.fee.v1.Fee) | | fee encapsulates the recv, ack and timeout fees associated with an IBC packet | +| `source_port_id` | [string](#string) | | the source port unique identifier | +| `source_channel_id` | [string](#string) | | the source channel unique identifer | +| `signer` | [string](#string) | | account address to refund fee if necessary | +| `relayers` | [string](#string) | repeated | optional list of relayers permitted to the receive packet fees | + + + + + + + + +### MsgPayPacketFeeAsync +MsgPayPacketFeeAsync defines the request type for the PayPacketFeeAsync rpc +This Msg can be used to pay for a packet at a specified sequence (instead of the next sequence send) + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `packet_id` | [ibc.core.channel.v1.PacketId](#ibc.core.channel.v1.PacketId) | | unique packet identifier comprised of the channel ID, port ID and sequence | +| `packet_fee` | [PacketFee](#ibc.applications.fee.v1.PacketFee) | | the packet fee associated with a particular IBC packet | + + + + + + + + +### MsgPayPacketFeeAsyncResponse +MsgPayPacketFeeAsyncResponse defines the response type for the PayPacketFeeAsync rpc + + + + + + + + +### MsgPayPacketFeeResponse +MsgPayPacketFeeResponse defines the response type for the PayPacketFee rpc + + + + + + + + +### MsgRegisterCounterpartyAddress +MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `address` | [string](#string) | | the relayer address | +| `counterparty_address` | [string](#string) | | the counterparty relayer address | +| `channel_id` | [string](#string) | | unique channel identifier | + + + + + + + + +### MsgRegisterCounterpartyAddressResponse +MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc + + + + + + + + + + + + + + +### Msg +Msg defines the ICS29 Msg service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `RegisterCounterpartyAddress` | [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress) | [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse) | RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying. This ensures they will be properly compensated for forward relaying since destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function may be called more than once by a relayer, in which case, latest counterparty address is always used. | | +| `PayPacketFee` | [MsgPayPacketFee](#ibc.applications.fee.v1.MsgPayPacketFee) | [MsgPayPacketFeeResponse](#ibc.applications.fee.v1.MsgPayPacketFeeResponse) | PayPacketFee defines a rpc handler method for MsgPayPacketFee PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to incentivize the relaying of the packet at the next sequence NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows initiates the lifecycle of the incentivized packet | | +| `PayPacketFeeAsync` | [MsgPayPacketFeeAsync](#ibc.applications.fee.v1.MsgPayPacketFeeAsync) | [MsgPayPacketFeeAsyncResponse](#ibc.applications.fee.v1.MsgPayPacketFeeAsyncResponse) | PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to incentivize the relaying of a known packet (i.e. at a particular sequence) | | + + + + + + +

    Top

    + +## ibc/applications/interchain_accounts/controller/v1/controller.proto + + + + + +### Params +Params defines the set of on-chain interchain accounts parameters. +The following parameters may be used to disable the controller submodule. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `controller_enabled` | [bool](#bool) | | controller_enabled enables or disables the controller submodule. | + + + + + + + + + + + + + + + + +

    Top

    + +## ibc/applications/interchain_accounts/controller/v1/query.proto + + + + + +### QueryParamsRequest +QueryParamsRequest is the request type for the Query/Params RPC method. + + + + + + + + +### QueryParamsResponse +QueryParamsResponse is the response type for the Query/Params RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `params` | [Params](#ibc.applications.interchain_accounts.controller.v1.Params) | | params defines the parameters of the module. | + + + + + + + + + + + + + + +### Query +Query provides defines the gRPC querier service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Params` | [QueryParamsRequest](#ibc.applications.interchain_accounts.controller.v1.QueryParamsRequest) | [QueryParamsResponse](#ibc.applications.interchain_accounts.controller.v1.QueryParamsResponse) | Params queries all parameters of the ICA controller submodule. | GET|/ibc/apps/interchain_accounts/controller/v1/params| + + + + + + +

    Top

    + +## ibc/applications/interchain_accounts/host/v1/host.proto + + + + + +### Params +Params defines the set of on-chain interchain accounts parameters. +The following parameters may be used to disable the host submodule. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `host_enabled` | [bool](#bool) | | host_enabled enables or disables the host submodule. | +| `allow_messages` | [string](#string) | repeated | allow_messages defines a list of sdk message typeURLs allowed to be executed on a host chain. | + + + + + + + + + + + + + + + + +

    Top

    + +## ibc/applications/interchain_accounts/host/v1/query.proto + + + + + +### QueryParamsRequest +QueryParamsRequest is the request type for the Query/Params RPC method. + + + + + + + + +### QueryParamsResponse +QueryParamsResponse is the response type for the Query/Params RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `params` | [Params](#ibc.applications.interchain_accounts.host.v1.Params) | | params defines the parameters of the module. | + + + + + + + + + + + + + + +### Query +Query provides defines the gRPC querier service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Params` | [QueryParamsRequest](#ibc.applications.interchain_accounts.host.v1.QueryParamsRequest) | [QueryParamsResponse](#ibc.applications.interchain_accounts.host.v1.QueryParamsResponse) | Params queries all parameters of the ICA host submodule. | GET|/ibc/apps/interchain_accounts/host/v1/params| + + + + + + +

    Top

    + +## ibc/applications/interchain_accounts/v1/account.proto + + + + + +### InterchainAccount +An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `base_account` | [cosmos.auth.v1beta1.BaseAccount](#cosmos.auth.v1beta1.BaseAccount) | | | +| `account_owner` | [string](#string) | | | + + + + + + + + + + + + + + + + +

    Top

    + +## ibc/applications/interchain_accounts/v1/genesis.proto + + + + + +### ActiveChannel +ActiveChannel contains a connection ID, port ID and associated active channel ID + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `connection_id` | [string](#string) | | | +| `port_id` | [string](#string) | | | +| `channel_id` | [string](#string) | | | + + + + + + + + +### ControllerGenesisState +ControllerGenesisState defines the interchain accounts controller genesis state + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `active_channels` | [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) | repeated | | +| `interchain_accounts` | [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) | repeated | | +| `ports` | [string](#string) | repeated | | +| `params` | [ibc.applications.interchain_accounts.controller.v1.Params](#ibc.applications.interchain_accounts.controller.v1.Params) | | | + + + + + + + + +### GenesisState +GenesisState defines the interchain accounts genesis state + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `controller_genesis_state` | [ControllerGenesisState](#ibc.applications.interchain_accounts.v1.ControllerGenesisState) | | | +| `host_genesis_state` | [HostGenesisState](#ibc.applications.interchain_accounts.v1.HostGenesisState) | | | + + + + + + + + +### HostGenesisState +HostGenesisState defines the interchain accounts host genesis state + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `active_channels` | [ActiveChannel](#ibc.applications.interchain_accounts.v1.ActiveChannel) | repeated | | +| `interchain_accounts` | [RegisteredInterchainAccount](#ibc.applications.interchain_accounts.v1.RegisteredInterchainAccount) | repeated | | +| `port` | [string](#string) | | | +| `params` | [ibc.applications.interchain_accounts.host.v1.Params](#ibc.applications.interchain_accounts.host.v1.Params) | | | + + + + + + + + +### RegisteredInterchainAccount +RegisteredInterchainAccount contains a connection ID, port ID and associated interchain account address + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `connection_id` | [string](#string) | | | +| `port_id` | [string](#string) | | | +| `account_address` | [string](#string) | | | + + + + + + + + + + + + + + + + +

    Top

    + +## ibc/applications/interchain_accounts/v1/metadata.proto + + + + + +### Metadata +Metadata defines a set of protocol specific data encoded into the ICS27 channel version bytestring +See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `version` | [string](#string) | | version defines the ICS27 protocol version | +| `controller_connection_id` | [string](#string) | | controller_connection_id is the connection identifier associated with the controller chain | +| `host_connection_id` | [string](#string) | | host_connection_id is the connection identifier associated with the host chain | +| `address` | [string](#string) | | address defines the interchain account address to be fulfilled upon the OnChanOpenTry handshake step NOTE: the address field is empty on the OnChanOpenInit handshake step | +| `encoding` | [string](#string) | | encoding defines the supported codec format | +| `tx_type` | [string](#string) | | tx_type defines the type of transactions the interchain account can execute | + + + + + + + + + + + + + + + + +

    Top

    + +## ibc/applications/interchain_accounts/v1/packet.proto + + + + + +### CosmosTx +CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `messages` | [google.protobuf.Any](#google.protobuf.Any) | repeated | | + + + + + + + + +### InterchainAccountPacketData +InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `type` | [Type](#ibc.applications.interchain_accounts.v1.Type) | | | +| `data` | [bytes](#bytes) | | | +| `memo` | [string](#string) | | | + + + + + + + + + + +### Type +Type defines a classification of message issued from a controller chain to its associated interchain accounts +host + +| Name | Number | Description | +| ---- | ------ | ----------- | +| TYPE_UNSPECIFIED | 0 | Default zero value enumeration | +| TYPE_EXECUTE_TX | 1 | Execute a transaction on an interchain accounts host chain | + + + + + + + + + + + +

    Top

    + +## ibc/applications/transfer/v1/transfer.proto + + + + + +### DenomTrace +DenomTrace contains the base denomination for ICS20 fungible tokens and the +source tracing information path. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `path` | [string](#string) | | path defines the chain of port/channel identifiers used for tracing the source of the fungible token. | +| `base_denom` | [string](#string) | | base denomination of the relayed fungible token. | + + + + + + + + +### Params +Params defines the set of IBC transfer parameters. +NOTE: To prevent a single token from being transferred, set the +TransfersEnabled parameter to true and then set the bank module's SendEnabled +parameter for the denomination to false. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `send_enabled` | [bool](#bool) | | send_enabled enables or disables all cross-chain token transfers from this chain. | +| `receive_enabled` | [bool](#bool) | | receive_enabled enables or disables all cross-chain token transfers to this chain. | + + + + + + + + + + + + + + + + +

    Top

    + +## ibc/applications/transfer/v1/genesis.proto + + + + + +### GenesisState +GenesisState defines the ibc-transfer genesis state | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `denom` | [string](#string) | | the token denomination to be transferred | -| `amount` | [string](#string) | | the token amount to be transferred | -| `sender` | [string](#string) | | the sender address | -| `receiver` | [string](#string) | | the recipient address on the destination chain | +| `port_id` | [string](#string) | | | +| `denom_traces` | [DenomTrace](#ibc.applications.transfer.v1.DenomTrace) | repeated | | +| `params` | [Params](#ibc.applications.transfer.v1.Params) | | | @@ -981,131 +1713,129 @@ https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transf - +

    Top

    -## ibc/core/channel/v1/channel.proto +## ibc/applications/transfer/v1/query.proto - + -### Acknowledgement -Acknowledgement is the recommended acknowledgement format to be used by -app-specific protocols. -NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental -conflicts with other protobuf message formats used for acknowledgements. -The first byte of any message with this format will be the non-ASCII values -`0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: -https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope +### QueryDenomHashRequest +QueryDenomHashRequest is the request type for the Query/DenomHash RPC +method | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `result` | [bytes](#bytes) | | | -| `error` | [string](#string) | | | +| `trace` | [string](#string) | | The denomination trace ([port_id]/[channel_id])+/[denom] | - + -### Channel -Channel defines pipeline for exactly-once packet delivery between specific -modules on separate blockchains, which has at least one end capable of -sending packets and one end capable of receiving packets. +### QueryDenomHashResponse +QueryDenomHashResponse is the response type for the Query/DenomHash RPC +method. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `state` | [State](#ibc.core.channel.v1.State) | | current state of the channel end | -| `ordering` | [Order](#ibc.core.channel.v1.Order) | | whether the channel is ordered or unordered | -| `counterparty` | [Counterparty](#ibc.core.channel.v1.Counterparty) | | counterparty channel end | -| `connection_hops` | [string](#string) | repeated | list of connection identifiers, in order, along which packets sent on this channel will travel | -| `version` | [string](#string) | | opaque channel version, which is agreed upon during the handshake | +| `hash` | [string](#string) | | hash (in hex format) of the denomination trace information. | - + -### Counterparty -Counterparty defines a channel end counterparty +### QueryDenomTraceRequest +QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC +method | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `port_id` | [string](#string) | | port on the counterparty chain which owns the other end of the channel. | -| `channel_id` | [string](#string) | | channel end on the counterparty chain | +| `hash` | [string](#string) | | hash (in hex format) of the denomination trace information. | - + -### IdentifiedChannel -IdentifiedChannel defines a channel with additional port and channel -identifier fields. +### QueryDenomTraceResponse +QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC +method. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `state` | [State](#ibc.core.channel.v1.State) | | current state of the channel end | -| `ordering` | [Order](#ibc.core.channel.v1.Order) | | whether the channel is ordered or unordered | -| `counterparty` | [Counterparty](#ibc.core.channel.v1.Counterparty) | | counterparty channel end | -| `connection_hops` | [string](#string) | repeated | list of connection identifiers, in order, along which packets sent on this channel will travel | -| `version` | [string](#string) | | opaque channel version, which is agreed upon during the handshake | -| `port_id` | [string](#string) | | port identifier | -| `channel_id` | [string](#string) | | channel identifier | +| `denom_trace` | [DenomTrace](#ibc.applications.transfer.v1.DenomTrace) | | denom_trace returns the requested denomination trace information. | - + -### Packet -Packet defines a type that carries data across different chains through IBC +### QueryDenomTracesRequest +QueryConnectionsRequest is the request type for the Query/DenomTraces RPC +method | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `sequence` | [uint64](#uint64) | | number corresponds to the order of sends and receives, where a Packet with an earlier sequence number must be sent and received before a Packet with a later sequence number. | -| `source_port` | [string](#string) | | identifies the port on the sending chain. | -| `source_channel` | [string](#string) | | identifies the channel end on the sending chain. | -| `destination_port` | [string](#string) | | identifies the port on the receiving chain. | -| `destination_channel` | [string](#string) | | identifies the channel end on the receiving chain. | -| `data` | [bytes](#bytes) | | actual opaque bytes transferred directly to the application module | -| `timeout_height` | [ibc.core.client.v1.Height](#ibc.core.client.v1.Height) | | block height after which the packet times out | -| `timeout_timestamp` | [uint64](#uint64) | | block timestamp (in nanoseconds) after which the packet times out | +| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | - + -### PacketState -PacketState defines the generic type necessary to retrieve and store -packet commitments, acknowledgements, and receipts. -Caller is responsible for knowing the context necessary to interpret this -state as a commitment, acknowledgement, or a receipt. +### QueryDenomTracesResponse +QueryConnectionsResponse is the response type for the Query/DenomTraces RPC +method. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `port_id` | [string](#string) | | channel port identifier. | -| `channel_id` | [string](#string) | | channel unique identifier. | -| `sequence` | [uint64](#uint64) | | packet sequence. | -| `data` | [bytes](#bytes) | | embedded data that represents packet state. | +| `denom_traces` | [DenomTrace](#ibc.applications.transfer.v1.DenomTrace) | repeated | denom_traces returns all denominations trace information. | +| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination in the response. | + + + + + + + + +### QueryParamsRequest +QueryParamsRequest is the request type for the Query/Params RPC method. + + + + + + + + +### QueryParamsResponse +QueryParamsResponse is the response type for the Query/Params RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `params` | [Params](#ibc.applications.transfer.v1.Params) | | params defines the parameters of the module. | @@ -1113,34 +1843,113 @@ state as a commitment, acknowledgement, or a receipt. + - + -### Order -Order defines if a channel is ORDERED or UNORDERED -| Name | Number | Description | -| ---- | ------ | ----------- | -| ORDER_NONE_UNSPECIFIED | 0 | zero-value for channel ordering | -| ORDER_UNORDERED | 1 | packets can be delivered in any order, which may differ from the order in which they were sent. | -| ORDER_ORDERED | 2 | packets are delivered exactly in the order which they were sent | + +### Query +Query provides defines the gRPC querier service. +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `DenomTrace` | [QueryDenomTraceRequest](#ibc.applications.transfer.v1.QueryDenomTraceRequest) | [QueryDenomTraceResponse](#ibc.applications.transfer.v1.QueryDenomTraceResponse) | DenomTrace queries a denomination trace information. | GET|/ibc/apps/transfer/v1/denom_traces/{hash}| +| `DenomTraces` | [QueryDenomTracesRequest](#ibc.applications.transfer.v1.QueryDenomTracesRequest) | [QueryDenomTracesResponse](#ibc.applications.transfer.v1.QueryDenomTracesResponse) | DenomTraces queries all denomination traces. | GET|/ibc/apps/transfer/v1/denom_traces| +| `Params` | [QueryParamsRequest](#ibc.applications.transfer.v1.QueryParamsRequest) | [QueryParamsResponse](#ibc.applications.transfer.v1.QueryParamsResponse) | Params queries all parameters of the ibc-transfer module. | GET|/ibc/apps/transfer/v1/params| +| `DenomHash` | [QueryDenomHashRequest](#ibc.applications.transfer.v1.QueryDenomHashRequest) | [QueryDenomHashResponse](#ibc.applications.transfer.v1.QueryDenomHashResponse) | DenomHash queries a denomination hash information. | GET|/ibc/apps/transfer/v1/denom_hashes/{trace}| - + -### State -State defines if a channel is in one of the following states: -CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. -| Name | Number | Description | -| ---- | ------ | ----------- | -| STATE_UNINITIALIZED_UNSPECIFIED | 0 | Default State | -| STATE_INIT | 1 | A channel has just started the opening handshake. | -| STATE_TRYOPEN | 2 | A channel has acknowledged the handshake step on the counterparty chain. | -| STATE_OPEN | 3 | A channel has completed the handshake. Open channels are ready to send and receive packets. | -| STATE_CLOSED | 4 | A channel has been closed and can no longer be used to send or receive packets. | + +

    Top

    + +## ibc/applications/transfer/v1/tx.proto + + + + + +### MsgTransfer +MsgTransfer defines a msg to transfer fungible tokens (i.e Coins) between +ICS20 enabled chains. See ICS Spec here: +https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `source_port` | [string](#string) | | the port on which the packet will be sent | +| `source_channel` | [string](#string) | | the channel by which the packet will be sent | +| `token` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | the tokens to be transferred | +| `sender` | [string](#string) | | the sender address | +| `receiver` | [string](#string) | | the recipient address on the destination chain | +| `timeout_height` | [ibc.core.client.v1.Height](#ibc.core.client.v1.Height) | | Timeout height relative to the current block height. The timeout is disabled when set to 0. | +| `timeout_timestamp` | [uint64](#uint64) | | Timeout timestamp in absolute nanoseconds since unix epoch. The timeout is disabled when set to 0. | + + + + + + + + +### MsgTransferResponse +MsgTransferResponse defines the Msg/Transfer response type. + + + + + + + + + + + + + + +### Msg +Msg defines the ibc/transfer Msg service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Transfer` | [MsgTransfer](#ibc.applications.transfer.v1.MsgTransfer) | [MsgTransferResponse](#ibc.applications.transfer.v1.MsgTransferResponse) | Transfer defines a rpc handler method for MsgTransfer. | | + + + + + + +

    Top

    + +## ibc/applications/transfer/v2/packet.proto + + + + + +### FungibleTokenPacketData +FungibleTokenPacketData defines a struct for the packet payload +See FungibleTokenPacketData spec: +https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `denom` | [string](#string) | | the token denomination to be transferred | +| `amount` | [string](#string) | | the token amount to be transferred | +| `sender` | [string](#string) | | the sender address | +| `receiver` | [string](#string) | | the recipient address on the destination chain | + + + + + + diff --git a/modules/apps/29-fee/client/cli/cli.go b/modules/apps/29-fee/client/cli/cli.go new file mode 100644 index 00000000000..292f1d7b3d8 --- /dev/null +++ b/modules/apps/29-fee/client/cli/cli.go @@ -0,0 +1,42 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/spf13/cobra" +) + +// GetQueryCmd returns the query commands for 29-fee +func GetQueryCmd() *cobra.Command { + queryCmd := &cobra.Command{ + Use: "ibc-fee", + Short: "", // TODO + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + } + + queryCmd.AddCommand( + GetCmdTotalRecvFees(), + GetCmdTotalAckFees(), + GetCmdTotalTimeoutFees(), + ) + + return queryCmd +} + +// NewTxCmd returns the transaction commands for 29-fee +func NewTxCmd() *cobra.Command { + txCmd := &cobra.Command{ + Use: "ibc-fee", + Short: "Transaction subcommand for IBC relayer incentivization", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + txCmd.AddCommand( + NewPayPacketFeeAsyncTxCmd(), + NewRegisterCounterpartyAddress(), + ) + + return txCmd +} diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go new file mode 100644 index 00000000000..95bb0959ba7 --- /dev/null +++ b/modules/apps/29-fee/client/cli/query.go @@ -0,0 +1,151 @@ +package cli + +import ( + "fmt" + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/spf13/cobra" +) + +// GetCmdTotalRecvFees returns the command handler for the Query/TotalRecvFees rpc. +func GetCmdTotalRecvFees() *cobra.Command { + cmd := &cobra.Command{ + Use: "total-recv-fees [port-id] [channel-id] [sequence]", + Short: "Query the total receive fees for a packet", + Long: "Query the total receive fees for a packet", + Args: cobra.ExactArgs(3), + Example: fmt.Sprintf("%s query ibc-fee total-recv-fees transfer channel-5 100", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + portID, channelID := args[0], args[1] + seq, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return err + } + + packetID := channeltypes.NewPacketId(channelID, portID, seq) + + if err := packetID.Validate(); err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryTotalRecvFeesRequest{ + PacketId: packetID, + } + + res, err := queryClient.TotalRecvFees(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdTotalAckFees returns the command handler for the Query/TotalAckFees rpc. +func GetCmdTotalAckFees() *cobra.Command { + cmd := &cobra.Command{ + Use: "total-ack-fees [port-id] [channel-id] [sequence]", + Short: "Query the total acknowledgement fees for a packet", + Long: "Query the total acknowledgement fees for a packet", + Args: cobra.ExactArgs(3), + Example: fmt.Sprintf("%s query ibc-fee total-ack-fees transfer channel-5 100", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + portID, channelID := args[0], args[1] + seq, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return err + } + + packetID := channeltypes.NewPacketId(channelID, portID, seq) + + if err := packetID.Validate(); err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryTotalAckFeesRequest{ + PacketId: packetID, + } + + res, err := queryClient.TotalAckFees(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdTotalTimeoutFees returns the command handler for the Query/TotalTimeoutFees rpc. +func GetCmdTotalTimeoutFees() *cobra.Command { + cmd := &cobra.Command{ + Use: "total-timeout-fees [port-id] [channel-id] [sequence]", + Short: "Query the total timeout fees for a packet", + Long: "Query the total timeout fees for a packet", + Args: cobra.ExactArgs(3), + Example: fmt.Sprintf("%s query ibc-fee total-timeout-fees transfer channel-5 100", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + portID, channelID := args[0], args[1] + seq, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return err + } + + packetID := channeltypes.NewPacketId(channelID, portID, seq) + + if err := packetID.Validate(); err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryTotalTimeoutFeesRequest{ + PacketId: packetID, + } + + res, err := queryClient.TotalTimeoutFees(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/modules/apps/29-fee/client/cli/tx.go b/modules/apps/29-fee/client/cli/tx.go new file mode 100644 index 00000000000..0a4436b0bc4 --- /dev/null +++ b/modules/apps/29-fee/client/cli/tx.go @@ -0,0 +1,124 @@ +package cli + +import ( + "fmt" + "strconv" + "strings" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + "github.com/spf13/cobra" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" +) + +const ( + flagRecvFee = "recv-fee" + flagAckFee = "ack-fee" + flagTimeoutFee = "timeout-fee" +) + +// NewPayPacketFeeAsyncTxCmd returns the command to create a MsgPayPacketFeeAsync +func NewPayPacketFeeAsyncTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "pay-packet-fee [src-port] [src-channel] [sequence]", + Short: "Pay a fee to incentivize an existing IBC packet", + Long: strings.TrimSpace(`Pay a fee to incentivize an existing IBC packet.`), + Example: fmt.Sprintf("%s tx ibc-fee pay-packet-fee transfer channel-0 1 --recv-fee 10stake --ack-fee 10stake --timeout-fee 10stake", version.AppName), + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + // NOTE: specifying non-nil relayers is currently unsupported + var relayers []string + + sender := clientCtx.GetFromAddress().String() + seq, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return err + } + + packetID := channeltypes.NewPacketId(args[1], args[0], seq) + + recvFeeStr, err := cmd.Flags().GetString(flagRecvFee) + if err != nil { + return err + } + + recvFee, err := sdk.ParseCoinsNormalized(recvFeeStr) + if err != nil { + return err + } + + ackFeeStr, err := cmd.Flags().GetString(flagAckFee) + if err != nil { + return err + } + + ackFee, err := sdk.ParseCoinsNormalized(ackFeeStr) + if err != nil { + return err + } + + timeoutFeeStr, err := cmd.Flags().GetString(flagTimeoutFee) + if err != nil { + return err + } + + timeoutFee, err := sdk.ParseCoinsNormalized(timeoutFeeStr) + if err != nil { + return err + } + + fee := types.Fee{ + RecvFee: recvFee, + AckFee: ackFee, + TimeoutFee: timeoutFee, + } + + packetFee := types.NewPacketFee(fee, sender, relayers) + msg := types.NewMsgPayPacketFeeAsync(packetID, packetFee) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(flagRecvFee, "", "Fee paid to a relayer for relaying a packet receive.") + cmd.Flags().String(flagAckFee, "", "Fee paid to a relayer for relaying a packet acknowledgement.") + cmd.Flags().String(flagTimeoutFee, "", "Fee paid to a relayer for relaying a packet timeout.") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// NewRegisterCounterpartyAddress returns the command to create a MsgRegisterCounterpartyAddress +func NewRegisterCounterpartyAddress() *cobra.Command { + cmd := &cobra.Command{ + Use: "register-counterparty [address] [counterparty-address] [channel-id]", + Short: "Register a counterparty relayer address on a given channel.", + Long: strings.TrimSpace(`Register a counterparty relayer address on a given channel.`), + Example: fmt.Sprintf("%s tx ibc-fee register-counterparty cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 channel-0", version.AppName), + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgRegisterCounterpartyAddress(args[0], args[1], args[2]) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/modules/apps/29-fee/fee_test.go b/modules/apps/29-fee/fee_test.go new file mode 100644 index 00000000000..9369fc16743 --- /dev/null +++ b/modules/apps/29-fee/fee_test.go @@ -0,0 +1,65 @@ +package fee_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" + ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" +) + +type FeeTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain + chainC *ibctesting.TestChain + + path *ibctesting.Path + pathAToC *ibctesting.Path +} + +func (suite *FeeTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) + suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3)) + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + mockFeeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.Version = mockFeeVersion + path.EndpointB.ChannelConfig.Version = mockFeeVersion + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + suite.path = path + + path = ibctesting.NewPath(suite.chainA, suite.chainC) + path.EndpointA.ChannelConfig.Version = mockFeeVersion + path.EndpointB.ChannelConfig.Version = mockFeeVersion + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + suite.pathAToC = path +} + +func TestIBCFeeTestSuite(t *testing.T) { + suite.Run(t, new(FeeTestSuite)) +} + +func (suite *FeeTestSuite) CreateMockPacket() channeltypes.Packet { + return channeltypes.NewPacket( + ibcmock.MockPacketData, + suite.chainA.SenderAccount.GetSequence(), + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) +} diff --git a/modules/apps/29-fee/ibc_module.go b/modules/apps/29-fee/ibc_module.go new file mode 100644 index 00000000000..89d27b9f86f --- /dev/null +++ b/modules/apps/29-fee/ibc_module.go @@ -0,0 +1,275 @@ +package fee + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/keeper" + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/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" + "github.com/cosmos/ibc-go/v3/modules/core/exported" +) + +// IBCModule implements the ICS26 callbacks for the fee middleware given the fee keeper and the underlying application. +type IBCModule struct { + keeper keeper.Keeper + app porttypes.IBCModule +} + +// NewIBCModule creates a new IBCModule given the keeper and underlying application +func NewIBCModule(k keeper.Keeper, app porttypes.IBCModule) IBCModule { + return IBCModule{ + keeper: k, + app: app, + } +} + +// OnChanOpenInit implements the IBCModule interface +func (im IBCModule) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) error { + var versionMetadata types.Metadata + if err := types.ModuleCdc.UnmarshalJSON([]byte(version), &versionMetadata); err != nil { + // Since it is valid for fee version to not be specified, the above middleware version may be for a middleware + // lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying + // application. + return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, + chanCap, counterparty, version) + } + + if versionMetadata.FeeVersion != types.Version { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) + } + + im.keeper.SetFeeEnabled(ctx, portID, channelID) + + // call underlying app's OnChanOpenInit callback with the appVersion + return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, + chanCap, counterparty, versionMetadata.AppVersion) +} + +// OnChanOpenTry implements the IBCModule interface +// If the channel is not fee enabled the underlying application version will be returned +// If the channel is fee enabled we merge the underlying application version with the ics29 version +func (im IBCModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + var versionMetadata types.Metadata + if err := types.ModuleCdc.UnmarshalJSON([]byte(counterpartyVersion), &versionMetadata); err != nil { + // Since it is valid for fee version to not be specified, the above middleware version may be for a middleware + // lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying + // application. + return im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, counterpartyVersion) + } + + if versionMetadata.FeeVersion != types.Version { + return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) + } + + im.keeper.SetFeeEnabled(ctx, portID, channelID) + + // call underlying app's OnChanOpenTry callback with the app versions + appVersion, err := im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, versionMetadata.AppVersion) + if err != nil { + return "", err + } + + versionMetadata.AppVersion = appVersion + + versionBytes, err := types.ModuleCdc.MarshalJSON(&versionMetadata) + if err != nil { + return "", err + } + + return string(versionBytes), nil +} + +// OnChanOpenAck implements the IBCModule interface +func (im IBCModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyChannelID string, + counterpartyVersion string, +) error { + // If handshake was initialized with fee enabled it must complete with fee enabled. + // If handshake was initialized with fee disabled it must complete with fee disabled. + if im.keeper.IsFeeEnabled(ctx, portID, channelID) { + var versionMetadata types.Metadata + if err := types.ModuleCdc.UnmarshalJSON([]byte(counterpartyVersion), &versionMetadata); err != nil { + return sdkerrors.Wrap(types.ErrInvalidVersion, "failed to unmarshal ICS29 counterparty version metadata") + } + + if versionMetadata.FeeVersion != types.Version { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected counterparty fee version: %s, got: %s", types.Version, versionMetadata.FeeVersion) + } + + // call underlying app's OnChanOpenAck callback with the counterparty app version. + return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, versionMetadata.AppVersion) + } + + // call underlying app's OnChanOpenAck callback with the counterparty app version. + return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) +} + +// OnChanOpenConfirm implements the IBCModule interface +func (im IBCModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // call underlying app's OnChanOpenConfirm callback. + return im.app.OnChanOpenConfirm(ctx, portID, channelID) +} + +// OnChanCloseInit implements the IBCModule interface +func (im IBCModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + if err := im.app.OnChanCloseInit(ctx, portID, channelID); err != nil { + return err + } + + // delete fee enabled on channel + // and refund any remaining fees escrowed on channel + im.keeper.DeleteFeeEnabled(ctx, portID, channelID) + err := im.keeper.RefundFeesOnChannel(ctx, portID, channelID) + // error should only be non-nil if there is a bug in the code + // that causes module account to have insufficient funds to refund + // all escrowed fees on the channel. + // Disable all channels to allow for coordinated fix to the issue + // and mitigate/reverse damage. + // NOTE: Underlying application's packets will still go through, but + // fee module will be disabled for all channels + if err != nil { + im.keeper.DisableAllChannels(ctx) + } + + return nil +} + +// OnChanCloseConfirm implements the IBCModule interface +func (im IBCModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // delete fee enabled on channel + // and refund any remaining fees escrowed on channel + im.keeper.DeleteFeeEnabled(ctx, portID, channelID) + err := im.keeper.RefundFeesOnChannel(ctx, portID, channelID) + // error should only be non-nil if there is a bug in the code + // that causes module account to have insufficient funds to refund + // all escrowed fees on the channel. + // Disable all channels to allow for coordinated fix to the issue + // and mitigate/reverse damage. + // NOTE: Underlying application's packets will still go through, but + // fee module will be disabled for all channels + if err != nil { + im.keeper.DisableAllChannels(ctx) + } + return im.app.OnChanCloseConfirm(ctx, portID, channelID) +} + +// OnRecvPacket implements the IBCModule interface. +// If fees are not enabled, this callback will default to the ibc-core packet callback +func (im IBCModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) exported.Acknowledgement { + if !im.keeper.IsFeeEnabled(ctx, packet.DestinationPort, packet.DestinationChannel) { + return im.app.OnRecvPacket(ctx, packet, relayer) + } + + ack := im.app.OnRecvPacket(ctx, packet, relayer) + + // incase of async aknowledgement (ack == nil) store the relayer address for use later during async WriteAcknowledgement + if ack == nil { + im.keeper.SetRelayerAddressForAsyncAck(ctx, channeltypes.NewPacketId(packet.GetDestChannel(), packet.GetDestPort(), packet.GetSequence()), relayer.String()) + return nil + } + + // if forwardRelayer is not found we refund recv_fee + forwardRelayer, _ := im.keeper.GetCounterpartyAddress(ctx, relayer.String(), packet.GetDestChannel()) + + return types.NewIncentivizedAcknowledgement(forwardRelayer, ack.Acknowledgement(), ack.Success()) +} + +// OnAcknowledgementPacket implements the IBCModule interface +// If fees are not enabled, this callback will default to the ibc-core packet callback +func (im IBCModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + if !im.keeper.IsFeeEnabled(ctx, packet.SourcePort, packet.SourceChannel) { + return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) + } + + ack := new(types.IncentivizedAcknowledgement) + if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, ack); err != nil { + return sdkerrors.Wrapf(err, "cannot unmarshal ICS-29 incentivized packet acknowledgement: %v", ack) + } + + packetID := channeltypes.NewPacketId(packet.SourceChannel, packet.SourcePort, packet.Sequence) + feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) + if !found { + // return underlying callback if no fee found for given packetID + return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer) + } + + im.keeper.DistributePacketFees(ctx, ack.ForwardRelayerAddress, relayer, feesInEscrow.PacketFees) + + // removes the fees from the store as fees are now paid + im.keeper.DeleteFeesInEscrow(ctx, packetID) + + // call underlying callback + return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer) +} + +// OnTimeoutPacket implements the IBCModule interface +// If fees are not enabled, this callback will default to the ibc-core packet callback +func (im IBCModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) error { + if !im.keeper.IsFeeEnabled(ctx, packet.SourcePort, packet.SourceChannel) { + return im.app.OnTimeoutPacket(ctx, packet, relayer) + } + + packetID := channeltypes.NewPacketId(packet.SourceChannel, packet.SourcePort, packet.Sequence) + feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) + if !found { + // return underlying callback if fee not found for given packetID + return im.app.OnTimeoutPacket(ctx, packet, relayer) + } + + im.keeper.DistributePacketFeesOnTimeout(ctx, relayer, feesInEscrow.PacketFees) + + // removes the fee from the store as fee is now paid + im.keeper.DeleteFeesInEscrow(ctx, packetID) + + // call underlying callback + return im.app.OnTimeoutPacket(ctx, packet, relayer) +} diff --git a/modules/apps/29-fee/ibc_module_test.go b/modules/apps/29-fee/ibc_module_test.go new file mode 100644 index 00000000000..8bdc92458f7 --- /dev/null +++ b/modules/apps/29-fee/ibc_module_test.go @@ -0,0 +1,815 @@ +package fee_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v3/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v3/testing" + ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" +) + +var ( + validCoins = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}} + validCoins2 = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}} + validCoins3 = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(300)}} +) + +// Tests OnChanOpenInit on ChainA +func (suite *FeeTestSuite) TestOnChanOpenInit() { + testCases := []struct { + name string + version string + expPass bool + }{ + { + "success - valid fee middleware and mock version", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), + true, + }, + { + "success - fee version not included, only perform mock logic", + ibcmock.Version, + true, + }, + { + "invalid fee middleware version", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: "invalid-ics29-1", AppVersion: ibcmock.Version})), + false, + }, + { + "invalid mock version", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: "invalid-mock-version"})), + false, + }, + { + "mock version not wrapped", + types.Version, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + // reset suite + suite.SetupTest() + suite.coordinator.SetupConnections(suite.path) + + // setup mock callback + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, + portID, channelID string, chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, version string, + ) error { + if version != ibcmock.Version { + return fmt.Errorf("incorrect mock version") + } + return nil + } + + suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID + + counterparty := channeltypes.NewCounterparty(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + channel := &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: channeltypes.UNORDERED, + Counterparty: counterparty, + ConnectionHops: []string{suite.path.EndpointA.ConnectionID}, + Version: tc.version, + } + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, chanCap, counterparty, channel.Version) + + if tc.expPass { + suite.Require().NoError(err, "unexpected error from version: %s", tc.version) + } else { + suite.Require().Error(err, "error not returned for version: %s", tc.version) + } + }) + } +} + +// Tests OnChanOpenTry on ChainA +func (suite *FeeTestSuite) TestOnChanOpenTry() { + testCases := []struct { + name string + cpVersion string + crossing bool + expPass bool + }{ + { + "success - valid fee middleware version", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), + false, + true, + }, + { + "success - valid mock version", + ibcmock.Version, + false, + true, + }, + { + "success - crossing hellos: valid fee middleware", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), + true, + true, + }, + { + "invalid fee middleware version", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: "invalid-ics29-1", AppVersion: ibcmock.Version})), + false, + false, + }, + { + "invalid mock version", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: "invalid-mock-version"})), + false, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + // reset suite + suite.SetupTest() + suite.coordinator.SetupConnections(suite.path) + suite.path.EndpointB.ChanOpenInit() + + // setup mock callback + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenTry = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, + portID, channelID string, chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, counterpartyVersion string, + ) (string, error) { + if counterpartyVersion != ibcmock.Version { + return "", fmt.Errorf("incorrect mock version") + } + return ibcmock.Version, nil + } + + var ( + chanCap *capabilitytypes.Capability + ok bool + err error + ) + if tc.crossing { + suite.path.EndpointA.ChanOpenInit() + chanCap, ok = suite.chainA.GetSimApp().ScopedFeeMockKeeper.GetCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + suite.Require().True(ok) + } else { + chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + suite.Require().NoError(err) + } + + suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID + + counterparty := channeltypes.NewCounterparty(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + channel := &channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: channeltypes.UNORDERED, + Counterparty: counterparty, + ConnectionHops: []string{suite.path.EndpointA.ConnectionID}, + Version: tc.cpVersion, + } + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + _, err = cbs.OnChanOpenTry(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, chanCap, counterparty, tc.cpVersion) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +// Tests OnChanOpenAck on ChainA +func (suite *FeeTestSuite) TestOnChanOpenAck() { + testCases := []struct { + name string + cpVersion string + malleate func(suite *FeeTestSuite) + expPass bool + }{ + { + "success", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), + func(suite *FeeTestSuite) {}, + true, + }, + { + "invalid fee version", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: "invalid-ics29-1", AppVersion: ibcmock.Version})), + func(suite *FeeTestSuite) {}, + false, + }, + { + "invalid mock version", + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: "invalid-mock-version"})), + func(suite *FeeTestSuite) {}, + false, + }, + { + "invalid version fails to unmarshal metadata", + "invalid-version", + func(suite *FeeTestSuite) {}, + false, + }, + { + "previous INIT set without fee, however counterparty set fee version", // note this can only happen with incompetent or malicious counterparty chain + string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), + func(suite *FeeTestSuite) { + // do the first steps without fee version, then pass the fee version as counterparty version in ChanOpenACK + suite.path.EndpointA.ChannelConfig.Version = ibcmock.Version + suite.path.EndpointB.ChannelConfig.Version = ibcmock.Version + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + suite.coordinator.SetupConnections(suite.path) + + // setup mock callback + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenAck = func( + ctx sdk.Context, portID, channelID string, counterpartyChannelID string, counterpartyVersion string, + ) error { + if counterpartyVersion != ibcmock.Version { + return fmt.Errorf("incorrect mock version") + } + return nil + } + + // malleate test case + tc.malleate(suite) + + suite.path.EndpointA.ChanOpenInit() + suite.path.EndpointB.ChanOpenTry() + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + err = cbs.OnChanOpenAck(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.path.EndpointA.Counterparty.ChannelID, tc.cpVersion) + if tc.expPass { + suite.Require().NoError(err, "unexpected error for case: %s", tc.name) + } else { + suite.Require().Error(err, "%s expected error but returned none", tc.name) + } + }) + } +} + +// Tests OnChanCloseInit on chainA +func (suite *FeeTestSuite) TestOnChanCloseInit() { + testCases := []struct { + name string + setup func(suite *FeeTestSuite) + disabled bool + }{ + { + "success", + func(suite *FeeTestSuite) { + packetID := channeltypes.NewPacketId( + suite.path.EndpointA.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, + 1, + ) + refundAcc := suite.chainA.SenderAccount.GetAddress() + packetFee := types.NewPacketFee(types.Fee{validCoins, validCoins2, validCoins3}, refundAcc.String(), []string{}) + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + }, + false, + }, + { + "module account balance insufficient", + func(suite *FeeTestSuite) { + packetID := channeltypes.PacketId{ + PortId: suite.path.EndpointA.ChannelConfig.PortID, + ChannelId: suite.path.EndpointA.ChannelID, + Sequence: 1, + } + refundAcc := suite.chainA.SenderAccount.GetAddress() + packetFee := types.NewPacketFee(types.Fee{validCoins, validCoins2, validCoins3}, refundAcc.String(), []string{}) + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, refundAcc, validCoins3) + + // set fee enabled on different channel + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "portID7", "channel-7") + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + suite.coordinator.Setup(suite.path) // setup channel + + origBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress()) + + tc.setup(suite) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + if tc.disabled { + suite.Require().True( + suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID), + "fee is not disabled on original channel: %s", suite.path.EndpointA.ChannelID, + ) + suite.Require().True( + suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "portID7", "channel-7"), + "fee is not disabled on other channel: %s", "channel-7", + ) + } else { + cbs.OnChanCloseInit(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + afterBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress()) + suite.Require().Equal(origBal, afterBal, "balances of refund account not equal after all fees refunded") + } + }) + } +} + +// Tests OnChanCloseConfirm on chainA +func (suite *FeeTestSuite) TestOnChanCloseConfirm() { + testCases := []struct { + name string + setup func(suite *FeeTestSuite) + disabled bool + }{ + { + "success", + func(suite *FeeTestSuite) { + packetID := channeltypes.PacketId{ + PortId: suite.path.EndpointA.ChannelConfig.PortID, + ChannelId: suite.path.EndpointA.ChannelID, + Sequence: 1, + } + refundAcc := suite.chainA.SenderAccount.GetAddress() + packetFee := types.NewPacketFee(types.Fee{validCoins, validCoins2, validCoins3}, refundAcc.String(), []string{}) + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + }, + false, + }, + { + "module account balance insufficient", + func(suite *FeeTestSuite) { + packetID := channeltypes.PacketId{ + PortId: suite.path.EndpointA.ChannelConfig.PortID, + ChannelId: suite.path.EndpointA.ChannelID, + Sequence: 1, + } + refundAcc := suite.chainA.SenderAccount.GetAddress() + packetFee := types.NewPacketFee(types.Fee{validCoins, validCoins2, validCoins3}, refundAcc.String(), []string{}) + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, refundAcc, validCoins3) + + // set fee enabled on different channel + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "portID7", "channel-7") + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + suite.coordinator.Setup(suite.path) // setup channel + + origBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress()) + + tc.setup(suite) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + if tc.disabled { + suite.Require().True( + suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID), + "fee is not disabled on original channel: %s", suite.path.EndpointA.ChannelID, + ) + suite.Require().True( + suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "portID7", "channel-7"), + "fee is not disabled on other channel: %s", "channel-7", + ) + } else { + cbs.OnChanCloseConfirm(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + afterBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress()) + suite.Require().Equal(origBal, afterBal, "balances of refund account not equal after all fees refunded") + } + }) + } +} + +func (suite *FeeTestSuite) TestOnRecvPacket() { + testCases := []struct { + name string + malleate func() + // forwardRelayer bool indicates if there is a forwardRelayer address set + forwardRelayer bool + feeEnabled bool + }{ + { + "success", + func() {}, + true, + true, + }, + { + "async write acknowledgement: ack is nil", + func() { + // setup mock callback + suite.chainB.GetSimApp().FeeMockModule.IBCApp.OnRecvPacket = func( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, + ) exported.Acknowledgement { + return nil + } + }, + true, + true, + }, + { + "fee not enabled", + func() { + suite.chainB.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainB.GetContext(), suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + }, + true, + false, + }, + { + "forward address is not found", + func() { + suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), "", suite.path.EndpointB.ChannelID) + }, + false, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + // setup pathAToC (chainA -> chainC) first in order to have different channel IDs for chainA & chainB + suite.coordinator.Setup(suite.pathAToC) + // setup path for chainA -> chainB + suite.coordinator.Setup(suite.path) + + suite.chainB.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainB.GetContext(), suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + + packet := suite.CreateMockPacket() + + // set up module and callbacks + module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) + + // malleate test case + tc.malleate() + + result := cbs.OnRecvPacket(suite.chainB.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()) + + switch { + case tc.name == "success": + forwardAddr, _ := suite.chainB.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) + + expectedAck := types.IncentivizedAcknowledgement{ + Result: ibcmock.MockAcknowledgement.Acknowledgement(), + ForwardRelayerAddress: forwardAddr, + UnderlyingAppSuccess: true, + } + suite.Require().Equal(expectedAck, result) + + case !tc.feeEnabled: + suite.Require().Equal(ibcmock.MockAcknowledgement, result) + + case tc.forwardRelayer && result == nil: + suite.Require().Equal(nil, result) + packetID := channeltypes.NewPacketId(packet.GetDestChannel(), packet.GetDestPort(), packet.GetSequence()) + + // retrieve the forward relayer that was stored in `onRecvPacket` + relayer, _ := suite.chainB.GetSimApp().IBCFeeKeeper.GetRelayerAddressForAsyncAck(suite.chainB.GetContext(), packetID) + suite.Require().Equal(relayer, suite.chainA.SenderAccount.GetAddress().String()) + + case !tc.forwardRelayer: + expectedAck := types.IncentivizedAcknowledgement{ + Result: ibcmock.MockAcknowledgement.Acknowledgement(), + ForwardRelayerAddress: "", + UnderlyingAppSuccess: true, + } + suite.Require().Equal(expectedAck, result) + } + }) + } +} + +// different channel than sending chain +func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { + var ( + ack []byte + packetFee types.PacketFee + originalBalance sdk.Coins + expectedBalance sdk.Coins + expectedRelayerBalance sdk.Coins + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() { + expectedRelayerBalance = packetFee.Fee.RecvFee.Add(packetFee.Fee.AckFee[0]) + }, + true, + }, + { + "no op success without a packet fee", + func() { + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, suite.chainA.SenderAccount.GetSequence()) + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeesInEscrow(suite.chainA.GetContext(), packetID) + + ack = types.IncentivizedAcknowledgement{ + Result: ibcmock.MockAcknowledgement.Acknowledgement(), + ForwardRelayerAddress: suite.chainA.SenderAccount.GetAddress().String(), + }.Acknowledgement() + + expectedBalance = originalBalance + }, + true, + }, + { + "ack wrong format", + func() { + ack = []byte("unsupported acknowledgement format") + + expectedBalance = originalBalance + }, + false, + }, + { + "channel is not fee not enabled, success", + func() { + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + ack = ibcmock.MockAcknowledgement.Acknowledgement() + + expectedBalance = originalBalance + }, + true, + }, + { + "fail on distribute receive fee (blocked address)", + func() { + blockedAddr := suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() + + ack = types.IncentivizedAcknowledgement{ + Result: ibcmock.MockAcknowledgement.Acknowledgement(), + ForwardRelayerAddress: blockedAddr.String(), + }.Acknowledgement() + + expectedRelayerBalance = packetFee.Fee.AckFee + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + suite.coordinator.Setup(suite.path) + packet := suite.CreateMockPacket() + + expectedRelayerBalance = sdk.Coins{} // reset + + // set up module and callbacks + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + // escrow the packet fee + packetID := channeltypes.NewPacketId(packet.GetSourceChannel(), packet.GetSourcePort(), packet.GetSequence()) + packetFee = types.NewPacketFee( + types.Fee{ + RecvFee: validCoins, + AckFee: validCoins2, + TimeoutFee: validCoins3, + }, + suite.chainA.SenderAccount.GetAddress().String(), + []string{}, + ) + err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + relayerAddr := suite.chainB.SenderAccount.GetAddress() + + // must be changed explicitly + ack = types.IncentivizedAcknowledgement{ + Result: ibcmock.MockAcknowledgement.Acknowledgement(), + ForwardRelayerAddress: relayerAddr.String(), + }.Acknowledgement() + + // log original sender balance + // NOTE: balance is logged after escrowing tokens + originalBalance = sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + + // default to success case + expectedBalance = originalBalance.Add(packetFee.Fee.TimeoutFee[0]) + + // malleate test case + tc.malleate() + + err = cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, ack, relayerAddr) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + suite.Require().Equal( + expectedBalance, + sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), + ) + + relayerBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, ibctesting.TestCoin.Denom)) + suite.Require().Equal( + expectedRelayerBalance, + relayerBalance, + ) + + }) + } +} + +func (suite *FeeTestSuite) TestOnTimeoutPacket() { + var ( + relayerAddr sdk.AccAddress + packetFee types.PacketFee + originalBalance sdk.Coins + expectedBalance sdk.Coins + ) + testCases := []struct { + name string + malleate func() + expFeeDistributed bool + }{ + { + "success", + func() {}, + true, + }, + { + "fee not enabled", + func() { + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + + expectedBalance = originalBalance + }, + false, + }, + { + "no op if identified packet fee doesn't exist", + func() { + // delete packet fee + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, suite.chainA.SenderAccount.GetSequence()) + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeesInEscrow(suite.chainA.GetContext(), packetID) + + expectedBalance = originalBalance + }, + false, + }, + { + "distribute fee fails for timeout fee (blocked address)", + func() { + relayerAddr = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() + + expectedBalance = originalBalance. + Add(packetFee.Fee.RecvFee[0]). + Add(packetFee.Fee.AckFee[0]) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + suite.coordinator.Setup(suite.path) + packet := suite.CreateMockPacket() + + // set up module and callbacks + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + packetID := channeltypes.NewPacketId(packet.GetSourceChannel(), packet.GetSourcePort(), packet.GetSequence()) + + // must be explicitly changed + relayerAddr = suite.chainB.SenderAccount.GetAddress() + + packetFee = types.NewPacketFee( + types.Fee{ + RecvFee: validCoins, + AckFee: validCoins2, + TimeoutFee: validCoins3, + }, + suite.chainA.SenderAccount.GetAddress().String(), + []string{}, + ) + + err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + // log original sender balance + // NOTE: balance is logged after escrowing tokens + originalBalance = sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + + // default to success case + expectedBalance = originalBalance. + Add(packetFee.Fee.RecvFee[0]). + Add(packetFee.Fee.AckFee[0]) + + // malleate test case + tc.malleate() + + err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, relayerAddr) + suite.Require().NoError(err) + + suite.Require().Equal( + expectedBalance, + sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), + ) + + relayerBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, ibctesting.TestCoin.Denom)) + if tc.expFeeDistributed { + // there should no longer be a fee in escrow for this packet + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + + suite.Require().Equal(packetFee.Fee.TimeoutFee, relayerBalance) + } else { + suite.Require().Empty(relayerBalance) + } + }) + } +} diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go new file mode 100644 index 00000000000..37c9dd7e624 --- /dev/null +++ b/modules/apps/29-fee/keeper/escrow.go @@ -0,0 +1,145 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" +) + +// EscrowPacketFee sends the packet fee to the 29-fee module account to hold in escrow +func (k Keeper) EscrowPacketFee(ctx sdk.Context, packetID channeltypes.PacketId, packetFee types.PacketFee) error { + if !k.IsFeeEnabled(ctx, packetID.PortId, packetID.ChannelId) { + // users may not escrow fees on this channel. Must send packets without a fee message + return sdkerrors.Wrap(types.ErrFeeNotEnabled, "cannot escrow fee for packet") + } + // check if the refund account exists + refundAcc, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) + if err != nil { + return err + } + + hasRefundAcc := k.authKeeper.GetAccount(ctx, refundAcc) + if hasRefundAcc == nil { + return sdkerrors.Wrapf(types.ErrRefundAccNotFound, "account with address: %s not found", refundAcc) + } + + coins := packetFee.Fee.Total() + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, refundAcc, types.ModuleName, coins); err != nil { + return err + } + + fees := []types.PacketFee{packetFee} + if feesInEscrow, found := k.GetFeesInEscrow(ctx, packetID); found { + fees = append(fees, feesInEscrow.PacketFees...) + } + + packetFees := types.NewPacketFees(fees) + k.SetFeesInEscrow(ctx, packetID, packetFees) + + EmitIncentivizedPacket(ctx, packetID, packetFee) + + return nil +} + +// DistributePacketFees pays the acknowledgement fee & receive fee for a given packetID while refunding the timeout fee to the refund account associated with the Fee. +func (k Keeper) DistributePacketFees(ctx sdk.Context, forwardRelayer string, reverseRelayer sdk.AccAddress, feesInEscrow []types.PacketFee) { + forwardAddr, _ := sdk.AccAddressFromBech32(forwardRelayer) + + for _, packetFee := range feesInEscrow { + refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) + if err != nil { + panic(fmt.Sprintf("could not parse refundAcc %s to sdk.AccAddress", packetFee.RefundAddress)) + } + + // distribute fee to valid forward relayer address otherwise refund the fee + if !forwardAddr.Empty() { + // distribute fee for forward relaying + k.distributeFee(ctx, forwardAddr, packetFee.Fee.RecvFee) + } else { + // refund onRecv fee as forward relayer is not valid address + k.distributeFee(ctx, refundAddr, packetFee.Fee.RecvFee) + } + + // distribute fee for reverse relaying + k.distributeFee(ctx, reverseRelayer, packetFee.Fee.AckFee) + + // refund timeout fee for unused timeout + k.distributeFee(ctx, refundAddr, packetFee.Fee.TimeoutFee) + } +} + +// DistributePacketsFeesTimeout pays the timeout fee for a given packetID while refunding the acknowledgement fee & receive fee to the refund account associated with the Fee +func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sdk.AccAddress, feesInEscrow []types.PacketFee) { + for _, feeInEscrow := range feesInEscrow { + // check if refundAcc address works + refundAddr, err := sdk.AccAddressFromBech32(feeInEscrow.RefundAddress) + if err != nil { + panic(fmt.Sprintf("could not parse refundAcc %s to sdk.AccAddress", feeInEscrow.RefundAddress)) + } + + // refund receive fee for unused forward relaying + k.distributeFee(ctx, refundAddr, feeInEscrow.Fee.RecvFee) + + // refund ack fee for unused reverse relaying + k.distributeFee(ctx, refundAddr, feeInEscrow.Fee.AckFee) + + // distribute fee for timeout relaying + k.distributeFee(ctx, timeoutRelayer, feeInEscrow.Fee.TimeoutFee) + } +} + +// distributeFee will attempt to distribute the escrowed fee to the receiver address. +// If the distribution fails for any reason (such as the receiving address being blocked), +// the state changes will be discarded. +func (k Keeper) distributeFee(ctx sdk.Context, receiver sdk.AccAddress, fee sdk.Coins) { + // cache context before trying to distribute fees + cacheCtx, writeFn := ctx.CacheContext() + + err := k.bankKeeper.SendCoinsFromModuleToAccount(cacheCtx, types.ModuleName, receiver, fee) + if err == nil { + // write the cache + writeFn() + + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + } +} + +func (k Keeper) RefundFeesOnChannel(ctx sdk.Context, portID, channelID string) error { + + var refundErr error + + k.IteratePacketFeesInEscrow(ctx, portID, channelID, func(packetFees types.PacketFees) (stop bool) { + for _, identifiedFee := range packetFees.PacketFees { + refundAccAddr, err := sdk.AccAddressFromBech32(identifiedFee.RefundAddress) + if err != nil { + refundErr = err + return true + } + + // refund all fees to refund address + // Use SendCoins rather than the module account send functions since refund address may be a user account or module address. + // if any `SendCoins` call returns an error, we return error and stop iteration + if err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, refundAccAddr, identifiedFee.Fee.RecvFee); err != nil { + refundErr = err + return true + } + if err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, refundAccAddr, identifiedFee.Fee.AckFee); err != nil { + refundErr = err + return true + } + if err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, refundAccAddr, identifiedFee.Fee.TimeoutFee); err != nil { + refundErr = err + return true + } + } + + return false + }) + + return refundErr +} diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go new file mode 100644 index 00000000000..647b968f56d --- /dev/null +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -0,0 +1,313 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tendermint/tendermint/crypto/secp256k1" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +func (suite *KeeperTestSuite) TestEscrowPacketFee() { + var ( + err error + refundAcc sdk.AccAddress + ackFee sdk.Coins + receiveFee sdk.Coins + timeoutFee sdk.Coins + packetID channeltypes.PacketId + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "success with existing packet fee", func() { + fee := types.Fee{ + RecvFee: receiveFee, + AckFee: ackFee, + TimeoutFee: timeoutFee, + } + + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + feesInEscrow := types.NewPacketFees([]types.PacketFee{packetFee}) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, feesInEscrow) + }, true, + }, + { + "fee not enabled on this channel", func() { + packetID.ChannelId = "disabled_channel" + }, false, + }, + { + "refundAcc does not exist", func() { + // this acc does not exist on chainA + refundAcc = suite.chainB.SenderAccount.GetAddress() + }, false, + }, + { + "ackFee balance not found", func() { + ackFee = invalidCoins + }, false, + }, + { + "receive balance not found", func() { + receiveFee = invalidCoins + }, false, + }, + { + "timeout balance not found", func() { + timeoutFee = invalidCoins + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + suite.coordinator.Setup(suite.path) // setup channel + + // setup + refundAcc = suite.chainA.SenderAccount.GetAddress() + receiveFee = defaultReceiveFee + ackFee = defaultAckFee + timeoutFee = defaultTimeoutFee + packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, uint64(1)) + + tc.malleate() + fee := types.Fee{ + RecvFee: receiveFee, + AckFee: ackFee, + TimeoutFee: timeoutFee, + } + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + + // refundAcc balance before escrow + originalBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + + // escrow the packet fee + err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + + if tc.expPass { + feesInEscrow, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().True(found) + // check if the escrowed fee is set in state + suite.Require().True(feesInEscrow.PacketFees[0].Fee.AckFee.IsEqual(fee.AckFee)) + suite.Require().True(feesInEscrow.PacketFees[0].Fee.RecvFee.IsEqual(fee.RecvFee)) + suite.Require().True(feesInEscrow.PacketFees[0].Fee.TimeoutFee.IsEqual(fee.TimeoutFee)) + // check if the fee is escrowed correctly + hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(600)}) + suite.Require().True(hasBalance) + expectedBal := originalBal.Amount.Sub(sdk.NewInt(600)) + // check if the refund acc has sent the fee + hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: expectedBal}) + suite.Require().True(hasBalance) + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestDistributeFee() { + var ( + reverseRelayer sdk.AccAddress + forwardRelayer string + refundAcc sdk.AccAddress + ) + + validSeq := uint64(1) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() {}, true, + }, + { + "invalid forward address", func() { + forwardRelayer = "invalid address" + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + suite.coordinator.Setup(suite.path) // setup channel + + // setup + refundAcc = suite.chainA.SenderAccount.GetAddress() + reverseRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + forwardRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, validSeq) + fee := types.Fee{ + RecvFee: defaultReceiveFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } + + // escrow the packet fee & store the fee in state + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + // escrow a second packet fee to test with multiple fees distributed + err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + tc.malleate() + + // refundAcc balance after escrow + refundAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + + suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFees(suite.chainA.GetContext(), forwardRelayer, reverseRelayer, []types.PacketFee{packetFee, packetFee}) + + if tc.expPass { + // check if the reverse relayer is paid + hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), reverseRelayer, fee.AckFee[0].Add(fee.AckFee[0])) + suite.Require().True(hasBalance) + + // check if the forward relayer is paid + forward, err := sdk.AccAddressFromBech32(forwardRelayer) + suite.Require().NoError(err) + hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), forward, fee.RecvFee[0].Add(fee.RecvFee[0])) + suite.Require().True(hasBalance) + + // check if the refund acc has been refunded the timeoutFee + expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0].Add(fee.TimeoutFee[0])) + hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) + suite.Require().True(hasBalance) + + // check the module acc wallet is now empty + hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(0)}) + suite.Require().True(hasBalance) + } else { + // check if the refund acc has been refunded the timeoutFee & onRecvFee + expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]).Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]) + hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) + suite.Require().True(hasBalance) + } + }) + } +} + +func (suite *KeeperTestSuite) TestDistributeTimeoutFee() { + suite.coordinator.Setup(suite.path) // setup channel + + // setup + refundAcc := suite.chainA.SenderAccount.GetAddress() + timeoutRelayer := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + + packetID := channeltypes.NewPacketId( + suite.path.EndpointA.ChannelID, + suite.path.EndpointA.ChannelConfig.PortID, + 1, + ) + + fee := types.Fee{ + RecvFee: defaultReceiveFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } + + // escrow the packet fee & store the fee in state + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + // escrow a second packet fee to test with multiple fees distributed + err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + // refundAcc balance after escrow + refundAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + + suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnTimeout(suite.chainA.GetContext(), timeoutRelayer, []types.PacketFee{packetFee, packetFee}) + + // check if the timeoutRelayer has been paid + hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), timeoutRelayer, fee.TimeoutFee[0]) + suite.Require().True(hasBalance) + + // check if the refund acc has been refunded the recv & ack fees + expectedRefundAccBal := refundAccBal.Add(fee.AckFee[0]).Add(fee.AckFee[0]) + expectedRefundAccBal = refundAccBal.Add(fee.RecvFee[0]).Add(fee.RecvFee[0]) + hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) + suite.Require().True(hasBalance) + + // check the module acc wallet is now empty + hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(0)}) + suite.Require().True(hasBalance) +} + +func (suite *KeeperTestSuite) TestRefundFeesOnChannel() { + suite.coordinator.Setup(suite.path) + + // setup + refundAcc := suite.chainA.SenderAccount.GetAddress() + + // refundAcc balance before escrow + prevBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) + + for i := 0; i < 5; i++ { + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, uint64(i)) + fee := types.Fee{ + RecvFee: defaultReceiveFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } + + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + } + + // send a packet over a different channel to ensure this fee is not refunded + packetID := channeltypes.NewPacketId("channel-1", ibctesting.MockFeePort, 1) + fee := types.Fee{ + RecvFee: defaultReceiveFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } + + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, "channel-1") + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + // check that refunding all fees on channel-0 refunds all fees except for fee on channel-1 + err = suite.chainA.GetSimApp().IBCFeeKeeper.RefundFeesOnChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + suite.Require().NoError(err, "refund fees returned unexpected error") + + // add fee sent to channel-1 to after balance to recover original balance + afterBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) + suite.Require().Equal(prevBal, afterBal.Add(fee.RecvFee...).Add(fee.AckFee...).Add(fee.TimeoutFee...), "refund account not back to original balance after refunding all tokens") + + // create escrow and then change module account balance to cause error on refund + packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, uint64(6)) + + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, refundAcc, fee.TimeoutFee) + + err = suite.chainA.GetSimApp().IBCFeeKeeper.RefundFeesOnChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + suite.Require().Error(err, "refund fees returned no error with insufficient balance on module account") +} diff --git a/modules/apps/29-fee/keeper/events.go b/modules/apps/29-fee/keeper/events.go new file mode 100644 index 00000000000..9ff6f320ffc --- /dev/null +++ b/modules/apps/29-fee/keeper/events.go @@ -0,0 +1,25 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" +) + +// EmitIncentivizedPacket emits an event so that relayers know an incentivized packet is ready to be relayed +func EmitIncentivizedPacket(ctx sdk.Context, packetID channeltypes.PacketId, packetFee types.PacketFee) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeIncentivizedPacket, + sdk.NewAttribute(channeltypes.AttributeKeyPortID, packetID.PortId), + sdk.NewAttribute(channeltypes.AttributeKeyChannelID, packetID.ChannelId), + sdk.NewAttribute(channeltypes.AttributeKeySequence, fmt.Sprint(packetID.Sequence)), + sdk.NewAttribute(types.AttributeKeyRecvFee, packetFee.Fee.RecvFee.String()), + sdk.NewAttribute(types.AttributeKeyAckFee, packetFee.Fee.AckFee.String()), + sdk.NewAttribute(types.AttributeKeyTimeoutFee, packetFee.Fee.TimeoutFee.String()), + ), + ) +} diff --git a/modules/apps/29-fee/keeper/genesis.go b/modules/apps/29-fee/keeper/genesis.go new file mode 100644 index 00000000000..70b6a5012a2 --- /dev/null +++ b/modules/apps/29-fee/keeper/genesis.go @@ -0,0 +1,36 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" +) + +// InitGenesis initializes the fee middleware application state from a provided genesis state +func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { + for _, identifiedFees := range state.IdentifiedFees { + k.SetFeesInEscrow(ctx, identifiedFees.PacketId, types.NewPacketFees(identifiedFees.PacketFees)) + } + + for _, relayer := range state.RegisteredRelayers { + k.SetCounterpartyAddress(ctx, relayer.Address, relayer.CounterpartyAddress, relayer.ChannelId) + } + + for _, forwardAddr := range state.ForwardRelayers { + k.SetRelayerAddressForAsyncAck(ctx, forwardAddr.PacketId, forwardAddr.Address) + } + + for _, enabledChan := range state.FeeEnabledChannels { + k.SetFeeEnabled(ctx, enabledChan.PortId, enabledChan.ChannelId) + } +} + +// ExportGenesis returns the fee middleware application exported genesis +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + return &types.GenesisState{ + IdentifiedFees: k.GetAllIdentifiedPacketFees(ctx), + FeeEnabledChannels: k.GetAllFeeEnabledChannels(ctx), + RegisteredRelayers: k.GetAllRelayerAddresses(ctx), + ForwardRelayers: k.GetAllForwardRelayerAddresses(ctx), + } +} diff --git a/modules/apps/29-fee/keeper/genesis_test.go b/modules/apps/29-fee/keeper/genesis_test.go new file mode 100644 index 00000000000..f2824120a82 --- /dev/null +++ b/modules/apps/29-fee/keeper/genesis_test.go @@ -0,0 +1,113 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +func (suite *KeeperTestSuite) TestInitGenesis() { + // build PacketId & Fee + refundAcc := suite.chainA.SenderAccount.GetAddress() + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + fee := types.Fee{ + RecvFee: defaultReceiveFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } + + // relayer addresses + sender := suite.chainA.SenderAccount.GetAddress().String() + counterparty := suite.chainB.SenderAccount.GetAddress().String() + + genesisState := types.GenesisState{ + IdentifiedFees: []types.IdentifiedPacketFees{ + { + PacketId: packetID, + PacketFees: []types.PacketFee{ + { + Fee: fee, + RefundAddress: refundAcc.String(), + Relayers: nil, + }, + }, + }, + }, + FeeEnabledChannels: []types.FeeEnabledChannel{ + { + PortId: ibctesting.MockFeePort, + ChannelId: ibctesting.FirstChannelID, + }, + }, + RegisteredRelayers: []types.RegisteredRelayerAddress{ + { + Address: sender, + CounterpartyAddress: counterparty, + ChannelId: ibctesting.FirstChannelID, + }, + }, + } + + suite.chainA.GetSimApp().IBCFeeKeeper.InitGenesis(suite.chainA.GetContext(), genesisState) + + // check fee + feesInEscrow, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().True(found) + suite.Require().Equal(genesisState.IdentifiedFees[0].PacketFees, feesInEscrow.PacketFees) + + // check fee is enabled + isEnabled := suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) + suite.Require().True(isEnabled) + + // check relayers + addr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(suite.chainA.GetContext(), sender, ibctesting.FirstChannelID) + suite.Require().True(found) + suite.Require().Equal(genesisState.RegisteredRelayers[0].CounterpartyAddress, addr) +} + +func (suite *KeeperTestSuite) TestExportGenesis() { + // set fee enabled + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) + + // setup & escrow the packet fee + refundAcc := suite.chainA.SenderAccount.GetAddress() + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + fee := types.Fee{ + RecvFee: defaultReceiveFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } + + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) + + // relayer addresses + sender := suite.chainA.SenderAccount.GetAddress().String() + counterparty := suite.chainB.SenderAccount.GetAddress().String() + // set counterparty address + suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID) + + // set forward relayer address + suite.chainA.GetSimApp().IBCFeeKeeper.SetRelayerAddressForAsyncAck(suite.chainA.GetContext(), packetID, sender) + + // export genesis + genesisState := suite.chainA.GetSimApp().IBCFeeKeeper.ExportGenesis(suite.chainA.GetContext()) + + // check fee enabled + suite.Require().Equal(ibctesting.FirstChannelID, genesisState.FeeEnabledChannels[0].ChannelId) + suite.Require().Equal(ibctesting.MockFeePort, genesisState.FeeEnabledChannels[0].PortId) + + // check fee + suite.Require().Equal(packetID, genesisState.IdentifiedFees[0].PacketId) + suite.Require().Equal(fee, genesisState.IdentifiedFees[0].PacketFees[0].Fee) + suite.Require().Equal(refundAcc.String(), genesisState.IdentifiedFees[0].PacketFees[0].RefundAddress) + suite.Require().Equal([]string(nil), genesisState.IdentifiedFees[0].PacketFees[0].Relayers) + + // check registered relayer addresses + suite.Require().Equal(sender, genesisState.RegisteredRelayers[0].Address) + suite.Require().Equal(counterparty, genesisState.RegisteredRelayers[0].CounterpartyAddress) + + // check registered relayer addresses + suite.Require().Equal(sender, genesisState.ForwardRelayers[0].Address) + suite.Require().Equal(packetID, genesisState.ForwardRelayers[0].PacketId) +} diff --git a/modules/apps/29-fee/keeper/grpc_query.go b/modules/apps/29-fee/keeper/grpc_query.go new file mode 100644 index 00000000000..68f2cb332ca --- /dev/null +++ b/modules/apps/29-fee/keeper/grpc_query.go @@ -0,0 +1,175 @@ +package keeper + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/query" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" +) + +var _ types.QueryServer = Keeper{} + +// IncentivizedPackets implements the IncentivizedPackets gRPC method +func (k Keeper) IncentivizedPackets(c context.Context, req *types.QueryIncentivizedPacketsRequest) (*types.QueryIncentivizedPacketsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c).WithBlockHeight(int64(req.QueryHeight)) + + var identifiedPackets []types.IdentifiedPacketFees + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.FeesInEscrowPrefix)) + _, err := query.Paginate(store, req.Pagination, func(key, value []byte) error { + packetID, err := types.ParseKeyFeesInEscrow(types.FeesInEscrowPrefix + string(key)) + if err != nil { + return err + } + + packetFees := k.MustUnmarshalFees(value) + identifiedPackets = append(identifiedPackets, types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees)) + return nil + }) + + if err != nil { + return nil, status.Error(codes.NotFound, err.Error()) + } + + return &types.QueryIncentivizedPacketsResponse{ + IncentivizedPackets: identifiedPackets, + }, nil +} + +// IncentivizedPacket implements the IncentivizedPacket gRPC method +func (k Keeper) IncentivizedPacket(c context.Context, req *types.QueryIncentivizedPacketRequest) (*types.QueryIncentivizedPacketResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c).WithBlockHeight(int64(req.QueryHeight)) + + feesInEscrow, exists := k.GetFeesInEscrow(ctx, req.PacketId) + if !exists { + return nil, status.Error( + codes.NotFound, + sdkerrors.Wrapf(types.ErrFeeNotFound, "channel: %s, port: %s, sequence: %d", req.PacketId.ChannelId, req.PacketId.PortId, req.PacketId.Sequence).Error()) + } + + return &types.QueryIncentivizedPacketResponse{ + IncentivizedPacket: types.NewIdentifiedPacketFees(req.PacketId, feesInEscrow.PacketFees), + }, nil +} + +// IncentivizedPacketsForChannel implements the IncentivizedPacketsForChannel gRPC method +func (k Keeper) IncentivizedPacketsForChannel(goCtx context.Context, req *types.QueryIncentivizedPacketsForChannelRequest) (*types.QueryIncentivizedPacketsForChannelResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(goCtx).WithBlockHeight(int64(req.QueryHeight)) + + var packets []*types.IdentifiedPacketFees + keyPrefix := types.KeyFeesInEscrowChannelPrefix(req.PortId, req.ChannelId) + store := prefix.NewStore(ctx.KVStore(k.storeKey), keyPrefix) + _, err := query.Paginate(store, req.Pagination, func(key, value []byte) error { + packetID, err := types.ParseKeyFeesInEscrow(string(keyPrefix) + string(key)) + if err != nil { + return err + } + + packetFees := k.MustUnmarshalFees(value) + + identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) + packets = append(packets, &identifiedPacketFees) + + return nil + }) + + if err != nil { + return nil, status.Error(codes.NotFound, err.Error()) + } + + return &types.QueryIncentivizedPacketsForChannelResponse{ + IncentivizedPackets: packets, + }, nil +} + +// TotalRecvFees implements the Query/TotalRecvFees gRPC method +func (k Keeper) TotalRecvFees(goCtx context.Context, req *types.QueryTotalRecvFeesRequest) (*types.QueryTotalRecvFeesResponse, error) { + + ctx := sdk.UnwrapSDKContext(goCtx) + + feesInEscrow, found := k.GetFeesInEscrow(ctx, req.PacketId) + if !found { + return nil, status.Errorf( + codes.NotFound, + sdkerrors.Wrapf(types.ErrFeeNotFound, "channel: %s, port: %s, sequence: %d", req.PacketId.ChannelId, req.PacketId.PortId, req.PacketId.Sequence).Error(), + ) + } + + var recvFees sdk.Coins + for _, packetFee := range feesInEscrow.PacketFees { + recvFees = recvFees.Add(packetFee.Fee.RecvFee...) + } + + return &types.QueryTotalRecvFeesResponse{ + RecvFees: recvFees, + }, nil +} + +// TotalAckFees implements the Query/TotalAckFees gRPC method +func (k Keeper) TotalAckFees(goCtx context.Context, req *types.QueryTotalAckFeesRequest) (*types.QueryTotalAckFeesResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + feesInEscrow, found := k.GetFeesInEscrow(ctx, req.PacketId) + if !found { + return nil, status.Errorf( + codes.NotFound, + sdkerrors.Wrapf(types.ErrFeeNotFound, "channel: %s, port: %s, sequence: %d", req.PacketId.ChannelId, req.PacketId.PortId, req.PacketId.Sequence).Error(), + ) + } + + var ackFees sdk.Coins + for _, packetFee := range feesInEscrow.PacketFees { + ackFees = ackFees.Add(packetFee.Fee.AckFee...) + } + + return &types.QueryTotalAckFeesResponse{ + AckFees: ackFees, + }, nil +} + +// TotalTimeoutFees implements the Query/TotalTimeoutFees gRPC method +func (k Keeper) TotalTimeoutFees(goCtx context.Context, req *types.QueryTotalTimeoutFeesRequest) (*types.QueryTotalTimeoutFeesResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + feesInEscrow, found := k.GetFeesInEscrow(ctx, req.PacketId) + if !found { + return nil, status.Errorf( + codes.NotFound, + sdkerrors.Wrapf(types.ErrFeeNotFound, "channel: %s, port: %s, sequence: %d", req.PacketId.ChannelId, req.PacketId.PortId, req.PacketId.Sequence).Error(), + ) + } + + var timeoutFees sdk.Coins + for _, packetFee := range feesInEscrow.PacketFees { + timeoutFees = timeoutFees.Add(packetFee.Fee.TimeoutFee...) + } + + return &types.QueryTotalTimeoutFeesResponse{ + TimeoutFees: timeoutFees, + }, nil +} diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go new file mode 100644 index 00000000000..4bd55b92903 --- /dev/null +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -0,0 +1,428 @@ +package keeper_test + +import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +func (suite *KeeperTestSuite) TestQueryIncentivizedPackets() { + var ( + req *types.QueryIncentivizedPacketsRequest + expectedPackets []types.IdentifiedPacketFees + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() { + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) + + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) + + for i := 0; i < 3; i++ { + // escrow packet fees for three different packets + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, uint64(i+1)) + suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + + expectedPackets = append(expectedPackets, types.NewIdentifiedPacketFees(packetID, []types.PacketFee{packetFee})) + } + + req = &types.QueryIncentivizedPacketsRequest{ + Pagination: &query.PageRequest{ + Limit: 5, + CountTotal: false, + }, + QueryHeight: 0, + } + }, + true, + }, + { + "empty pagination", + func() { + expectedPackets = nil + req = &types.QueryIncentivizedPacketsRequest{} + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + tc.malleate() // malleate mutates test data + + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.queryClient.IncentivizedPackets(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(expectedPackets, res.IncentivizedPackets) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryIncentivizedPacket() { + var ( + req *types.QueryIncentivizedPacketRequest + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "fees not found for packet id", + func() { + req = &types.QueryIncentivizedPacketRequest{ + PacketId: channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 100), + QueryHeight: 0, + } + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) + + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) + + for i := 0; i < 3; i++ { + // escrow three packet fees for the same packet + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + } + + req = &types.QueryIncentivizedPacketRequest{ + PacketId: packetID, + QueryHeight: 0, + } + + tc.malleate() // malleate mutates test data + + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.queryClient.IncentivizedPacket(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(types.NewIdentifiedPacketFees(packetID, []types.PacketFee{packetFee, packetFee, packetFee}), res.IncentivizedPacket) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryIncentivizedPacketsForChannel() { + var ( + req *types.QueryIncentivizedPacketsForChannelRequest + expIdentifiedPacketFees []*types.IdentifiedPacketFees + ) + + fee := types.Fee{ + AckFee: sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}}, + RecvFee: sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}}, + TimeoutFee: sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}}, + } + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty pagination", + func() { + expIdentifiedPacketFees = nil + req = &types.QueryIncentivizedPacketsForChannelRequest{} + }, + true, + }, + { + "success", + func() { + req = &types.QueryIncentivizedPacketsForChannelRequest{ + Pagination: &query.PageRequest{ + Limit: 5, + CountTotal: false, + }, + PortId: ibctesting.MockFeePort, + ChannelId: ibctesting.FirstChannelID, + QueryHeight: 0, + } + }, + true, + }, + { + "no packets for specified channel", + func() { + expIdentifiedPacketFees = nil + req = &types.QueryIncentivizedPacketsForChannelRequest{ + Pagination: &query.PageRequest{ + Limit: 5, + CountTotal: false, + }, + PortId: ibctesting.MockFeePort, + ChannelId: "channel-10", + QueryHeight: 0, + } + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + // setup + refundAcc := suite.chainA.SenderAccount.GetAddress() + packetFee := types.NewPacketFee(fee, refundAcc.String(), nil) + packetFees := types.NewPacketFees([]types.PacketFee{packetFee, packetFee, packetFee}) + + identifiedFees1 := types.NewIdentifiedPacketFees(channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1), packetFees.PacketFees) + identifiedFees2 := types.NewIdentifiedPacketFees(channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 2), packetFees.PacketFees) + identifiedFees3 := types.NewIdentifiedPacketFees(channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 3), packetFees.PacketFees) + + expIdentifiedPacketFees = append(expIdentifiedPacketFees, &identifiedFees1, &identifiedFees2, &identifiedFees3) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) + for _, identifiedPacketFees := range expIdentifiedPacketFees { + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), identifiedPacketFees.PacketId, types.NewPacketFees(identifiedPacketFees.PacketFees)) + } + + tc.malleate() + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + + res, err := suite.queryClient.IncentivizedPacketsForChannel(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(expIdentifiedPacketFees, res.IncentivizedPackets) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryTotalRecvFees() { + var ( + req *types.QueryTotalRecvFeesRequest + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "packet not found", + func() { + req.PacketId = channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 100) + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) + + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) + + for i := 0; i < 3; i++ { + // escrow three packet fees for the same packet + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + } + + req = &types.QueryTotalRecvFeesRequest{ + PacketId: packetID, + } + + tc.malleate() + + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.queryClient.TotalRecvFees(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + // expected total is three times the default recv fee + expectedFees := defaultReceiveFee.Add(defaultReceiveFee...).Add(defaultReceiveFee...) + suite.Require().Equal(expectedFees, res.RecvFees) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryTotalAckFees() { + var ( + req *types.QueryTotalAckFeesRequest + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "packet not found", + func() { + req.PacketId = channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 100) + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) + + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) + + for i := 0; i < 3; i++ { + // escrow three packet fees for the same packet + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + } + + req = &types.QueryTotalAckFeesRequest{ + PacketId: packetID, + } + + tc.malleate() + + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.queryClient.TotalAckFees(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + // expected total is three times the default acknowledgement fee + expectedFees := defaultAckFee.Add(defaultAckFee...).Add(defaultAckFee...) + suite.Require().Equal(expectedFees, res.AckFees) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryTotalTimeoutFees() { + var ( + req *types.QueryTotalTimeoutFeesRequest + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "packet not found", + func() { + req.PacketId = channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 100) + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) + + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) + + for i := 0; i < 3; i++ { + // escrow three packet fees for the same packet + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + } + + req = &types.QueryTotalTimeoutFeesRequest{ + PacketId: packetID, + } + + tc.malleate() + + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.queryClient.TotalTimeoutFees(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + // expected total is three times the default acknowledgement fee + expectedFees := defaultTimeoutFee.Add(defaultTimeoutFee...).Add(defaultTimeoutFee...) + suite.Require().Equal(expectedFees, res.TimeoutFees) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go new file mode 100644 index 00000000000..c0c43dbecc6 --- /dev/null +++ b/modules/apps/29-fee/keeper/keeper.go @@ -0,0 +1,327 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" +) + +// Middleware must implement types.ChannelKeeper and types.PortKeeper expected interfaces +// so that it can wrap IBC channel and port logic for underlying application. +var ( + _ types.ChannelKeeper = Keeper{} + _ types.PortKeeper = Keeper{} +) + +// Keeper defines the IBC fungible transfer keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc codec.BinaryCodec + + authKeeper types.AccountKeeper + ics4Wrapper types.ICS4Wrapper + channelKeeper types.ChannelKeeper + portKeeper types.PortKeeper + bankKeeper types.BankKeeper +} + +// NewKeeper creates a new 29-fee Keeper instance +func NewKeeper( + cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, + ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, +) Keeper { + + return Keeper{ + cdc: cdc, + storeKey: key, + ics4Wrapper: ics4Wrapper, + channelKeeper: channelKeeper, + portKeeper: portKeeper, + authKeeper: authKeeper, + bankKeeper: bankKeeper, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", "x/"+host.ModuleName+"-"+types.ModuleName) +} + +// BindPort defines a wrapper function for the port Keeper's function in +// order to expose it to module's InitGenesis function +func (k Keeper) BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability { + return k.portKeeper.BindPort(ctx, portID) +} + +// GetChannel wraps IBC ChannelKeeper's GetChannel function +func (k Keeper) GetChannel(ctx sdk.Context, portID, channelID string) (channeltypes.Channel, bool) { + return k.channelKeeper.GetChannel(ctx, portID, channelID) +} + +// GetNextSequenceSend wraps IBC ChannelKeeper's GetNextSequenceSend function +func (k Keeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) { + return k.channelKeeper.GetNextSequenceSend(ctx, portID, channelID) +} + +// GetFeeAccount returns the ICS29 Fee ModuleAccount address +func (k Keeper) GetFeeModuleAddress() sdk.AccAddress { + return k.authKeeper.GetModuleAddress(types.ModuleName) +} + +// EscrowAccountHasBalance verifies if the escrow account has the provided fee. +func (k Keeper) EscrowAccountHasBalance(ctx sdk.Context, coins sdk.Coins) bool { + for _, coin := range coins { + if !k.bankKeeper.HasBalance(ctx, k.GetFeeModuleAddress(), coin) { + return false + } + } + + return true +} + +// SetFeeEnabled sets a flag to determine if fee handling logic should run for the given channel +// identified by channel and port identifiers. +func (k Keeper) SetFeeEnabled(ctx sdk.Context, portID, channelID string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyFeeEnabled(portID, channelID), []byte{1}) +} + +// DeleteFeeEnabled deletes the fee enabled flag for a given portID and channelID +func (k Keeper) DeleteFeeEnabled(ctx sdk.Context, portID, channelID string) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.KeyFeeEnabled(portID, channelID)) +} + +// IsFeeEnabled returns whether fee handling logic should be run for the given port. It will check the +// fee enabled flag for the given port and channel identifiers +func (k Keeper) IsFeeEnabled(ctx sdk.Context, portID, channelID string) bool { + store := ctx.KVStore(k.storeKey) + return store.Get(types.KeyFeeEnabled(portID, channelID)) != nil +} + +// GetAllFeeEnabledChannels returns a list of all ics29 enabled channels containing portID & channelID that are stored in state +func (k Keeper) GetAllFeeEnabledChannels(ctx sdk.Context) []types.FeeEnabledChannel { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.FeeEnabledKeyPrefix)) + defer iterator.Close() + + var enabledChArr []types.FeeEnabledChannel + for ; iterator.Valid(); iterator.Next() { + portID, channelID, err := types.ParseKeyFeeEnabled(string(iterator.Key())) + if err != nil { + panic(err) + } + ch := types.FeeEnabledChannel{ + PortId: portID, + ChannelId: channelID, + } + + enabledChArr = append(enabledChArr, ch) + } + + return enabledChArr +} + +// DisableAllChannels will disable the fee module for all channels. +// Only called if the module enters into an invalid state +// e.g. ModuleAccount has insufficient balance to refund users. +// In this case, chain developers should investigate the issue, fix it, +// and then re-enable the fee module in a coordinated upgrade. +func (k Keeper) DisableAllChannels(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.FeeEnabledKeyPrefix)) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + store.Delete(iterator.Key()) + } +} + +// SetCounterpartyAddress maps the destination chain relayer address to the source relayer address +// The receiving chain must store the mapping from: address -> counterpartyAddress for the given channel +func (k Keeper) SetCounterpartyAddress(ctx sdk.Context, address, counterpartyAddress, channelID string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyCounterpartyRelayer(address, channelID), []byte(counterpartyAddress)) +} + +// GetCounterpartyAddress gets the relayer counterparty address given a destination relayer address +func (k Keeper) GetCounterpartyAddress(ctx sdk.Context, address, channelID string) (string, bool) { + store := ctx.KVStore(k.storeKey) + key := types.KeyCounterpartyRelayer(address, channelID) + + if !store.Has(key) { + return "", false + } + + addr := string(store.Get(key)) + return addr, true +} + +// GetAllRelayerAddresses returns all registered relayer addresses +func (k Keeper) GetAllRelayerAddresses(ctx sdk.Context) []types.RegisteredRelayerAddress { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.CounterpartyRelayerAddressKeyPrefix)) + defer iterator.Close() + + var registeredAddrArr []types.RegisteredRelayerAddress + for ; iterator.Valid(); iterator.Next() { + address, channelID, err := types.ParseKeyCounterpartyRelayer(string(iterator.Key())) + if err != nil { + panic(err) + } + + addr := types.RegisteredRelayerAddress{ + Address: address, + CounterpartyAddress: string(iterator.Value()), + ChannelId: channelID, + } + + registeredAddrArr = append(registeredAddrArr, addr) + } + + return registeredAddrArr +} + +// SetRelayerAddressForAsyncAck sets the forward relayer address during OnRecvPacket in case of async acknowledgement +func (k Keeper) SetRelayerAddressForAsyncAck(ctx sdk.Context, packetID channeltypes.PacketId, address string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyForwardRelayerAddress(packetID), []byte(address)) +} + +// GetRelayerAddressForAsyncAck gets forward relayer address for a particular packet +func (k Keeper) GetRelayerAddressForAsyncAck(ctx sdk.Context, packetID channeltypes.PacketId) (string, bool) { + store := ctx.KVStore(k.storeKey) + key := types.KeyForwardRelayerAddress(packetID) + if !store.Has(key) { + return "", false + } + + addr := string(store.Get(key)) + return addr, true +} + +// GetAllForwardRelayerAddresses returns all forward relayer addresses stored for async acknowledgements +func (k Keeper) GetAllForwardRelayerAddresses(ctx sdk.Context) []types.ForwardRelayerAddress { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.ForwardRelayerPrefix)) + defer iterator.Close() + + var forwardRelayerAddr []types.ForwardRelayerAddress + for ; iterator.Valid(); iterator.Next() { + packetID, err := types.ParseKeyForwardRelayerAddress(string(iterator.Key())) + if err != nil { + panic(err) + } + + addr := types.ForwardRelayerAddress{ + Address: string(iterator.Value()), + PacketId: packetID, + } + + forwardRelayerAddr = append(forwardRelayerAddr, addr) + } + + return forwardRelayerAddr +} + +// Deletes the forwardRelayerAddr associated with the packetID +func (k Keeper) DeleteForwardRelayerAddress(ctx sdk.Context, packetID channeltypes.PacketId) { + store := ctx.KVStore(k.storeKey) + key := types.KeyForwardRelayerAddress(packetID) + store.Delete(key) +} + +// GetFeesInEscrow returns all escrowed packet fees for a given packetID +func (k Keeper) GetFeesInEscrow(ctx sdk.Context, packetID channeltypes.PacketId) (types.PacketFees, bool) { + store := ctx.KVStore(k.storeKey) + key := types.KeyFeesInEscrow(packetID) + bz := store.Get(key) + if bz == nil { + return types.PacketFees{}, false + } + + return k.MustUnmarshalFees(bz), true +} + +// HasFeesInEscrow returns true if packet fees exist for the provided packetID +func (k Keeper) HasFeesInEscrow(ctx sdk.Context, packetID channeltypes.PacketId) bool { + store := ctx.KVStore(k.storeKey) + key := types.KeyFeesInEscrow(packetID) + + return store.Has(key) +} + +// SetFeesInEscrow sets the given packet fees in escrow keyed by the packetID +func (k Keeper) SetFeesInEscrow(ctx sdk.Context, packetID channeltypes.PacketId, fees types.PacketFees) { + store := ctx.KVStore(k.storeKey) + bz := k.MustMarshalFees(fees) + store.Set(types.KeyFeesInEscrow(packetID), bz) +} + +// DeleteFeesInEscrow deletes the fee associated with the given packetID +func (k Keeper) DeleteFeesInEscrow(ctx sdk.Context, packetID channeltypes.PacketId) { + store := ctx.KVStore(k.storeKey) + key := types.KeyFeesInEscrow(packetID) + store.Delete(key) +} + +// IteratePacketFeesInEscrow iterates over all the fees on the given channel currently escrowed and calls the provided callback +// if the callback returns true, then iteration is stopped. +func (k Keeper) IteratePacketFeesInEscrow(ctx sdk.Context, portID, channelID string, cb func(packetFees types.PacketFees) (stop bool)) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.KeyFeesInEscrowChannelPrefix(portID, channelID)) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + packetFees := k.MustUnmarshalFees(iterator.Value()) + if cb(packetFees) { + break + } + } +} + +// GetAllIdentifiedPacketFees returns a list of all IdentifiedPacketFees that are stored in state +func (k Keeper) GetAllIdentifiedPacketFees(ctx sdk.Context) []types.IdentifiedPacketFees { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.FeesInEscrowPrefix)) + defer iterator.Close() + + var identifiedFees []types.IdentifiedPacketFees + for ; iterator.Valid(); iterator.Next() { + packetID, err := types.ParseKeyFeesInEscrow(string(iterator.Key())) + if err != nil { + panic(err) + } + + feesInEscrow := k.MustUnmarshalFees(iterator.Value()) + + identifiedFee := types.IdentifiedPacketFees{ + PacketId: packetID, + PacketFees: feesInEscrow.PacketFees, + } + + identifiedFees = append(identifiedFees, identifiedFee) + } + + return identifiedFees +} + +// MustMarshalFees attempts to encode a Fee object and returns the +// raw encoded bytes. It panics on error. +func (k Keeper) MustMarshalFees(fees types.PacketFees) []byte { + return k.cdc.MustMarshal(&fees) +} + +// MustUnmarshalFees attempts to decode and return a Fee object from +// raw encoded bytes. It panics on error. +func (k Keeper) MustUnmarshalFees(bz []byte) types.PacketFees { + var fees types.PacketFees + k.cdc.MustUnmarshal(bz, &fees) + return fees +} diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go new file mode 100644 index 00000000000..1f29a8872d5 --- /dev/null +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -0,0 +1,202 @@ +package keeper_test + +import ( + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" + ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" +) + +var ( + defaultReceiveFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}} + defaultAckFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}} + defaultTimeoutFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(300)}} + invalidCoins = sdk.Coins{sdk.Coin{Denom: "invalidDenom", Amount: sdk.NewInt(100)}} +) + +type KeeperTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + // testing chains used for convenience and readability + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain + chainC *ibctesting.TestChain + + path *ibctesting.Path + pathAToC *ibctesting.Path + + queryClient types.QueryClient +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) + suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3)) + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + mockFeeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})) + path.EndpointA.ChannelConfig.Version = mockFeeVersion + path.EndpointB.ChannelConfig.Version = mockFeeVersion + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + suite.path = path + + path = ibctesting.NewPath(suite.chainA, suite.chainC) + path.EndpointA.ChannelConfig.Version = mockFeeVersion + path.EndpointB.ChannelConfig.Version = mockFeeVersion + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + suite.pathAToC = path + + queryHelper := baseapp.NewQueryServerTestHelper(suite.chainA.GetContext(), suite.chainA.GetSimApp().InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, suite.chainA.GetSimApp().IBCFeeKeeper) + suite.queryClient = types.NewQueryClient(queryHelper) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func (suite *KeeperTestSuite) TestEscrowAccountHasBalance() { + fee := types.Fee{ + AckFee: defaultAckFee, + RecvFee: defaultReceiveFee, + TimeoutFee: defaultTimeoutFee, + } + + suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.EscrowAccountHasBalance(suite.chainA.GetContext(), fee.Total())) + + // set fee in escrow account + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, fee.Total()) + suite.Require().Nil(err) + + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.EscrowAccountHasBalance(suite.chainA.GetContext(), fee.Total())) + + // increase ack fee + fee.AckFee = fee.AckFee.Add(defaultAckFee...) + suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.EscrowAccountHasBalance(suite.chainA.GetContext(), fee.Total())) + +} + +func (suite *KeeperTestSuite) TestFeesInEscrow() { + suite.coordinator.Setup(suite.path) + + // escrow five fees for packet sequence 1 + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, 1) + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + + for i := 1; i < 6; i++ { + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), nil) + suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + } + + // retrieve the fees in escrow and assert the length of PacketFees + feesInEscrow, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().True(found) + suite.Require().Len(feesInEscrow.PacketFees, 5, fmt.Sprintf("expected length 5, but got %d", len(feesInEscrow.PacketFees))) + + // delete fees for packet sequence 1 + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeesInEscrow(suite.chainA.GetContext(), packetID) + hasFeesInEscrow := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(hasFeesInEscrow) +} + +func (suite *KeeperTestSuite) TestDisableAllChannels() { + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "port1", "channel1") + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "port2", "channel2") + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "port3", "channel3") + + suite.chainA.GetSimApp().IBCFeeKeeper.DisableAllChannels(suite.chainA.GetContext()) + + suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "port1", "channel1"), + "fee is still enabled on channel-1 after DisableAllChannels call") + suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "port2", "channel2"), + "fee is still enabled on channel-2 after DisableAllChannels call") + suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "port3", "channel3"), + "fee is still enabled on channel-3 after DisableAllChannels call") +} + +func (suite *KeeperTestSuite) TestGetAllIdentifiedPacketFees() { + suite.coordinator.Setup(suite.path) + + // escrow a fee + refundAcc := suite.chainA.SenderAccount.GetAddress() + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, 1) + fee := types.Fee{ + AckFee: defaultAckFee, + RecvFee: defaultReceiveFee, + TimeoutFee: defaultTimeoutFee, + } + + // escrow the packet fee + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) + + expectedFees := []types.IdentifiedPacketFees{ + { + PacketId: packetID, + PacketFees: []types.PacketFee{ + { + Fee: fee, + RefundAddress: refundAcc.String(), + Relayers: nil, + }, + }, + }, + } + + identifiedFees := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllIdentifiedPacketFees(suite.chainA.GetContext()) + suite.Require().Len(identifiedFees, len(expectedFees)) + suite.Require().Equal(identifiedFees, expectedFees) +} + +func (suite *KeeperTestSuite) TestGetAllFeeEnabledChannels() { + validPortId := "ibcmoduleport" + // set two channels enabled + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), validPortId, ibctesting.FirstChannelID) + + expectedCh := []types.FeeEnabledChannel{ + { + PortId: validPortId, + ChannelId: ibctesting.FirstChannelID, + }, + { + PortId: ibctesting.MockFeePort, + ChannelId: ibctesting.FirstChannelID, + }, + } + + ch := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllFeeEnabledChannels(suite.chainA.GetContext()) + suite.Require().Len(ch, len(expectedCh)) + suite.Require().Equal(ch, expectedCh) +} + +func (suite *KeeperTestSuite) TestGetAllRelayerAddresses() { + sender := suite.chainA.SenderAccount.GetAddress().String() + counterparty := suite.chainB.SenderAccount.GetAddress().String() + + suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID) + + expectedAddr := []types.RegisteredRelayerAddress{ + { + Address: sender, + CounterpartyAddress: counterparty, + ChannelId: ibctesting.FirstChannelID, + }, + } + + addr := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllRelayerAddresses(suite.chainA.GetContext()) + suite.Require().Len(addr, len(expectedAddr)) + suite.Require().Equal(addr, expectedAddr) +} diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go new file mode 100644 index 00000000000..fdac1d27874 --- /dev/null +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -0,0 +1,65 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" +) + +var _ types.MsgServer = Keeper{} + +// RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying +// This ensures they will be properly compensated for forward relaying on the source chain since the destination chain must send back relayer's source address (counterparty address) in acknowledgement +// This function may be called more than once by relayers, in which case, the previous counterparty address will be overwritten by the new counterparty address +func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.MsgRegisterCounterpartyAddress) (*types.MsgRegisterCounterpartyAddressResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + k.SetCounterpartyAddress( + ctx, msg.Address, msg.CounterpartyAddress, msg.ChannelId, + ) + + k.Logger(ctx).Info("Registering counterparty address for relayer.", "Address:", msg.Address, "Counterparty Address:", msg.CounterpartyAddress) + + return &types.MsgRegisterCounterpartyAddressResponse{}, nil +} + +// PayPacketFee defines a rpc handler method for MsgPayPacketFee +// PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to relay the packet with the next sequence +func (k Keeper) PayPacketFee(goCtx context.Context, msg *types.MsgPayPacketFee) (*types.MsgPayPacketFeeResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // get the next sequence + sequence, found := k.GetNextSequenceSend(ctx, msg.SourcePortId, msg.SourceChannelId) + if !found { + return nil, channeltypes.ErrSequenceSendNotFound + } + + packetID := channeltypes.NewPacketId( + msg.SourceChannelId, + msg.SourcePortId, + sequence, + ) + + packetFee := types.NewPacketFee(msg.Fee, msg.Signer, msg.Relayers) + if err := k.EscrowPacketFee(ctx, packetID, packetFee); err != nil { + return nil, err + } + + return &types.MsgPayPacketFeeResponse{}, nil +} + +// PayPacketFee defines a rpc handler method for MsgPayPacketFee +// PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to +// incentivize the relaying of a known packet +func (k Keeper) PayPacketFeeAsync(goCtx context.Context, msg *types.MsgPayPacketFeeAsync) (*types.MsgPayPacketFeeAsyncResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if err := k.EscrowPacketFee(ctx, msg.PacketId, msg.PacketFee); err != nil { + return nil, err + } + + return &types.MsgPayPacketFeeAsyncResponse{}, nil +} diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go new file mode 100644 index 00000000000..26ce387b60e --- /dev/null +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -0,0 +1,136 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() { + var ( + sender string + counterparty string + ) + + testCases := []struct { + name string + expPass bool + malleate func() + }{ + { + "success", + true, + func() {}, + }, + { + "counterparty is an arbitrary string", + true, + func() { counterparty = "arbitrary-string" }, + }, + } + + for _, tc := range testCases { + suite.SetupTest() + ctx := suite.chainA.GetContext() + + sender = suite.chainA.SenderAccount.GetAddress().String() + counterparty = suite.chainB.SenderAccount.GetAddress().String() + tc.malleate() + msg := types.NewMsgRegisterCounterpartyAddress(sender, counterparty, ibctesting.FirstChannelID) + + _, err := suite.chainA.SendMsgs(msg) + + if tc.expPass { + suite.Require().NoError(err) // message committed + + counterpartyAddress, _ := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(ctx, suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) + suite.Require().Equal(counterparty, counterpartyAddress) + } else { + suite.Require().Error(err) + } + } +} + +func (suite *KeeperTestSuite) TestPayPacketFee() { + testCases := []struct { + name string + expPass bool + malleate func() + }{ + { + "success", + true, + func() {}, + }, + } + + for _, tc := range testCases { + suite.SetupTest() + suite.coordinator.Setup(suite.path) // setup channel + + refundAcc := suite.chainA.SenderAccount.GetAddress() + channelID := suite.path.EndpointA.ChannelID + fee := types.Fee{ + RecvFee: defaultReceiveFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } + msg := types.NewMsgPayPacketFee(fee, suite.path.EndpointA.ChannelConfig.PortID, channelID, refundAcc.String(), []string{}) + + tc.malleate() + _, err := suite.chainA.SendMsgs(msg) + + if tc.expPass { + suite.Require().NoError(err) // message committed + } else { + suite.Require().Error(err) + } + } +} + +func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { + testCases := []struct { + name string + expPass bool + malleate func() + }{ + { + "success", + true, + func() {}, + }, + } + + for _, tc := range testCases { + suite.SetupTest() + suite.coordinator.Setup(suite.path) // setup channel + + ctxA := suite.chainA.GetContext() + + refundAcc := suite.chainA.SenderAccount.GetAddress() + + // build packetID + channelID := suite.path.EndpointA.ChannelID + fee := types.Fee{ + RecvFee: defaultReceiveFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } + seq, _ := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceSend(ctxA, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + + // build fee + packetID := channeltypes.NewPacketId(channelID, suite.path.EndpointA.ChannelConfig.PortID, seq) + packetFee := types.NewPacketFee(fee, refundAcc.String(), nil) + + tc.malleate() + + msg := types.NewMsgPayPacketFeeAsync(packetID, packetFee) + _, err := suite.chainA.SendMsgs(msg) + + if tc.expPass { + suite.Require().NoError(err) // message committed + } else { + suite.Require().Error(err) + } + } +} diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go new file mode 100644 index 00000000000..a2ef8a7ca11 --- /dev/null +++ b/modules/apps/29-fee/keeper/relay.go @@ -0,0 +1,44 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" +) + +// SendPacket wraps IBC ChannelKeeper's SendPacket function +func (k Keeper) SendPacket(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI) error { + return k.ics4Wrapper.SendPacket(ctx, chanCap, packet) +} + +// WriteAcknowledgement wraps IBC ChannelKeeper's WriteAcknowledgement function +// ICS29 WriteAcknowledgement is used for asynchronous acknowledgements +func (k Keeper) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error { + if !k.IsFeeEnabled(ctx, packet.GetDestPort(), packet.GetDestChannel()) { + // ics4Wrapper may be core IBC or higher-level middleware + return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, acknowledgement) + } + + packetID := channeltypes.NewPacketId(packet.GetDestChannel(), packet.GetDestPort(), packet.GetSequence()) + + // retrieve the forward relayer that was stored in `onRecvPacket` + relayer, found := k.GetRelayerAddressForAsyncAck(ctx, packetID) + if !found { + return sdkerrors.Wrapf(types.ErrRelayerNotFoundForAsyncAck, "no relayer address stored for async acknowledgement for packet with portID: %s, channelID: %s, sequence: %d", packetID.PortId, packetID.ChannelId, packetID.Sequence) + } + + // it is possible that a relayer has not registered a counterparty address. + // if there is no registered counterparty address then write acknowledgement with empty relayer address and refund recv_fee. + forwardRelayer, _ := k.GetCounterpartyAddress(ctx, relayer, packet.GetDestChannel()) + + ack := types.NewIncentivizedAcknowledgement(forwardRelayer, acknowledgement.Acknowledgement(), acknowledgement.Success()) + + k.DeleteForwardRelayerAddress(ctx, packetID) + + // ics4Wrapper may be core IBC or higher-level middleware + return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) +} diff --git a/modules/apps/29-fee/keeper/relay_test.go b/modules/apps/29-fee/keeper/relay_test.go new file mode 100644 index 00000000000..3cfd627b520 --- /dev/null +++ b/modules/apps/29-fee/keeper/relay_test.go @@ -0,0 +1,103 @@ +package keeper_test + +import ( + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" +) + +func (suite *KeeperTestSuite) TestWriteAcknowledgementAsync() { + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() { + suite.chainB.GetSimApp().IBCFeeKeeper.SetRelayerAddressForAsyncAck(suite.chainB.GetContext(), channeltypes.NewPacketId(suite.path.EndpointB.ChannelID, suite.path.EndpointB.ChannelConfig.PortID, 1), suite.chainA.SenderAccount.GetAddress().String()) + suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) + }, + true, + }, + { + "relayer address not set for async WriteAcknowledgement", + func() {}, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + // open incentivized channels + // setup pathAToC (chainA -> chainC) first in order to have different channel IDs for chainA & chainB + suite.coordinator.Setup(suite.pathAToC) + // setup path for chainA -> chainB + suite.coordinator.Setup(suite.path) + + // build packet + timeoutTimestamp := ^uint64(0) + packet := channeltypes.NewPacket( + []byte("packetData"), + 1, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + clienttypes.ZeroHeight(), + timeoutTimestamp, + ) + + ack := channeltypes.NewResultAcknowledgement([]byte("success")) + chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + + // malleate test case + tc.malleate() + + err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) + + if tc.expPass { + suite.Require().NoError(err) + _, found := suite.chainB.GetSimApp().IBCFeeKeeper.GetRelayerAddressForAsyncAck(suite.chainB.GetContext(), channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, 1)) + suite.Require().False(found) + + expectedAck := types.NewIncentivizedAcknowledgement(suite.chainB.SenderAccount.GetAddress().String(), ack.Acknowledgement(), ack.Success()) + commitedAck, _ := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) + suite.Require().Equal(commitedAck, channeltypes.CommitAcknowledgement(expectedAck.Acknowledgement())) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestWriteAcknowledgementAsyncFeeDisabled() { + // open incentivized channel + suite.coordinator.Setup(suite.path) + suite.chainB.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainB.GetContext(), suite.path.EndpointB.ChannelConfig.PortID, "channel-0") + + // build packet + timeoutTimestamp := ^uint64(0) + packet := channeltypes.NewPacket( + []byte("packetData"), + 1, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.path.EndpointB.ChannelConfig.PortID, + suite.path.EndpointB.ChannelID, + clienttypes.ZeroHeight(), + timeoutTimestamp, + ) + + ack := channeltypes.NewResultAcknowledgement([]byte("success")) + chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) + + err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) + suite.Require().NoError(err) + + packetAck, _ := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) + suite.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) +} diff --git a/modules/apps/29-fee/module.go b/modules/apps/29-fee/module.go new file mode 100644 index 00000000000..bb9b7081c7c --- /dev/null +++ b/modules/apps/29-fee/module.go @@ -0,0 +1,179 @@ +package fee + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/client/cli" + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/keeper" + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + + // "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/client/cli" + // "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/simulation" + + porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" +) + +var ( + _ module.AppModule = AppModule{} + _ porttypes.IBCModule = IBCModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// AppModuleBasic is the 29-fee AppModuleBasic +type AppModuleBasic struct{} + +// Name implements AppModuleBasic interface +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec implements AppModuleBasic interface +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} + +// RegisterInterfaces registers module concrete types into protobuf Any. +func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// DefaultGenesis returns default genesis state as raw bytes for the ibc +// 29-fee module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesisState()) +} + +// ValidateGenesis performs genesis state validation for the 29-fee module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var gs types.GenesisState + if err := cdc.UnmarshalJSON(bz, &gs); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + + return gs.Validate() +} + +// RegisterRESTRoutes implements AppModuleBasic interface +func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) { +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for ics29 fee module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) +} + +// GetTxCmd implements AppModuleBasic interface +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.NewTxCmd() +} + +// GetQueryCmd implements AppModuleBasic interface +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// AppModule represents the AppModule for this module +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper +} + +// NewAppModule creates a new 29-fee module +func NewAppModule(k keeper.Keeper) AppModule { + return AppModule{ + keeper: k, + } +} + +// RegisterInvariants implements the AppModule interface +func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + // TODO +} + +// Route implements the AppModule interface +func (am AppModule) Route() sdk.Route { + return sdk.Route{} +} + +// QuerierRoute implements the AppModule interface +func (AppModule) QuerierRoute() string { + return types.QuerierRoute +} + +// LegacyQuerierHandler implements the AppModule interface +func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers module services. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), am.keeper) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// InitGenesis performs genesis initialization for the ibc-29-fee 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 + cdc.MustUnmarshalJSON(data, &genesisState) + am.keeper.InitGenesis(ctx, genesisState) + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the exported genesis state as raw bytes for the ibc-29-fee +// module. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(gs) +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock implements the AppModule interface +func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { +} + +// EndBlock implements the AppModule interface +func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the 29-fee module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized ibc-29-fee param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { + // return simulation.ParamChanges(r) + return nil +} + +// RegisterStoreDecoder registers a decoder for 29-fee module's types +func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + // sdr[types.StoreKey] = simulation.NewDecodeStore(am.keeper) +} + +// WeightedOperations returns the all the 29-fee module operations with their respective weights. +func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { + return nil +} diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go new file mode 100644 index 00000000000..a07d841d07c --- /dev/null +++ b/modules/apps/29-fee/transfer_test.go @@ -0,0 +1,72 @@ +package fee_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +// Integration test to ensure ics29 works with ics20 +func (suite *FeeTestSuite) TestFeeTransfer() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.Version})) + path.EndpointA.ChannelConfig.Version = feeTransferVersion + path.EndpointB.ChannelConfig.Version = feeTransferVersion + path.EndpointA.ChannelConfig.PortID = transfertypes.PortID + path.EndpointB.ChannelConfig.PortID = transfertypes.PortID + + suite.coordinator.Setup(path) + + // set up coin & ics20 packet + coin := ibctesting.TestCoin + fee := types.Fee{ + RecvFee: validCoins, + AckFee: validCoins2, + TimeoutFee: validCoins3, + } + + msgs := []sdk.Msg{ + types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 100), 0), + } + res, err := suite.chainA.SendMsgs(msgs...) + suite.Require().NoError(err) // message committed + + // after incentivizing the packets + originalChainASenderAccountBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + suite.Require().NoError(err) + + // register counterparty address on chainB + // relayerAddress is address of sender account on chainB, but we will use it on chainA + // to differentiate from the chainA.SenderAccount for checking successful relay payouts + relayerAddress := suite.chainB.SenderAccount.GetAddress() + + msgRegister := types.NewMsgRegisterCounterpartyAddress(suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String(), ibctesting.FirstChannelID) + _, err = suite.chainB.SendMsgs(msgRegister) + suite.Require().NoError(err) // message committed + + // relay packet + err = path.RelayPacket(packet) + suite.Require().NoError(err) // relay committed + + // ensure relayers got paid + // relayer for forward relay: chainB.SenderAccount + // relayer for reverse relay: chainA.SenderAccount + + // check forward relay balance + suite.Require().Equal( + fee.RecvFee, + sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), + ) + + suite.Require().Equal( + fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded + sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)).Sub(originalChainASenderAccountBalance), + ) + +} diff --git a/modules/apps/29-fee/types/ack.go b/modules/apps/29-fee/types/ack.go new file mode 100644 index 00000000000..229d8e4cc3f --- /dev/null +++ b/modules/apps/29-fee/types/ack.go @@ -0,0 +1,27 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// NewIncentivizedAcknowledgement creates a new instance of IncentivizedAcknowledgement +func NewIncentivizedAcknowledgement(relayer string, ack []byte, success bool) IncentivizedAcknowledgement { + return IncentivizedAcknowledgement{ + Result: ack, + ForwardRelayerAddress: relayer, + UnderlyingAppSuccess: success, + } +} + +// Success implements the Acknowledgement interface. The acknowledgement is +// considered successful if the forward relayer address is empty. Otherwise it is +// considered a failed acknowledgement. +func (ack IncentivizedAcknowledgement) Success() bool { + return ack.UnderlyingAppSuccess +} + +// Acknowledgement implements the Acknowledgement interface. It returns the +// acknowledgement serialised using JSON. +func (ack IncentivizedAcknowledgement) Acknowledgement() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&ack)) +} diff --git a/modules/apps/29-fee/types/ack.pb.go b/modules/apps/29-fee/types/ack.pb.go new file mode 100644 index 00000000000..4f6437da224 --- /dev/null +++ b/modules/apps/29-fee/types/ack.pb.go @@ -0,0 +1,423 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/fee/v1/ack.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware +type IncentivizedAcknowledgement struct { + // the underlying app acknowledgement result bytes + Result []byte `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` + // the relayer address which submits the recv packet message + ForwardRelayerAddress string `protobuf:"bytes,2,opt,name=forward_relayer_address,json=forwardRelayerAddress,proto3" json:"forward_relayer_address,omitempty" yaml:"forward_relayer_address"` + // success flag of the base application callback + UnderlyingAppSuccess bool `protobuf:"varint,3,opt,name=underlying_app_success,json=underlyingAppSuccess,proto3" json:"underlying_app_success,omitempty" yaml:"underlying_app_successl"` +} + +func (m *IncentivizedAcknowledgement) Reset() { *m = IncentivizedAcknowledgement{} } +func (m *IncentivizedAcknowledgement) String() string { return proto.CompactTextString(m) } +func (*IncentivizedAcknowledgement) ProtoMessage() {} +func (*IncentivizedAcknowledgement) Descriptor() ([]byte, []int) { + return fileDescriptor_ab2834946fb65ea4, []int{0} +} +func (m *IncentivizedAcknowledgement) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IncentivizedAcknowledgement) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IncentivizedAcknowledgement.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *IncentivizedAcknowledgement) XXX_Merge(src proto.Message) { + xxx_messageInfo_IncentivizedAcknowledgement.Merge(m, src) +} +func (m *IncentivizedAcknowledgement) XXX_Size() int { + return m.Size() +} +func (m *IncentivizedAcknowledgement) XXX_DiscardUnknown() { + xxx_messageInfo_IncentivizedAcknowledgement.DiscardUnknown(m) +} + +var xxx_messageInfo_IncentivizedAcknowledgement proto.InternalMessageInfo + +func (m *IncentivizedAcknowledgement) GetResult() []byte { + if m != nil { + return m.Result + } + return nil +} + +func (m *IncentivizedAcknowledgement) GetForwardRelayerAddress() string { + if m != nil { + return m.ForwardRelayerAddress + } + return "" +} + +func (m *IncentivizedAcknowledgement) GetUnderlyingAppSuccess() bool { + if m != nil { + return m.UnderlyingAppSuccess + } + return false +} + +func init() { + proto.RegisterType((*IncentivizedAcknowledgement)(nil), "ibc.applications.fee.v1.IncentivizedAcknowledgement") +} + +func init() { proto.RegisterFile("ibc/applications/fee/v1/ack.proto", fileDescriptor_ab2834946fb65ea4) } + +var fileDescriptor_ab2834946fb65ea4 = []byte{ + // 315 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0xb1, 0x4e, 0xf3, 0x30, + 0x14, 0x85, 0xeb, 0xff, 0x97, 0x2a, 0x88, 0x98, 0xa2, 0xd2, 0x56, 0x20, 0x85, 0x92, 0xa9, 0x4b, + 0x63, 0x95, 0x8a, 0x01, 0xb6, 0x76, 0x63, 0x42, 0x0a, 0x0b, 0xea, 0x12, 0x39, 0xf6, 0x6d, 0xb0, + 0xea, 0xd8, 0x96, 0xed, 0xa4, 0x0a, 0x4f, 0xc1, 0x63, 0x31, 0x76, 0x64, 0x42, 0xa8, 0x1d, 0xd9, + 0x78, 0x02, 0x94, 0xa6, 0x12, 0x1d, 0x60, 0xbb, 0xf7, 0x9c, 0x4f, 0x67, 0xf8, 0xbc, 0x4b, 0x9e, + 0x52, 0x4c, 0xb4, 0x16, 0x9c, 0x12, 0xc7, 0x95, 0xb4, 0x78, 0x01, 0x80, 0xcb, 0x31, 0x26, 0x74, + 0x19, 0x69, 0xa3, 0x9c, 0xf2, 0x7b, 0x3c, 0xa5, 0xd1, 0x21, 0x12, 0x2d, 0x00, 0xa2, 0x72, 0x7c, + 0xd6, 0xc9, 0x54, 0xa6, 0x76, 0x0c, 0xae, 0xaf, 0x06, 0x0f, 0x3f, 0x91, 0x77, 0x7e, 0x27, 0x29, + 0x48, 0xc7, 0x4b, 0xfe, 0x0c, 0x6c, 0x4a, 0x97, 0x52, 0xad, 0x04, 0xb0, 0x0c, 0x72, 0x90, 0xce, + 0xef, 0x7a, 0x6d, 0x03, 0xb6, 0x10, 0xae, 0x8f, 0x06, 0x68, 0x78, 0x12, 0xef, 0x3f, 0x7f, 0xee, + 0xf5, 0x16, 0xca, 0xac, 0x88, 0x61, 0x89, 0x01, 0x41, 0x2a, 0x30, 0x09, 0x61, 0xcc, 0x80, 0xb5, + 0xfd, 0x7f, 0x03, 0x34, 0x3c, 0x9e, 0x85, 0x5f, 0xef, 0x17, 0x41, 0x45, 0x72, 0x71, 0x1b, 0xfe, + 0x01, 0x86, 0xf1, 0xe9, 0xbe, 0x89, 0x9b, 0x62, 0xda, 0xe4, 0xfe, 0xa3, 0xd7, 0x2d, 0x24, 0x03, + 0x23, 0x2a, 0x2e, 0xb3, 0x84, 0x68, 0x9d, 0xd8, 0x82, 0xd2, 0x7a, 0xfa, 0xff, 0x00, 0x0d, 0x8f, + 0x0e, 0xa7, 0x7f, 0xe7, 0x44, 0x18, 0x77, 0x7e, 0x9a, 0xa9, 0xd6, 0x0f, 0x4d, 0x3e, 0xbb, 0x7f, + 0xdd, 0x04, 0x68, 0xbd, 0x09, 0xd0, 0xc7, 0x26, 0x40, 0x2f, 0xdb, 0xa0, 0xb5, 0xde, 0x06, 0xad, + 0xb7, 0x6d, 0xd0, 0x9a, 0x5f, 0x67, 0xdc, 0x3d, 0x15, 0x69, 0x44, 0x55, 0x8e, 0xa9, 0xb2, 0xb9, + 0xb2, 0x98, 0xa7, 0x74, 0x94, 0x29, 0x5c, 0x4e, 0x70, 0xae, 0x58, 0x21, 0xc0, 0xd6, 0xe6, 0x2d, + 0xbe, 0xba, 0x19, 0xd5, 0xd2, 0x5d, 0xa5, 0xc1, 0xa6, 0xed, 0x9d, 0xc5, 0xc9, 0x77, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x2e, 0x38, 0x5f, 0x80, 0x99, 0x01, 0x00, 0x00, +} + +func (m *IncentivizedAcknowledgement) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *IncentivizedAcknowledgement) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IncentivizedAcknowledgement) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.UnderlyingAppSuccess { + i-- + if m.UnderlyingAppSuccess { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if len(m.ForwardRelayerAddress) > 0 { + i -= len(m.ForwardRelayerAddress) + copy(dAtA[i:], m.ForwardRelayerAddress) + i = encodeVarintAck(dAtA, i, uint64(len(m.ForwardRelayerAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.Result) > 0 { + i -= len(m.Result) + copy(dAtA[i:], m.Result) + i = encodeVarintAck(dAtA, i, uint64(len(m.Result))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintAck(dAtA []byte, offset int, v uint64) int { + offset -= sovAck(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *IncentivizedAcknowledgement) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Result) + if l > 0 { + n += 1 + l + sovAck(uint64(l)) + } + l = len(m.ForwardRelayerAddress) + if l > 0 { + n += 1 + l + sovAck(uint64(l)) + } + if m.UnderlyingAppSuccess { + n += 2 + } + return n +} + +func sovAck(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAck(x uint64) (n int) { + return sovAck(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *IncentivizedAcknowledgement) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAck + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: IncentivizedAcknowledgement: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IncentivizedAcknowledgement: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAck + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAck + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAck + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Result = append(m.Result[:0], dAtA[iNdEx:postIndex]...) + if m.Result == nil { + m.Result = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ForwardRelayerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAck + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAck + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAck + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ForwardRelayerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnderlyingAppSuccess", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAck + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.UnderlyingAppSuccess = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipAck(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAck + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAck(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAck + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAck + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAck + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAck + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAck + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAck + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAck = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAck = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAck = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/29-fee/types/codec.go b/modules/apps/29-fee/types/codec.go new file mode 100644 index 00000000000..846716d740f --- /dev/null +++ b/modules/apps/29-fee/types/codec.go @@ -0,0 +1,42 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +// RegisterLegacyAminoCodec registers the necessary x/ibc 29-fee interfaces and concrete types +// on the provided LegacyAmino codec. These types are used for Amino JSON serialization. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgRegisterCounterpartyAddress{}, "cosmos-sdk/MsgRegisterCounterpartyAddress", nil) + cdc.RegisterConcrete(&MsgPayPacketFee{}, "cosmos-sdk/MsgPayPacketFee", nil) + cdc.RegisterConcrete(&MsgPayPacketFeeAsync{}, "cosmos-sdk/MsgPayPacketFeeAsync", nil) +} + +// RegisterInterfaces register the 29-fee module interfaces to protobuf +// Any. +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), &MsgRegisterCounterpartyAddress{}, &MsgPayPacketFee{}, &MsgPayPacketFeeAsync{}) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + amino = codec.NewLegacyAmino() + + // ModuleCdc references the global x/ibc-transfer module codec. Note, the codec + // should ONLY be used in certain instances of tests and for JSON encoding. + // + // The actual codec used for serialization should be provided to x/ibc transfer and + // defined at the application level. + ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + + // AminoCdc is a amino codec created to support amino json compatible msgs. + AminoCdc = codec.NewAminoCodec(amino) +) + +func init() { + RegisterLegacyAminoCodec(amino) + amino.Seal() +} diff --git a/modules/apps/29-fee/types/errors.go b/modules/apps/29-fee/types/errors.go new file mode 100644 index 00000000000..75fdd436c91 --- /dev/null +++ b/modules/apps/29-fee/types/errors.go @@ -0,0 +1,18 @@ +package types + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// 29-fee sentinel errors +var ( + ErrInvalidVersion = sdkerrors.Register(ModuleName, 2, "invalid ICS29 middleware version") + ErrRefundAccNotFound = sdkerrors.Register(ModuleName, 3, "no account found for given refund address") + ErrBalanceNotFound = sdkerrors.Register(ModuleName, 4, "balance not found for given account address") + ErrFeeNotFound = sdkerrors.Register(ModuleName, 5, "there is no fee escrowed for the given packetID") + ErrRelayersNotNil = sdkerrors.Register(ModuleName, 6, "relayers must be nil. This feature is not supported") + ErrCounterpartyAddressEmpty = sdkerrors.Register(ModuleName, 7, "counterparty address must not be empty") + ErrForwardRelayerAddressNotFound = sdkerrors.Register(ModuleName, 8, "forward relayer address not found") + ErrFeeNotEnabled = sdkerrors.Register(ModuleName, 9, "fee module is not enabled for this channel. If this error occurs after channel setup, fee module may not be enabled") + ErrRelayerNotFoundForAsyncAck = sdkerrors.Register(ModuleName, 10, "relayer address must be stored for async WriteAcknowledgement") +) diff --git a/modules/apps/29-fee/types/events.go b/modules/apps/29-fee/types/events.go new file mode 100644 index 00000000000..cac882d98d3 --- /dev/null +++ b/modules/apps/29-fee/types/events.go @@ -0,0 +1,10 @@ +package types + +// 29-fee events +const ( + EventTypeIncentivizedPacket = "incentivized_ibc_packet" + + AttributeKeyRecvFee = "recv_fee" + AttributeKeyAckFee = "ack_fee" + AttributeKeyTimeoutFee = "timeout_fee" +) diff --git a/modules/apps/29-fee/types/expected_keepers.go b/modules/apps/29-fee/types/expected_keepers.go new file mode 100644 index 00000000000..0b42718ff02 --- /dev/null +++ b/modules/apps/29-fee/types/expected_keepers.go @@ -0,0 +1,40 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" +) + +// AccountKeeper defines the contract required for account APIs. +type AccountKeeper interface { + GetModuleAddress(name string) sdk.AccAddress + GetAccount(sdk.Context, sdk.AccAddress) types.AccountI +} + +// ICS4Wrapper defines the expected ICS4Wrapper for middleware +type ICS4Wrapper interface { + WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error + SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error +} + +// ChannelKeeper defines the expected IBC channel keeper +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) + GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) +} + +// PortKeeper defines the expected IBC port keeper +type PortKeeper interface { + BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability +} + +// BankKeeper defines the expected bank keeper +type BankKeeper interface { + HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error +} diff --git a/modules/apps/29-fee/types/fee.go b/modules/apps/29-fee/types/fee.go new file mode 100644 index 00000000000..1f979c732d8 --- /dev/null +++ b/modules/apps/29-fee/types/fee.go @@ -0,0 +1,92 @@ +package types + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" +) + +// NewPacketFee creates and returns a new PacketFee struct including the incentivization fees, refund addres and relayers +func NewPacketFee(fee Fee, refundAddr string, relayers []string) PacketFee { + return PacketFee{ + Fee: fee, + RefundAddress: refundAddr, + Relayers: relayers, + } +} + +// Validate performs basic stateless validation of the associated PacketFee +func (p PacketFee) Validate() error { + _, err := sdk.AccAddressFromBech32(p.RefundAddress) + if err != nil { + return sdkerrors.Wrap(err, "failed to convert RefundAddress into sdk.AccAddress") + } + + // enforce relayer is nil + if p.Relayers != nil { + return ErrRelayersNotNil + } + + if err := p.Fee.Validate(); err != nil { + return err + } + + return nil +} + +// NewPacketFees creates and returns a new PacketFees struct including a list of type PacketFee +func NewPacketFees(packetFees []PacketFee) PacketFees { + return PacketFees{ + PacketFees: packetFees, + } +} + +// NewIdentifiedPacketFees creates and returns a new IdentifiedPacketFees struct containing a packet ID and packet fees +func NewIdentifiedPacketFees(packetID channeltypes.PacketId, packetFees []PacketFee) IdentifiedPacketFees { + return IdentifiedPacketFees{ + PacketId: packetID, + PacketFees: packetFees, + } +} + +// NewFee creates and returns a new Fee struct encapsulating the receive, acknowledgement and timeout fees as sdk.Coins +func NewFee(recvFee, ackFee, timeoutFee sdk.Coins) Fee { + return Fee{ + RecvFee: recvFee, + AckFee: ackFee, + TimeoutFee: timeoutFee, + } +} + +// Total returns the total amount for a given Fee +func (f Fee) Total() sdk.Coins { + return f.RecvFee.Add(f.AckFee...).Add(f.TimeoutFee...) +} + +// Validate asserts that each Fee is valid and all three Fees are not empty or zero +func (fee Fee) Validate() error { + var errFees []string + if !fee.AckFee.IsValid() { + errFees = append(errFees, "ack fee invalid") + } + if !fee.RecvFee.IsValid() { + errFees = append(errFees, "recv fee invalid") + } + if !fee.TimeoutFee.IsValid() { + errFees = append(errFees, "timeout fee invalid") + } + + if len(errFees) > 0 { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "contains invalid fees: %s", strings.Join(errFees, " , ")) + } + + // if all three fee's are zero or empty return an error + if fee.AckFee.IsZero() && fee.RecvFee.IsZero() && fee.TimeoutFee.IsZero() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "all fees are zero") + } + + return nil +} diff --git a/modules/apps/29-fee/types/fee.pb.go b/modules/apps/29-fee/types/fee.pb.go new file mode 100644 index 00000000000..1867eb351e5 --- /dev/null +++ b/modules/apps/29-fee/types/fee.pb.go @@ -0,0 +1,1182 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/fee/v1/fee.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Fee defines the ICS29 receive, acknowledgement and timeout fees +type Fee struct { + // the packet receive fee + RecvFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=recv_fee,json=recvFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"recv_fee" yaml:"recv_fee"` + // the packet acknowledgement fee + AckFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=ack_fee,json=ackFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"ack_fee" yaml:"ack_fee"` + // the packet timeout fee + TimeoutFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=timeout_fee,json=timeoutFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"timeout_fee" yaml:"timeout_fee"` +} + +func (m *Fee) Reset() { *m = Fee{} } +func (m *Fee) String() string { return proto.CompactTextString(m) } +func (*Fee) ProtoMessage() {} +func (*Fee) Descriptor() ([]byte, []int) { + return fileDescriptor_cb3319f1af2a53e5, []int{0} +} +func (m *Fee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Fee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Fee.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Fee) XXX_Merge(src proto.Message) { + xxx_messageInfo_Fee.Merge(m, src) +} +func (m *Fee) XXX_Size() int { + return m.Size() +} +func (m *Fee) XXX_DiscardUnknown() { + xxx_messageInfo_Fee.DiscardUnknown(m) +} + +var xxx_messageInfo_Fee proto.InternalMessageInfo + +func (m *Fee) GetRecvFee() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.RecvFee + } + return nil +} + +func (m *Fee) GetAckFee() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.AckFee + } + return nil +} + +func (m *Fee) GetTimeoutFee() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.TimeoutFee + } + return nil +} + +// PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers +type PacketFee struct { + // fee encapsulates the recv, ack and timeout fees associated with an IBC packet + Fee Fee `protobuf:"bytes,1,opt,name=fee,proto3" json:"fee"` + // the refund address for unspent fees + RefundAddress string `protobuf:"bytes,2,opt,name=refund_address,json=refundAddress,proto3" json:"refund_address,omitempty" yaml:"refund_address"` + // optional list of relayers permitted to receive fees + Relayers []string `protobuf:"bytes,3,rep,name=relayers,proto3" json:"relayers,omitempty"` +} + +func (m *PacketFee) Reset() { *m = PacketFee{} } +func (m *PacketFee) String() string { return proto.CompactTextString(m) } +func (*PacketFee) ProtoMessage() {} +func (*PacketFee) Descriptor() ([]byte, []int) { + return fileDescriptor_cb3319f1af2a53e5, []int{1} +} +func (m *PacketFee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PacketFee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PacketFee.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PacketFee) XXX_Merge(src proto.Message) { + xxx_messageInfo_PacketFee.Merge(m, src) +} +func (m *PacketFee) XXX_Size() int { + return m.Size() +} +func (m *PacketFee) XXX_DiscardUnknown() { + xxx_messageInfo_PacketFee.DiscardUnknown(m) +} + +var xxx_messageInfo_PacketFee proto.InternalMessageInfo + +func (m *PacketFee) GetFee() Fee { + if m != nil { + return m.Fee + } + return Fee{} +} + +func (m *PacketFee) GetRefundAddress() string { + if m != nil { + return m.RefundAddress + } + return "" +} + +func (m *PacketFee) GetRelayers() []string { + if m != nil { + return m.Relayers + } + return nil +} + +// PacketFees contains a list of type PacketFee +type PacketFees struct { + // list of packet fees + PacketFees []PacketFee `protobuf:"bytes,1,rep,name=packet_fees,json=packetFees,proto3" json:"packet_fees" yaml:"packet_fees"` +} + +func (m *PacketFees) Reset() { *m = PacketFees{} } +func (m *PacketFees) String() string { return proto.CompactTextString(m) } +func (*PacketFees) ProtoMessage() {} +func (*PacketFees) Descriptor() ([]byte, []int) { + return fileDescriptor_cb3319f1af2a53e5, []int{2} +} +func (m *PacketFees) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PacketFees) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PacketFees.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PacketFees) XXX_Merge(src proto.Message) { + xxx_messageInfo_PacketFees.Merge(m, src) +} +func (m *PacketFees) XXX_Size() int { + return m.Size() +} +func (m *PacketFees) XXX_DiscardUnknown() { + xxx_messageInfo_PacketFees.DiscardUnknown(m) +} + +var xxx_messageInfo_PacketFees proto.InternalMessageInfo + +func (m *PacketFees) GetPacketFees() []PacketFee { + if m != nil { + return m.PacketFees + } + return nil +} + +// IdentifiedPacketFees contains a list of type PacketFee and associated PacketId +type IdentifiedPacketFees struct { + // unique packet identifier comprised of the channel ID, port ID and sequence + PacketId types1.PacketId `protobuf:"bytes,1,opt,name=packet_id,json=packetId,proto3" json:"packet_id" yaml:"packet_id"` + // list of packet fees + PacketFees []PacketFee `protobuf:"bytes,2,rep,name=packet_fees,json=packetFees,proto3" json:"packet_fees" yaml:"packet_fees"` +} + +func (m *IdentifiedPacketFees) Reset() { *m = IdentifiedPacketFees{} } +func (m *IdentifiedPacketFees) String() string { return proto.CompactTextString(m) } +func (*IdentifiedPacketFees) ProtoMessage() {} +func (*IdentifiedPacketFees) Descriptor() ([]byte, []int) { + return fileDescriptor_cb3319f1af2a53e5, []int{3} +} +func (m *IdentifiedPacketFees) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *IdentifiedPacketFees) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_IdentifiedPacketFees.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *IdentifiedPacketFees) XXX_Merge(src proto.Message) { + xxx_messageInfo_IdentifiedPacketFees.Merge(m, src) +} +func (m *IdentifiedPacketFees) XXX_Size() int { + return m.Size() +} +func (m *IdentifiedPacketFees) XXX_DiscardUnknown() { + xxx_messageInfo_IdentifiedPacketFees.DiscardUnknown(m) +} + +var xxx_messageInfo_IdentifiedPacketFees proto.InternalMessageInfo + +func (m *IdentifiedPacketFees) GetPacketId() types1.PacketId { + if m != nil { + return m.PacketId + } + return types1.PacketId{} +} + +func (m *IdentifiedPacketFees) GetPacketFees() []PacketFee { + if m != nil { + return m.PacketFees + } + return nil +} + +func init() { + proto.RegisterType((*Fee)(nil), "ibc.applications.fee.v1.Fee") + proto.RegisterType((*PacketFee)(nil), "ibc.applications.fee.v1.PacketFee") + proto.RegisterType((*PacketFees)(nil), "ibc.applications.fee.v1.PacketFees") + proto.RegisterType((*IdentifiedPacketFees)(nil), "ibc.applications.fee.v1.IdentifiedPacketFees") +} + +func init() { proto.RegisterFile("ibc/applications/fee/v1/fee.proto", fileDescriptor_cb3319f1af2a53e5) } + +var fileDescriptor_cb3319f1af2a53e5 = []byte{ + // 525 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x31, 0x6f, 0x13, 0x31, + 0x14, 0xc7, 0x73, 0x09, 0x6a, 0x1b, 0x47, 0x14, 0x74, 0x2a, 0x22, 0x8d, 0xe0, 0x52, 0x3c, 0x65, + 0x89, 0xad, 0xa4, 0x30, 0xc0, 0x04, 0x57, 0x29, 0x52, 0x27, 0xd0, 0x89, 0x89, 0x25, 0xf2, 0xd9, + 0x2f, 0xa9, 0x95, 0xdc, 0xf9, 0x74, 0xbe, 0x44, 0xca, 0xca, 0x27, 0xe0, 0x1b, 0xb0, 0xf3, 0x49, + 0xba, 0x20, 0x75, 0x64, 0x0a, 0x28, 0xf9, 0x06, 0xdd, 0x91, 0x90, 0x7d, 0x4e, 0x94, 0x82, 0xaa, + 0xaa, 0x12, 0xd3, 0xf9, 0xd9, 0xef, 0xef, 0xdf, 0xb3, 0xdf, 0xff, 0x8c, 0x5e, 0xc8, 0x98, 0x53, + 0x96, 0x65, 0x53, 0xc9, 0x59, 0x21, 0x55, 0xaa, 0xe9, 0x08, 0x80, 0xce, 0x7b, 0xe6, 0x43, 0xb2, + 0x5c, 0x15, 0xca, 0x7f, 0x2a, 0x63, 0x4e, 0x76, 0x53, 0x88, 0x59, 0x9b, 0xf7, 0x5a, 0x01, 0x57, + 0x3a, 0x51, 0x9a, 0xc6, 0x4c, 0x1b, 0x49, 0x0c, 0x05, 0xeb, 0x51, 0xae, 0x64, 0x5a, 0x0a, 0x5b, + 0x47, 0x63, 0x35, 0x56, 0x76, 0x48, 0xcd, 0xc8, 0xcd, 0x5a, 0x22, 0x57, 0x39, 0x50, 0x7e, 0xc1, + 0xd2, 0x14, 0xa6, 0x86, 0xe6, 0x86, 0x65, 0x0a, 0xfe, 0x5d, 0x45, 0xb5, 0x01, 0x80, 0xbf, 0x40, + 0x07, 0x39, 0xf0, 0xf9, 0x70, 0x04, 0xd0, 0xf4, 0x4e, 0x6a, 0x9d, 0x46, 0xff, 0x98, 0x94, 0x4c, + 0x62, 0x98, 0xc4, 0x31, 0xc9, 0x99, 0x92, 0x69, 0x78, 0x76, 0xb9, 0x6c, 0x57, 0xae, 0x97, 0xed, + 0x47, 0x0b, 0x96, 0x4c, 0xdf, 0xe0, 0x8d, 0x10, 0x7f, 0xfb, 0xd9, 0xee, 0x8c, 0x65, 0x71, 0x31, + 0x8b, 0x09, 0x57, 0x09, 0x75, 0x35, 0x97, 0x9f, 0xae, 0x16, 0x13, 0x5a, 0x2c, 0x32, 0xd0, 0x76, + 0x0f, 0x1d, 0xed, 0x1b, 0x99, 0x41, 0xcf, 0xd1, 0x3e, 0xe3, 0x13, 0x4b, 0xae, 0xde, 0x45, 0x0e, + 0x1d, 0xf9, 0xb0, 0x24, 0x3b, 0xdd, 0xfd, 0xc0, 0x7b, 0x8c, 0x4f, 0x0c, 0xf7, 0xb3, 0x87, 0x1a, + 0x85, 0x4c, 0x40, 0xcd, 0x0a, 0x0b, 0xaf, 0xdd, 0x05, 0x1f, 0x38, 0xb8, 0x5f, 0xc2, 0x77, 0xb4, + 0xf7, 0x2b, 0x00, 0x39, 0xe5, 0x00, 0x00, 0x7f, 0xf5, 0x50, 0xfd, 0x03, 0xe3, 0x13, 0x30, 0x91, + 0xff, 0x12, 0xd5, 0xca, 0x06, 0x78, 0x9d, 0x46, 0xff, 0x19, 0xb9, 0xc5, 0x0d, 0x64, 0x00, 0x10, + 0x3e, 0x30, 0xc5, 0x44, 0x26, 0xdd, 0x7f, 0x8b, 0x0e, 0x73, 0x18, 0xcd, 0x52, 0x31, 0x64, 0x42, + 0xe4, 0xa0, 0x75, 0xb3, 0x7a, 0xe2, 0x75, 0xea, 0xe1, 0xf1, 0xf5, 0xb2, 0xfd, 0x64, 0xd3, 0xa2, + 0xdd, 0x75, 0x1c, 0x3d, 0x2c, 0x27, 0xde, 0x95, 0xb1, 0xdf, 0x32, 0xdd, 0x9f, 0xb2, 0x05, 0xe4, + 0xda, 0x5e, 0x43, 0x3d, 0xda, 0xc6, 0x38, 0x41, 0x68, 0x5b, 0xa0, 0xf6, 0x87, 0xa8, 0x91, 0xd9, + 0xc8, 0x1c, 0x5b, 0x3b, 0xab, 0xe0, 0x5b, 0x2b, 0xdd, 0x2a, 0xc3, 0xd6, 0xcd, 0xcb, 0xdb, 0xd9, + 0x04, 0x47, 0x28, 0xdb, 0x02, 0xf0, 0x77, 0x0f, 0x1d, 0x9d, 0x0b, 0x48, 0x0b, 0x39, 0x92, 0x20, + 0x76, 0xc8, 0x1f, 0x51, 0xdd, 0x89, 0xa4, 0x70, 0x37, 0xf4, 0xdc, 0x72, 0x8d, 0xc1, 0xc9, 0xc6, + 0xd5, 0x5b, 0xe6, 0xb9, 0x08, 0x9b, 0x0e, 0xf9, 0xf8, 0x06, 0x52, 0x0a, 0x1c, 0x1d, 0x64, 0x2e, + 0xe7, 0xef, 0xf3, 0x54, 0xff, 0xf7, 0x79, 0xc2, 0xf7, 0x97, 0xab, 0xc0, 0xbb, 0x5a, 0x05, 0xde, + 0xaf, 0x55, 0xe0, 0x7d, 0x59, 0x07, 0x95, 0xab, 0x75, 0x50, 0xf9, 0xb1, 0x0e, 0x2a, 0x9f, 0x5e, + 0xfd, 0x6b, 0x18, 0x19, 0xf3, 0xee, 0x58, 0xd1, 0xf9, 0x29, 0x4d, 0x94, 0x98, 0x4d, 0x41, 0x9b, + 0xf7, 0x42, 0xd3, 0xfe, 0xeb, 0xae, 0x79, 0x2a, 0xac, 0x87, 0xe2, 0x3d, 0xfb, 0xe3, 0x9e, 0xfe, + 0x09, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x6c, 0xa2, 0x41, 0x4f, 0x04, 0x00, 0x00, +} + +func (m *Fee) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Fee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Fee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TimeoutFee) > 0 { + for iNdEx := len(m.TimeoutFee) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TimeoutFee[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintFee(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.AckFee) > 0 { + for iNdEx := len(m.AckFee) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AckFee[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintFee(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.RecvFee) > 0 { + for iNdEx := len(m.RecvFee) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RecvFee[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintFee(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *PacketFee) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PacketFee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PacketFee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Relayers) > 0 { + for iNdEx := len(m.Relayers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Relayers[iNdEx]) + copy(dAtA[i:], m.Relayers[iNdEx]) + i = encodeVarintFee(dAtA, i, uint64(len(m.Relayers[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.RefundAddress) > 0 { + i -= len(m.RefundAddress) + copy(dAtA[i:], m.RefundAddress) + i = encodeVarintFee(dAtA, i, uint64(len(m.RefundAddress))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintFee(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *PacketFees) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PacketFees) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PacketFees) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PacketFees) > 0 { + for iNdEx := len(m.PacketFees) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PacketFees[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintFee(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *IdentifiedPacketFees) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *IdentifiedPacketFees) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *IdentifiedPacketFees) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PacketFees) > 0 { + for iNdEx := len(m.PacketFees) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PacketFees[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintFee(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.PacketId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintFee(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintFee(dAtA []byte, offset int, v uint64) int { + offset -= sovFee(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Fee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RecvFee) > 0 { + for _, e := range m.RecvFee { + l = e.Size() + n += 1 + l + sovFee(uint64(l)) + } + } + if len(m.AckFee) > 0 { + for _, e := range m.AckFee { + l = e.Size() + n += 1 + l + sovFee(uint64(l)) + } + } + if len(m.TimeoutFee) > 0 { + for _, e := range m.TimeoutFee { + l = e.Size() + n += 1 + l + sovFee(uint64(l)) + } + } + return n +} + +func (m *PacketFee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Fee.Size() + n += 1 + l + sovFee(uint64(l)) + l = len(m.RefundAddress) + if l > 0 { + n += 1 + l + sovFee(uint64(l)) + } + if len(m.Relayers) > 0 { + for _, s := range m.Relayers { + l = len(s) + n += 1 + l + sovFee(uint64(l)) + } + } + return n +} + +func (m *PacketFees) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.PacketFees) > 0 { + for _, e := range m.PacketFees { + l = e.Size() + n += 1 + l + sovFee(uint64(l)) + } + } + return n +} + +func (m *IdentifiedPacketFees) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.PacketId.Size() + n += 1 + l + sovFee(uint64(l)) + if len(m.PacketFees) > 0 { + for _, e := range m.PacketFees { + l = e.Size() + n += 1 + l + sovFee(uint64(l)) + } + } + return n +} + +func sovFee(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozFee(x uint64) (n int) { + return sovFee(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Fee) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Fee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Fee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RecvFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthFee + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthFee + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RecvFee = append(m.RecvFee, types.Coin{}) + if err := m.RecvFee[len(m.RecvFee)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AckFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthFee + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthFee + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AckFee = append(m.AckFee, types.Coin{}) + if err := m.AckFee[len(m.AckFee)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeoutFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthFee + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthFee + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TimeoutFee = append(m.TimeoutFee, types.Coin{}) + if err := m.TimeoutFee[len(m.TimeoutFee)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipFee(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFee + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PacketFee) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PacketFee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PacketFee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthFee + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthFee + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RefundAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthFee + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFee + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RefundAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Relayers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthFee + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFee + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Relayers = append(m.Relayers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipFee(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFee + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PacketFees) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PacketFees: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PacketFees: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketFees", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthFee + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthFee + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PacketFees = append(m.PacketFees, PacketFee{}) + if err := m.PacketFees[len(m.PacketFees)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipFee(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFee + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *IdentifiedPacketFees) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: IdentifiedPacketFees: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: IdentifiedPacketFees: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthFee + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthFee + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PacketId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketFees", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFee + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthFee + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthFee + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PacketFees = append(m.PacketFees, PacketFee{}) + if err := m.PacketFees[len(m.PacketFees)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipFee(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFee + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipFee(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowFee + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowFee + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowFee + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthFee + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupFee + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthFee + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthFee = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowFee = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupFee = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/29-fee/types/fee_test.go b/modules/apps/29-fee/types/fee_test.go new file mode 100644 index 00000000000..2b02e5b857b --- /dev/null +++ b/modules/apps/29-fee/types/fee_test.go @@ -0,0 +1,123 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/secp256k1" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" +) + +var ( + // defaultRecvFee is the default packet receive fee used for testing purposes + defaultRecvFee = sdk.NewCoins(sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}) + + // defaultAckFee is the default packet acknowledgement fee used for testing purposes + defaultAckFee = sdk.NewCoins(sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}) + + // defaultTimeoutFee is the default packet timeout fee used for testing purposes + defaultTimeoutFee = sdk.NewCoins(sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(300)}) + + // invalidFee is an invalid coin set used to trigger error cases for testing purposes + invalidFee = sdk.Coins{sdk.Coin{Denom: "invalid-denom", Amount: sdk.NewInt(-2)}} + + // defaultAccAddress is the default account used for testing purposes + defaultAccAddress = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() +) + +func TestFeeTotal(t *testing.T) { + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + + total := fee.Total() + require.Equal(t, sdk.NewInt(600), total.AmountOf(sdk.DefaultBondDenom)) +} + +func TestPacketFeeValidation(t *testing.T) { + var ( + packetFee types.PacketFee + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "should fail when refund address is invalid", + func() { + packetFee.RefundAddress = "invalid-address" + }, + false, + }, + { + "should fail when all fees are invalid", + func() { + packetFee.Fee.AckFee = invalidFee + packetFee.Fee.RecvFee = invalidFee + packetFee.Fee.TimeoutFee = invalidFee + }, + false, + }, + { + "should fail with single invalid fee", + func() { + packetFee.Fee.AckFee = invalidFee + }, + false, + }, + { + "should fail with two invalid fees", + func() { + packetFee.Fee.TimeoutFee = invalidFee + packetFee.Fee.AckFee = invalidFee + }, + false, + }, + { + "should pass with two empty fees", + func() { + packetFee.Fee.TimeoutFee = sdk.Coins{} + packetFee.Fee.AckFee = sdk.Coins{} + }, + true, + }, + { + "should pass with one empty fee", + func() { + packetFee.Fee.TimeoutFee = sdk.Coins{} + }, + true, + }, + { + "should fail if all fees are empty", + func() { + packetFee.Fee.AckFee = sdk.Coins{} + packetFee.Fee.RecvFee = sdk.Coins{} + packetFee.Fee.TimeoutFee = sdk.Coins{} + }, + false, + }, + } + + for _, tc := range testCases { + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + packetFee = types.NewPacketFee(fee, defaultAccAddress, nil) + + tc.malleate() // malleate mutates test data + + err := packetFee.Validate() + + if tc.expPass { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } +} diff --git a/modules/apps/29-fee/types/genesis.go b/modules/apps/29-fee/types/genesis.go new file mode 100644 index 00000000000..be9299fcd94 --- /dev/null +++ b/modules/apps/29-fee/types/genesis.go @@ -0,0 +1,81 @@ +package types + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" +) + +// NewGenesisState creates a 29-fee GenesisState instance. +func NewGenesisState(identifiedFees []IdentifiedPacketFees, feeEnabledChannels []FeeEnabledChannel, registeredRelayers []RegisteredRelayerAddress, forwardRelayers []ForwardRelayerAddress) *GenesisState { + return &GenesisState{ + IdentifiedFees: identifiedFees, + FeeEnabledChannels: feeEnabledChannels, + RegisteredRelayers: registeredRelayers, + ForwardRelayers: forwardRelayers, + } +} + +// DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. +func DefaultGenesisState() *GenesisState { + return &GenesisState{ + IdentifiedFees: []IdentifiedPacketFees{}, + ForwardRelayers: []ForwardRelayerAddress{}, + FeeEnabledChannels: []FeeEnabledChannel{}, + RegisteredRelayers: []RegisteredRelayerAddress{}, + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + // Validate IdentifiedPacketFees + for _, identifiedFees := range gs.IdentifiedFees { + if err := identifiedFees.PacketId.Validate(); err != nil { + return err + } + + for _, packetFee := range identifiedFees.PacketFees { + if err := packetFee.Validate(); err != nil { + return err + } + } + } + + // Validate FeeEnabledChannels + for _, feeCh := range gs.FeeEnabledChannels { + if err := host.PortIdentifierValidator(feeCh.PortId); err != nil { + return sdkerrors.Wrap(err, "invalid source port ID") + } + if err := host.ChannelIdentifierValidator(feeCh.ChannelId); err != nil { + return sdkerrors.Wrap(err, "invalid source channel ID") + } + } + + // Validate RegisteredRelayers + for _, rel := range gs.RegisteredRelayers { + if _, err := sdk.AccAddressFromBech32(rel.Address); err != nil { + return sdkerrors.Wrap(err, "failed to convert source relayer address into sdk.AccAddress") + } + + if strings.TrimSpace(rel.CounterpartyAddress) == "" { + return ErrCounterpartyAddressEmpty + } + } + + // Validate ForwardRelayers + for _, rel := range gs.ForwardRelayers { + if _, err := sdk.AccAddressFromBech32(rel.Address); err != nil { + return sdkerrors.Wrap(err, "failed to convert forward relayer address into sdk.AccAddress") + } + + if err := rel.PacketId.Validate(); err != nil { + return err + } + } + + return nil +} diff --git a/modules/apps/29-fee/types/genesis.pb.go b/modules/apps/29-fee/types/genesis.pb.go new file mode 100644 index 00000000000..af78add463e --- /dev/null +++ b/modules/apps/29-fee/types/genesis.pb.go @@ -0,0 +1,1273 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/fee/v1/genesis.proto + +package types + +import ( + fmt "fmt" + types "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the ICS29 fee middleware genesis state +type GenesisState struct { + // list of identified packet fees + IdentifiedFees []IdentifiedPacketFees `protobuf:"bytes,1,rep,name=identified_fees,json=identifiedFees,proto3" json:"identified_fees" yaml:"identified_fees"` + // list of fee enabled channels + FeeEnabledChannels []FeeEnabledChannel `protobuf:"bytes,2,rep,name=fee_enabled_channels,json=feeEnabledChannels,proto3" json:"fee_enabled_channels" yaml:"fee_enabled_channels"` + // list of registered relayer addresses + RegisteredRelayers []RegisteredRelayerAddress `protobuf:"bytes,3,rep,name=registered_relayers,json=registeredRelayers,proto3" json:"registered_relayers" yaml:"registered_relayers"` + // list of forward relayer addresses + ForwardRelayers []ForwardRelayerAddress `protobuf:"bytes,4,rep,name=forward_relayers,json=forwardRelayers,proto3" json:"forward_relayers" yaml:"forward_relayers"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_7191992e856dff95, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetIdentifiedFees() []IdentifiedPacketFees { + if m != nil { + return m.IdentifiedFees + } + return nil +} + +func (m *GenesisState) GetFeeEnabledChannels() []FeeEnabledChannel { + if m != nil { + return m.FeeEnabledChannels + } + return nil +} + +func (m *GenesisState) GetRegisteredRelayers() []RegisteredRelayerAddress { + if m != nil { + return m.RegisteredRelayers + } + return nil +} + +func (m *GenesisState) GetForwardRelayers() []ForwardRelayerAddress { + if m != nil { + return m.ForwardRelayers + } + return nil +} + +// FeeEnabledChannel contains the PortID & ChannelID for a fee enabled channel +type FeeEnabledChannel struct { + // unique port identifier + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + // unique channel identifier + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` +} + +func (m *FeeEnabledChannel) Reset() { *m = FeeEnabledChannel{} } +func (m *FeeEnabledChannel) String() string { return proto.CompactTextString(m) } +func (*FeeEnabledChannel) ProtoMessage() {} +func (*FeeEnabledChannel) Descriptor() ([]byte, []int) { + return fileDescriptor_7191992e856dff95, []int{1} +} +func (m *FeeEnabledChannel) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FeeEnabledChannel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FeeEnabledChannel.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *FeeEnabledChannel) XXX_Merge(src proto.Message) { + xxx_messageInfo_FeeEnabledChannel.Merge(m, src) +} +func (m *FeeEnabledChannel) XXX_Size() int { + return m.Size() +} +func (m *FeeEnabledChannel) XXX_DiscardUnknown() { + xxx_messageInfo_FeeEnabledChannel.DiscardUnknown(m) +} + +var xxx_messageInfo_FeeEnabledChannel proto.InternalMessageInfo + +func (m *FeeEnabledChannel) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func (m *FeeEnabledChannel) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +// RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) +type RegisteredRelayerAddress struct { + // the relayer address + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // the counterparty relayer address + CounterpartyAddress string `protobuf:"bytes,2,opt,name=counterparty_address,json=counterpartyAddress,proto3" json:"counterparty_address,omitempty" yaml:"counterparty_address"` + // unique channel identifier + ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` +} + +func (m *RegisteredRelayerAddress) Reset() { *m = RegisteredRelayerAddress{} } +func (m *RegisteredRelayerAddress) String() string { return proto.CompactTextString(m) } +func (*RegisteredRelayerAddress) ProtoMessage() {} +func (*RegisteredRelayerAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_7191992e856dff95, []int{2} +} +func (m *RegisteredRelayerAddress) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RegisteredRelayerAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RegisteredRelayerAddress.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RegisteredRelayerAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_RegisteredRelayerAddress.Merge(m, src) +} +func (m *RegisteredRelayerAddress) XXX_Size() int { + return m.Size() +} +func (m *RegisteredRelayerAddress) XXX_DiscardUnknown() { + xxx_messageInfo_RegisteredRelayerAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_RegisteredRelayerAddress proto.InternalMessageInfo + +func (m *RegisteredRelayerAddress) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *RegisteredRelayerAddress) GetCounterpartyAddress() string { + if m != nil { + return m.CounterpartyAddress + } + return "" +} + +func (m *RegisteredRelayerAddress) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +// ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements +type ForwardRelayerAddress struct { + // the forward relayer address + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // unique packet identifer comprised of the channel ID, port ID and sequence + PacketId types.PacketId `protobuf:"bytes,2,opt,name=packet_id,json=packetId,proto3" json:"packet_id" yaml:"packet_id"` +} + +func (m *ForwardRelayerAddress) Reset() { *m = ForwardRelayerAddress{} } +func (m *ForwardRelayerAddress) String() string { return proto.CompactTextString(m) } +func (*ForwardRelayerAddress) ProtoMessage() {} +func (*ForwardRelayerAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_7191992e856dff95, []int{3} +} +func (m *ForwardRelayerAddress) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ForwardRelayerAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ForwardRelayerAddress.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ForwardRelayerAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_ForwardRelayerAddress.Merge(m, src) +} +func (m *ForwardRelayerAddress) XXX_Size() int { + return m.Size() +} +func (m *ForwardRelayerAddress) XXX_DiscardUnknown() { + xxx_messageInfo_ForwardRelayerAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_ForwardRelayerAddress proto.InternalMessageInfo + +func (m *ForwardRelayerAddress) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *ForwardRelayerAddress) GetPacketId() types.PacketId { + if m != nil { + return m.PacketId + } + return types.PacketId{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "ibc.applications.fee.v1.GenesisState") + proto.RegisterType((*FeeEnabledChannel)(nil), "ibc.applications.fee.v1.FeeEnabledChannel") + proto.RegisterType((*RegisteredRelayerAddress)(nil), "ibc.applications.fee.v1.RegisteredRelayerAddress") + proto.RegisterType((*ForwardRelayerAddress)(nil), "ibc.applications.fee.v1.ForwardRelayerAddress") +} + +func init() { + proto.RegisterFile("ibc/applications/fee/v1/genesis.proto", fileDescriptor_7191992e856dff95) +} + +var fileDescriptor_7191992e856dff95 = []byte{ + // 579 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x4d, 0x6f, 0xd4, 0x30, + 0x14, 0xdc, 0xb4, 0x55, 0x4b, 0x5d, 0xd4, 0x0f, 0xb7, 0xa5, 0x51, 0x11, 0x49, 0x31, 0x42, 0xaa, + 0x40, 0x4d, 0xb4, 0x2d, 0x1c, 0xe0, 0xc6, 0x22, 0x8a, 0xf6, 0x04, 0x32, 0x9c, 0xb8, 0x44, 0xf9, + 0x78, 0x49, 0x2d, 0xb2, 0x71, 0x64, 0xbb, 0x41, 0xcb, 0x8d, 0x0b, 0x1c, 0xe1, 0x17, 0x71, 0xee, + 0xb1, 0x47, 0x4e, 0x2b, 0xd4, 0xfe, 0x83, 0xfe, 0x02, 0x94, 0x38, 0xe9, 0x6e, 0x97, 0x0d, 0xe2, + 0xf6, 0x62, 0xcf, 0xbc, 0x19, 0x8f, 0xf3, 0x8c, 0x1e, 0xb2, 0x20, 0x74, 0xfd, 0x3c, 0x4f, 0x59, + 0xe8, 0x2b, 0xc6, 0x33, 0xe9, 0xc6, 0x00, 0x6e, 0xd1, 0x75, 0x13, 0xc8, 0x40, 0x32, 0xe9, 0xe4, + 0x82, 0x2b, 0x8e, 0x77, 0x58, 0x10, 0x3a, 0x93, 0x30, 0x27, 0x06, 0x70, 0x8a, 0xee, 0xee, 0x56, + 0xc2, 0x13, 0x5e, 0x61, 0xdc, 0xb2, 0xd2, 0xf0, 0xdd, 0xfb, 0x6d, 0x5d, 0x4b, 0xd6, 0x04, 0x24, + 0xe4, 0x02, 0xdc, 0xf0, 0xc4, 0xcf, 0x32, 0x48, 0xcb, 0xed, 0xba, 0xd4, 0x10, 0xf2, 0x7d, 0x01, + 0xdd, 0x7e, 0xad, 0x6d, 0xbc, 0x53, 0xbe, 0x02, 0x5c, 0xa0, 0x35, 0x16, 0x41, 0xa6, 0x58, 0xcc, + 0x20, 0xf2, 0x62, 0x00, 0x69, 0x1a, 0x7b, 0xf3, 0xfb, 0x2b, 0x87, 0x07, 0x4e, 0x8b, 0x3f, 0xa7, + 0x7f, 0x8d, 0x7f, 0xeb, 0x87, 0x1f, 0x41, 0x1d, 0x03, 0xc8, 0x9e, 0x75, 0x36, 0xb2, 0x3b, 0x57, + 0x23, 0xfb, 0xce, 0xd0, 0x1f, 0xa4, 0xcf, 0xc9, 0x54, 0x4f, 0x42, 0x57, 0xc7, 0x2b, 0x25, 0x1e, + 0x7f, 0x31, 0xd0, 0x56, 0x0c, 0xe0, 0x41, 0xe6, 0x07, 0x29, 0x44, 0x5e, 0x6d, 0x53, 0x9a, 0x73, + 0x95, 0xfa, 0xa3, 0x56, 0xf5, 0x63, 0x80, 0x57, 0x9a, 0xf3, 0x52, 0x53, 0x7a, 0x0f, 0x6a, 0xe9, + 0xbb, 0x5a, 0x7a, 0x56, 0x57, 0x42, 0x71, 0x3c, 0xcd, 0x93, 0xf8, 0xab, 0x81, 0x36, 0x05, 0x24, + 0x4c, 0x2a, 0x10, 0x10, 0x79, 0x02, 0x52, 0x7f, 0x08, 0x42, 0x9a, 0xf3, 0x95, 0x85, 0x6e, 0xab, + 0x05, 0x7a, 0xcd, 0xa1, 0x9a, 0xf2, 0x22, 0x8a, 0x04, 0x48, 0xd9, 0x23, 0xb5, 0x93, 0x5d, 0xed, + 0x64, 0x46, 0x6f, 0x42, 0xb1, 0x98, 0x66, 0x4b, 0xfc, 0x19, 0xad, 0xc7, 0x5c, 0x7c, 0xf2, 0xc5, + 0x84, 0x89, 0x85, 0xca, 0x84, 0xd3, 0x9e, 0x83, 0x26, 0x4c, 0x39, 0xb0, 0x6b, 0x07, 0x3b, 0x75, + 0x16, 0x53, 0x5d, 0x09, 0x5d, 0x8b, 0x6f, 0xf0, 0x24, 0x29, 0xd0, 0xc6, 0x5f, 0x91, 0xe2, 0xc7, + 0x68, 0x29, 0xe7, 0x42, 0x79, 0x2c, 0x32, 0x8d, 0x3d, 0x63, 0x7f, 0xb9, 0x87, 0xaf, 0x46, 0xf6, + 0xaa, 0xee, 0x59, 0x6f, 0x10, 0xba, 0x58, 0x56, 0xfd, 0x08, 0x3f, 0x41, 0xa8, 0xce, 0xb9, 0xc4, + 0xcf, 0x55, 0xf8, 0xed, 0xab, 0x91, 0xbd, 0xa1, 0xf1, 0xe3, 0x3d, 0x42, 0x97, 0xeb, 0x8f, 0x7e, + 0x44, 0x7e, 0x1a, 0xc8, 0x6c, 0x0b, 0x12, 0x9b, 0x68, 0xc9, 0xd7, 0xa5, 0xd6, 0xa7, 0xcd, 0x27, + 0xa6, 0x68, 0x2b, 0xe4, 0xa7, 0x99, 0x02, 0x91, 0xfb, 0x42, 0x0d, 0xbd, 0x06, 0xa6, 0x65, 0xed, + 0xf1, 0x6f, 0x30, 0x0b, 0x45, 0xe8, 0xe6, 0xe4, 0x72, 0xa3, 0x76, 0xf3, 0x00, 0xf3, 0xff, 0x79, + 0x80, 0x6f, 0x06, 0xda, 0x9e, 0x79, 0x09, 0xff, 0x70, 0xff, 0x1e, 0x2d, 0xe7, 0xd5, 0xcc, 0x34, + 0x49, 0xad, 0x1c, 0xde, 0xab, 0x6e, 0xb8, 0x9c, 0x5a, 0xa7, 0x19, 0xd5, 0xa2, 0xeb, 0xe8, 0xc9, + 0xea, 0x47, 0x3d, 0xb3, 0xbe, 0xd0, 0xf5, 0x3a, 0xfc, 0x86, 0x4d, 0xe8, 0xad, 0xbc, 0xc1, 0xbc, + 0x39, 0xbb, 0xb0, 0x8c, 0xf3, 0x0b, 0xcb, 0xf8, 0x7d, 0x61, 0x19, 0x3f, 0x2e, 0xad, 0xce, 0xf9, + 0xa5, 0xd5, 0xf9, 0x75, 0x69, 0x75, 0x3e, 0x3c, 0x4d, 0x98, 0x3a, 0x39, 0x0d, 0x9c, 0x90, 0x0f, + 0xdc, 0x90, 0xcb, 0x01, 0x97, 0x2e, 0x0b, 0xc2, 0x83, 0x84, 0xbb, 0xc5, 0x91, 0x3b, 0xe0, 0xd1, + 0x69, 0x0a, 0xb2, 0x7c, 0x54, 0xa4, 0x7b, 0xf8, 0xec, 0xa0, 0x7c, 0x4f, 0xd4, 0x30, 0x07, 0x19, + 0x2c, 0x56, 0x8f, 0xc5, 0xd1, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x33, 0x0f, 0x78, 0xca, + 0x04, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ForwardRelayers) > 0 { + for iNdEx := len(m.ForwardRelayers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ForwardRelayers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.RegisteredRelayers) > 0 { + for iNdEx := len(m.RegisteredRelayers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RegisteredRelayers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.FeeEnabledChannels) > 0 { + for iNdEx := len(m.FeeEnabledChannels) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FeeEnabledChannels[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.IdentifiedFees) > 0 { + for iNdEx := len(m.IdentifiedFees) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IdentifiedFees[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *FeeEnabledChannel) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FeeEnabledChannel) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FeeEnabledChannel) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RegisteredRelayerAddress) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RegisteredRelayerAddress) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RegisteredRelayerAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.CounterpartyAddress) > 0 { + i -= len(m.CounterpartyAddress) + copy(dAtA[i:], m.CounterpartyAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.CounterpartyAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ForwardRelayerAddress) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ForwardRelayerAddress) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ForwardRelayerAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.PacketId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.IdentifiedFees) > 0 { + for _, e := range m.IdentifiedFees { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.FeeEnabledChannels) > 0 { + for _, e := range m.FeeEnabledChannels { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.RegisteredRelayers) > 0 { + for _, e := range m.RegisteredRelayers { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ForwardRelayers) > 0 { + for _, e := range m.ForwardRelayers { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *FeeEnabledChannel) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *RegisteredRelayerAddress) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.CounterpartyAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *ForwardRelayerAddress) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.PacketId.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IdentifiedFees", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IdentifiedFees = append(m.IdentifiedFees, IdentifiedPacketFees{}) + if err := m.IdentifiedFees[len(m.IdentifiedFees)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeeEnabledChannels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FeeEnabledChannels = append(m.FeeEnabledChannels, FeeEnabledChannel{}) + if err := m.FeeEnabledChannels[len(m.FeeEnabledChannels)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RegisteredRelayers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RegisteredRelayers = append(m.RegisteredRelayers, RegisteredRelayerAddress{}) + if err := m.RegisteredRelayers[len(m.RegisteredRelayers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ForwardRelayers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ForwardRelayers = append(m.ForwardRelayers, ForwardRelayerAddress{}) + if err := m.ForwardRelayers[len(m.ForwardRelayers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *FeeEnabledChannel) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FeeEnabledChannel: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FeeEnabledChannel: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RegisteredRelayerAddress) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RegisteredRelayerAddress: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RegisteredRelayerAddress: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CounterpartyAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ForwardRelayerAddress) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ForwardRelayerAddress: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ForwardRelayerAddress: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PacketId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/29-fee/types/genesis_test.go b/modules/apps/29-fee/types/genesis_test.go new file mode 100644 index 00000000000..edcd91c6f9d --- /dev/null +++ b/modules/apps/29-fee/types/genesis_test.go @@ -0,0 +1,215 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/secp256k1" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +var ( + addr1 = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + addr2 = sdk.AccAddress("testaddr2").String() + validCoins = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}} + validCoins2 = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}} + validCoins3 = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(300)}} +) + +func TestValidateGenesis(t *testing.T) { + var ( + packetID channeltypes.PacketId + fee types.Fee + refundAcc string + sender string + forwardAddr string + counterparty string + portID string + channelID string + packetChannelID string + seq uint64 + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "valid genesis", + func() {}, + true, + }, + { + "invalid packetID: invalid channel", + func() { + packetID = channeltypes.NewPacketId( + "", + portID, + seq, + ) + }, + false, + }, + { + "invalid packetID: invalid port", + func() { + packetID = channeltypes.NewPacketId( + channelID, + "", + seq, + ) + }, + false, + }, + { + "invalid packetID: invalid sequence", + func() { + packetID = channeltypes.NewPacketId( + channelID, + portID, + 0, + ) + }, + false, + }, + { + "invalid packetID: invalid fee", + func() { + fee = types.Fee{ + sdk.Coins{}, + sdk.Coins{}, + sdk.Coins{}, + } + }, + false, + }, + { + "invalid packetID: invalid refundAcc", + func() { + refundAcc = "" + }, + false, + }, + { + "invalid FeeEnabledChannel: invalid ChannelID", + func() { + channelID = "" + }, + false, + }, + { + "invalid FeeEnabledChannel: invalid PortID", + func() { + portID = "" + }, + false, + }, + { + "invalid RegisteredRelayers: invalid sender", + func() { + sender = "" + }, + false, + }, + { + "invalid RegisteredRelayers: invalid counterparty", + func() { + counterparty = " " + }, + false, + }, + { + "invalid ForwardRelayerAddress: invalid forwardAddr", + func() { + forwardAddr = "" + }, + false, + }, + { + "invalid ForwardRelayerAddress: invalid packet", + func() { + packetChannelID = "1" + }, + false, + }, + } + + for _, tc := range testCases { + portID = transfertypes.PortID + channelID = ibctesting.FirstChannelID + packetChannelID = ibctesting.FirstChannelID + seq = uint64(1) + + // build PacketId & Fee + packetID = channeltypes.NewPacketId( + portID, + channelID, + seq, + ) + fee = types.Fee{ + validCoins, + validCoins2, + validCoins3, + } + + refundAcc = addr1 + + // relayer addresses + sender = addr1 + counterparty = addr2 + forwardAddr = addr2 + + tc.malleate() + + genState := types.GenesisState{ + IdentifiedFees: []types.IdentifiedPacketFees{ + { + PacketId: packetID, + PacketFees: []types.PacketFee{ + { + Fee: fee, + RefundAddress: refundAcc, + Relayers: nil, + }, + }, + }, + }, + FeeEnabledChannels: []types.FeeEnabledChannel{ + { + PortId: portID, + ChannelId: channelID, + }, + }, + RegisteredRelayers: []types.RegisteredRelayerAddress{ + { + Address: sender, + CounterpartyAddress: counterparty, + }, + }, + ForwardRelayers: []types.ForwardRelayerAddress{ + { + Address: forwardAddr, + PacketId: channeltypes.NewPacketId(packetChannelID, portID, 1), + }, + }, + } + + err := genState.Validate() + if tc.expPass { + require.NoError(t, err, tc.name) + } else { + require.Error(t, err, tc.name) + } + } +} + +func TestValidateDefaultGenesis(t *testing.T) { + err := types.DefaultGenesisState().Validate() + require.NoError(t, err) +} diff --git a/modules/apps/29-fee/types/keys.go b/modules/apps/29-fee/types/keys.go new file mode 100644 index 00000000000..f2dd3458e20 --- /dev/null +++ b/modules/apps/29-fee/types/keys.go @@ -0,0 +1,133 @@ +package types + +import ( + "fmt" + "strconv" + "strings" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" +) + +const ( + // ModuleName defines the 29-fee name + ModuleName = "feeibc" + + // StoreKey is the store key string for IBC fee module + StoreKey = ModuleName + + // RouterKey is the message route for IBC fee module + RouterKey = ModuleName + + // QuerierRoute is the querier route for IBC fee module + QuerierRoute = ModuleName + + Version = "fee29-1" + + // FeeEnabledPrefix is the key prefix for storing fee enabled flag + FeeEnabledKeyPrefix = "feeEnabled" + + // CounterpartyRelayerAddressKeyPrefix is the key prefix for relayer address mapping + CounterpartyRelayerAddressKeyPrefix = "relayerAddress" + + // FeesInEscrowPrefix is the key prefix for fee in escrow mapping + FeesInEscrowPrefix = "feesInEscrow" + + // ForwardRelayerPrefix is the key prefix for forward relayer addresses stored in state for async acknowledgements + ForwardRelayerPrefix = "forwardRelayer" +) + +// KeyFeeEnabled returns the key that stores a flag to determine if fee logic should +// be enabled for the given port and channel identifiers. +func KeyFeeEnabled(portID, channelID string) []byte { + return []byte(fmt.Sprintf("%s/%s/%s", FeeEnabledKeyPrefix, portID, channelID)) +} + +// ParseKeyFeeEnabled parses the key used to indicate if the fee logic should be +// enabled for the given port and channel identifiers. +func ParseKeyFeeEnabled(key string) (portID, channelID string, err error) { + keySplit := strings.Split(key, "/") + if len(keySplit) != 3 { + return "", "", sdkerrors.Wrapf( + sdkerrors.ErrLogic, "key provided is incorrect: the key split has incorrect length, expected %d, got %d", 3, len(keySplit), + ) + } + + if keySplit[0] != FeeEnabledKeyPrefix { + return "", "", sdkerrors.Wrapf(sdkerrors.ErrLogic, "key prefix is incorrect: expected %s, got %s", FeeEnabledKeyPrefix, keySplit[0]) + } + + portID = keySplit[1] + channelID = keySplit[2] + + return portID, channelID, nil +} + +// KeyCounterpartyRelayer returns the key for relayer address -> counterparty address mapping +func KeyCounterpartyRelayer(address, channelID string) []byte { + return []byte(fmt.Sprintf("%s/%s/%s", CounterpartyRelayerAddressKeyPrefix, address, channelID)) +} + +// ParseKeyCounterpartyRelayer returns the registered relayer address and channelID used to store the counterpartyrelayer address +func ParseKeyCounterpartyRelayer(key string) (address string, channelID string, error error) { + keySplit := strings.Split(key, "/") + if len(keySplit) != 3 { + return "", "", sdkerrors.Wrapf( + sdkerrors.ErrLogic, "key provided is incorrect: the key split has incorrect length, expected %d, got %d", 3, len(keySplit), + ) + } + + return keySplit[1], keySplit[2], nil +} + +// KeyForwardRelayerAddress returns the key for packetID -> forwardAddress mapping +func KeyForwardRelayerAddress(packetID channeltypes.PacketId) []byte { + return []byte(fmt.Sprintf("%s/%s/%s/%d", ForwardRelayerPrefix, packetID.PortId, packetID.ChannelId, packetID.Sequence)) +} + +// ParseKeyForwardRelayerAddress parses the key used to store the forward relayer address and returns the packetID +func ParseKeyForwardRelayerAddress(key string) (channeltypes.PacketId, error) { + keySplit := strings.Split(key, "/") + if len(keySplit) != 4 { + return channeltypes.PacketId{}, sdkerrors.Wrapf( + sdkerrors.ErrLogic, "key provided is incorrect: the key split has incorrect length, expected %d, got %d", 4, len(keySplit), + ) + } + + seq, err := strconv.ParseUint(keySplit[3], 10, 64) + if err != nil { + return channeltypes.PacketId{}, err + } + + packetID := channeltypes.NewPacketId(keySplit[2], keySplit[1], seq) + return packetID, nil +} + +// KeyFeesInEscrow returns the key for escrowed fees +func KeyFeesInEscrow(packetID channeltypes.PacketId) []byte { + return []byte(fmt.Sprintf("%s/%d", KeyFeesInEscrowChannelPrefix(packetID.PortId, packetID.ChannelId), packetID.Sequence)) +} + +// ParseKeyFeesInEscrow parses the key used to store fees in escrow and returns the packet id +func ParseKeyFeesInEscrow(key string) (channeltypes.PacketId, error) { + keySplit := strings.Split(key, "/") + if len(keySplit) != 4 { + return channeltypes.PacketId{}, sdkerrors.Wrapf( + sdkerrors.ErrLogic, "key provided is incorrect: the key split has incorrect length, expected %d, got %d", 4, len(keySplit), + ) + } + + seq, err := strconv.ParseUint(keySplit[3], 10, 64) + if err != nil { + return channeltypes.PacketId{}, err + } + + packetID := channeltypes.NewPacketId(keySplit[2], keySplit[1], seq) + return packetID, nil +} + +// KeyFeesInEscrowChannelPrefix returns the key prefix for escrowed fees on the given channel +func KeyFeesInEscrowChannelPrefix(portID, channelID string) []byte { + return []byte(fmt.Sprintf("%s/%s/%s", FeesInEscrowPrefix, portID, channelID)) +} diff --git a/modules/apps/29-fee/types/keys_test.go b/modules/apps/29-fee/types/keys_test.go new file mode 100644 index 00000000000..518b2d65604 --- /dev/null +++ b/modules/apps/29-fee/types/keys_test.go @@ -0,0 +1,176 @@ +package types_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +var ( + validPacketID = channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) +) + +func TestKeyCounterpartyRelayer(t *testing.T) { + var ( + relayerAddress = "relayer_address" + channelID = "channel-0" + ) + + key := types.KeyCounterpartyRelayer(relayerAddress, channelID) + require.Equal(t, string(key), fmt.Sprintf("%s/%s/%s", types.CounterpartyRelayerAddressKeyPrefix, relayerAddress, channelID)) +} + +func TestKeyFeesInEscrow(t *testing.T) { + key := types.KeyFeesInEscrow(validPacketID) + require.Equal(t, string(key), fmt.Sprintf("%s/%s/%s/%d", types.FeesInEscrowPrefix, ibctesting.MockFeePort, ibctesting.FirstChannelID, 1)) +} + +func TestParseKeyFeeEnabled(t *testing.T) { + testCases := []struct { + name string + key string + expPass bool + }{ + { + "success", + string(types.KeyFeeEnabled(ibctesting.MockPort, ibctesting.FirstChannelID)), + true, + }, + { + "incorrect key - key split has incorrect length", + string(types.KeyFeesInEscrow(validPacketID)), + false, + }, + { + "incorrect key - key split has incorrect length", + fmt.Sprintf("%s/%s/%s", "fee", ibctesting.MockPort, ibctesting.FirstChannelID), + false, + }, + } + + for _, tc := range testCases { + portID, channelID, err := types.ParseKeyFeeEnabled(tc.key) + + if tc.expPass { + require.NoError(t, err) + require.Equal(t, ibctesting.MockPort, portID) + require.Equal(t, ibctesting.FirstChannelID, channelID) + } else { + require.Error(t, err) + require.Empty(t, portID) + require.Empty(t, channelID) + } + } +} + +func TestParseKeyFeesInEscrow(t *testing.T) { + + testCases := []struct { + name string + key string + expPass bool + }{ + { + "success", + string(types.KeyFeesInEscrow(validPacketID)), + true, + }, + { + "incorrect key - key split has incorrect length", + string(types.KeyFeeEnabled(validPacketID.PortId, validPacketID.ChannelId)), + false, + }, + { + "incorrect key - sequence cannot be parsed", + fmt.Sprintf("%s/%s", types.KeyFeesInEscrowChannelPrefix(validPacketID.PortId, validPacketID.ChannelId), "sequence"), + false, + }, + } + + for _, tc := range testCases { + packetID, err := types.ParseKeyFeesInEscrow(tc.key) + + if tc.expPass { + require.NoError(t, err) + require.Equal(t, validPacketID, packetID) + } else { + require.Error(t, err) + } + } +} + +func TestParseKeyForwardRelayerAddress(t *testing.T) { + + testCases := []struct { + name string + key string + expPass bool + }{ + { + "success", + string(types.KeyForwardRelayerAddress(validPacketID)), + true, + }, + { + "incorrect key - key split has incorrect length", + "forwardRelayer/transfer/channel-0", + false, + }, + { + "incorrect key - sequence is not correct", + "forwardRelayer/transfer/channel-0/sequence", + false, + }, + } + + for _, tc := range testCases { + packetID, err := types.ParseKeyForwardRelayerAddress(tc.key) + + if tc.expPass { + require.NoError(t, err) + require.Equal(t, validPacketID, packetID) + } else { + require.Error(t, err) + } + } +} + +func TestParseKeyCounterpartyRelayer(t *testing.T) { + var ( + relayerAddress = "relayer_address" + ) + + testCases := []struct { + name string + key string + expPass bool + }{ + { + "success", + string(types.KeyCounterpartyRelayer(relayerAddress, ibctesting.FirstChannelID)), + true, + }, + { + "incorrect key - key split has incorrect length", + "relayerAddress/relayer_address/transfer/channel-0", + false, + }, + } + + for _, tc := range testCases { + address, channelID, err := types.ParseKeyCounterpartyRelayer(tc.key) + + if tc.expPass { + require.NoError(t, err) + require.Equal(t, relayerAddress, address) + require.Equal(t, ibctesting.FirstChannelID, channelID) + } else { + require.Error(t, err) + } + } +} diff --git a/modules/apps/29-fee/types/metadata.pb.go b/modules/apps/29-fee/types/metadata.pb.go new file mode 100644 index 00000000000..95bb9244946 --- /dev/null +++ b/modules/apps/29-fee/types/metadata.pb.go @@ -0,0 +1,378 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/fee/v1/metadata.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Metadata defines the ICS29 channel specific metadata encoded into the channel version bytestring +// See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning +type Metadata struct { + // fee_version defines the ICS29 fee version + FeeVersion string `protobuf:"bytes,1,opt,name=fee_version,json=feeVersion,proto3" json:"fee_version,omitempty" yaml:"fee_version"` + // app_version defines the underlying application version, which may or may not be a JSON encoded bytestring + AppVersion string `protobuf:"bytes,2,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty" yaml:"app_version"` +} + +func (m *Metadata) Reset() { *m = Metadata{} } +func (m *Metadata) String() string { return proto.CompactTextString(m) } +func (*Metadata) ProtoMessage() {} +func (*Metadata) Descriptor() ([]byte, []int) { + return fileDescriptor_03d0f000eda681ce, []int{0} +} +func (m *Metadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Metadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Metadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Metadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_Metadata.Merge(m, src) +} +func (m *Metadata) XXX_Size() int { + return m.Size() +} +func (m *Metadata) XXX_DiscardUnknown() { + xxx_messageInfo_Metadata.DiscardUnknown(m) +} + +var xxx_messageInfo_Metadata proto.InternalMessageInfo + +func (m *Metadata) GetFeeVersion() string { + if m != nil { + return m.FeeVersion + } + return "" +} + +func (m *Metadata) GetAppVersion() string { + if m != nil { + return m.AppVersion + } + return "" +} + +func init() { + proto.RegisterType((*Metadata)(nil), "ibc.applications.fee.v1.Metadata") +} + +func init() { + proto.RegisterFile("ibc/applications/fee/v1/metadata.proto", fileDescriptor_03d0f000eda681ce) +} + +var fileDescriptor_03d0f000eda681ce = []byte{ + // 248 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xcb, 0x4c, 0x4a, 0xd6, + 0x4f, 0x2c, 0x28, 0xc8, 0xc9, 0x4c, 0x4e, 0x2c, 0xc9, 0xcc, 0xcf, 0x2b, 0xd6, 0x4f, 0x4b, 0x4d, + 0xd5, 0x2f, 0x33, 0xd4, 0xcf, 0x4d, 0x2d, 0x49, 0x4c, 0x49, 0x2c, 0x49, 0xd4, 0x2b, 0x28, 0xca, + 0x2f, 0xc9, 0x17, 0x12, 0xcf, 0x4c, 0x4a, 0xd6, 0x43, 0x56, 0xa7, 0x97, 0x96, 0x9a, 0xaa, 0x57, + 0x66, 0x28, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0x56, 0xa3, 0x0f, 0x62, 0x41, 0x94, 0x2b, 0xd5, + 0x70, 0x71, 0xf8, 0x42, 0x0d, 0x10, 0x32, 0xe7, 0xe2, 0x4e, 0x4b, 0x4d, 0x8d, 0x2f, 0x4b, 0x2d, + 0x2a, 0xce, 0xcc, 0xcf, 0x93, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x74, 0x12, 0xfb, 0x74, 0x4f, 0x5e, + 0xa8, 0x32, 0x31, 0x37, 0xc7, 0x4a, 0x09, 0x49, 0x52, 0x29, 0x88, 0x2b, 0x2d, 0x35, 0x35, 0x0c, + 0xc2, 0x01, 0x69, 0x4c, 0x2c, 0x28, 0x80, 0x6b, 0x64, 0x42, 0xd7, 0x88, 0x24, 0xa9, 0x14, 0xc4, + 0x95, 0x58, 0x50, 0x00, 0xd5, 0xe8, 0xe4, 0x7f, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, + 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, + 0x0c, 0x51, 0xa6, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xc9, 0xf9, + 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x99, 0x49, 0xc9, 0xba, 0xe9, 0xf9, 0xfa, 0x65, 0xc6, 0xfa, 0xb9, + 0xf9, 0x29, 0xa5, 0x39, 0xa9, 0xc5, 0xa0, 0xe0, 0x28, 0xd6, 0x37, 0xb2, 0xd4, 0x05, 0x85, 0x44, + 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0xd8, 0x57, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x04, 0x84, 0x58, 0xe0, 0x2e, 0x01, 0x00, 0x00, +} + +func (m *Metadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Metadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Metadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AppVersion) > 0 { + i -= len(m.AppVersion) + copy(dAtA[i:], m.AppVersion) + i = encodeVarintMetadata(dAtA, i, uint64(len(m.AppVersion))) + i-- + dAtA[i] = 0x12 + } + if len(m.FeeVersion) > 0 { + i -= len(m.FeeVersion) + copy(dAtA[i:], m.FeeVersion) + i = encodeVarintMetadata(dAtA, i, uint64(len(m.FeeVersion))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintMetadata(dAtA []byte, offset int, v uint64) int { + offset -= sovMetadata(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Metadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FeeVersion) + if l > 0 { + n += 1 + l + sovMetadata(uint64(l)) + } + l = len(m.AppVersion) + if l > 0 { + n += 1 + l + sovMetadata(uint64(l)) + } + return n +} + +func sovMetadata(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozMetadata(x uint64) (n int) { + return sovMetadata(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Metadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetadata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Metadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Metadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeeVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetadata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetadata + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetadata + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FeeVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMetadata + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMetadata + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMetadata + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipMetadata(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMetadata + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipMetadata(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetadata + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetadata + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowMetadata + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthMetadata + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupMetadata + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthMetadata + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthMetadata = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowMetadata = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupMetadata = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/29-fee/types/msgs.go b/modules/apps/29-fee/types/msgs.go new file mode 100644 index 00000000000..d2fec3e542f --- /dev/null +++ b/modules/apps/29-fee/types/msgs.go @@ -0,0 +1,164 @@ +package types + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v3/modules/core/24-host" +) + +// msg types +const ( + TypeMsgPayPacketFee = "payPacketFee" + TypeMsgPayPacketFeeAsync = "payPacketFeeAsync" +) + +// NewMsgRegisterCounterpartyAddress creates a new instance of MsgRegisterCounterpartyAddress +func NewMsgRegisterCounterpartyAddress(address, counterpartyAddress, channelID string) *MsgRegisterCounterpartyAddress { + return &MsgRegisterCounterpartyAddress{ + Address: address, + CounterpartyAddress: counterpartyAddress, + ChannelId: channelID, + } +} + +// ValidateBasic performs a basic check of the MsgRegisterCounterpartyAddress fields +func (msg MsgRegisterCounterpartyAddress) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Address) + if err != nil { + return sdkerrors.Wrap(err, "failed to convert msg.Address into sdk.AccAddress") + } + + if strings.TrimSpace(msg.CounterpartyAddress) == "" { + return ErrCounterpartyAddressEmpty + } + + // validate channelId + if err := host.ChannelIdentifierValidator(msg.ChannelId); err != nil { + return err + } + + return nil +} + +// GetSigners implements sdk.Msg +func (msg MsgRegisterCounterpartyAddress) GetSigners() []sdk.AccAddress { + signer, err := sdk.AccAddressFromBech32(msg.Address) + if err != nil { + panic(err) + } + return []sdk.AccAddress{signer} +} + +// NewMsgPayPacketFee creates a new instance of MsgPayPacketFee +func NewMsgPayPacketFee(fee Fee, sourcePortId, sourceChannelId, signer string, relayers []string) *MsgPayPacketFee { + return &MsgPayPacketFee{ + Fee: fee, + SourcePortId: sourcePortId, + SourceChannelId: sourceChannelId, + Signer: signer, + Relayers: relayers, + } +} + +// ValidateBasic performs a basic check of the MsgPayPacketFee fields +func (msg MsgPayPacketFee) ValidateBasic() error { + // validate channelId + if err := host.ChannelIdentifierValidator(msg.SourceChannelId); err != nil { + return err + } + + // validate portId + if err := host.PortIdentifierValidator(msg.SourcePortId); err != nil { + return err + } + + // signer check + if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil { + return sdkerrors.Wrap(err, "failed to convert msg.Signer into sdk.AccAddress") + } + + // enforce relayer is nil + if msg.Relayers != nil { + return ErrRelayersNotNil + } + + if err := msg.Fee.Validate(); err != nil { + return err + } + + return nil +} + +// GetSigners implements sdk.Msg +func (msg MsgPayPacketFee) GetSigners() []sdk.AccAddress { + signer, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + panic(err) + } + return []sdk.AccAddress{signer} +} + +// Route implements sdk.Msg +func (msg MsgPayPacketFee) Route() string { + return RouterKey +} + +// Type implements sdk.Msg +func (msg MsgPayPacketFee) Type() string { + return TypeMsgPayPacketFee +} + +// GetSignBytes implements sdk.Msg. +func (msg MsgPayPacketFee) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) +} + +// NewMsgPayPacketAsync creates a new instance of MsgPayPacketFee +func NewMsgPayPacketFeeAsync(packetID channeltypes.PacketId, packetFee PacketFee) *MsgPayPacketFeeAsync { + return &MsgPayPacketFeeAsync{ + PacketId: packetID, + PacketFee: packetFee, + } +} + +// ValidateBasic performs a basic check of the MsgPayPacketFeeAsync fields +func (msg MsgPayPacketFeeAsync) ValidateBasic() error { + if err := msg.PacketId.Validate(); err != nil { + return err + } + + if err := msg.PacketFee.Validate(); err != nil { + return err + } + + return nil +} + +// GetSigners implements sdk.Msg +// The signer of the fee message must be the refund address +func (msg MsgPayPacketFeeAsync) GetSigners() []sdk.AccAddress { + signer, err := sdk.AccAddressFromBech32(msg.PacketFee.RefundAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{signer} +} + +// Route implements sdk.Msg +func (msg MsgPayPacketFeeAsync) Route() string { + return RouterKey +} + +// Type implements sdk.Msg +func (msg MsgPayPacketFeeAsync) Type() string { + return TypeMsgPayPacketFeeAsync +} + +// GetSignBytes implements sdk.Msg. +func (msg MsgPayPacketFeeAsync) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) +} diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go new file mode 100644 index 00000000000..8a7ec915a31 --- /dev/null +++ b/modules/apps/29-fee/types/msgs_test.go @@ -0,0 +1,319 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/secp256k1" +) + +func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { + var ( + msg *types.MsgRegisterCounterpartyAddress + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "validate with incorrect destination relayer address", + func() { + msg.Address = "invalid-address" + }, + false, + }, + { + "invalid counterparty address", + func() { + msg.CounterpartyAddress = "" + }, + false, + }, + { + "invalid counterparty address: whitespaced empty string", + func() { + msg.CounterpartyAddress = " " + }, + false, + }, + { + "invalid channelID", + func() { + msg.ChannelId = "" + }, + false, + }, + } + + for i, tc := range testCases { + msg = types.NewMsgRegisterCounterpartyAddress(defaultAccAddress, defaultAccAddress, ibctesting.FirstChannelID) + + tc.malleate() + + err := msg.ValidateBasic() + + if tc.expPass { + require.NoError(t, err, "valid test case %d failed: %s", i, tc.name) + } else { + require.Error(t, err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func TestRegisterCountepartyAddressGetSigners(t *testing.T) { + accAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + msg := types.NewMsgRegisterCounterpartyAddress(accAddress.String(), defaultAccAddress, ibctesting.FirstChannelID) + require.Equal(t, []sdk.AccAddress{sdk.AccAddress(accAddress)}, msg.GetSigners()) +} + +func TestMsgPayPacketFeeValidation(t *testing.T) { + var ( + msg *types.MsgPayPacketFee + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "invalid channelID", + func() { + msg.SourceChannelId = "" + }, + false, + }, + { + "invalid portID", + func() { + msg.SourcePortId = "" + }, + false, + }, + { + "relayers is not nil", + func() { + msg.Relayers = []string{defaultAccAddress} + }, + false, + }, + { + "invalid signer address", + func() { + msg.Signer = "invalid-address" + }, + false, + }, + } + + for _, tc := range testCases { + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + msg = types.NewMsgPayPacketFee(fee, ibctesting.MockFeePort, ibctesting.FirstChannelID, defaultAccAddress, nil) + + tc.malleate() // malleate mutates test data + + err := msg.ValidateBasic() + + if tc.expPass { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } +} + +func TestPayPacketFeeGetSigners(t *testing.T) { + refundAddr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + msg := types.NewMsgPayPacketFee(fee, ibctesting.MockFeePort, ibctesting.FirstChannelID, refundAddr.String(), nil) + + require.Equal(t, []sdk.AccAddress{refundAddr}, msg.GetSigners()) +} + +func TestMsgPayPacketFeeRoute(t *testing.T) { + var msg types.MsgPayPacketFee + require.Equal(t, types.RouterKey, msg.Route()) +} + +func TestMsgPayPacketFeeType(t *testing.T) { + var msg types.MsgPayPacketFee + require.Equal(t, "payPacketFee", msg.Type()) +} + +func TestMsgPayPacketFeeGetSignBytes(t *testing.T) { + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + msg := types.NewMsgPayPacketFee(fee, ibctesting.MockFeePort, ibctesting.FirstChannelID, defaultAccAddress, nil) + + require.NotPanics(t, func() { + _ = msg.GetSignBytes() + }) +} + +func TestMsgPayPacketFeeAsyncValidation(t *testing.T) { + var ( + msg *types.MsgPayPacketFeeAsync + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "invalid channelID", + func() { + msg.PacketId.ChannelId = "" + }, + false, + }, + { + "invalid portID", + func() { + msg.PacketId.PortId = "" + }, + false, + }, + { + "invalid sequence", + func() { + msg.PacketId.Sequence = 0 + }, + false, + }, + { + "relayers is not nil", + func() { + msg.PacketFee.Relayers = []string{defaultAccAddress} + }, + false, + }, + { + "invalid signer address", + func() { + msg.PacketFee.RefundAddress = "invalid-addr" + }, + false, + }, + { + "should fail when all fees are invalid", + func() { + msg.PacketFee.Fee.AckFee = invalidFee + msg.PacketFee.Fee.RecvFee = invalidFee + msg.PacketFee.Fee.TimeoutFee = invalidFee + }, + false, + }, + { + "should fail with single invalid fee", + func() { + msg.PacketFee.Fee.AckFee = invalidFee + }, + false, + }, + { + "should fail with two invalid fees", + func() { + msg.PacketFee.Fee.AckFee = invalidFee + msg.PacketFee.Fee.TimeoutFee = invalidFee + }, + false, + }, + { + "should pass with two empty fees", + func() { + msg.PacketFee.Fee.AckFee = sdk.Coins{} + msg.PacketFee.Fee.TimeoutFee = sdk.Coins{} + }, + true, + }, + { + "should pass with one empty fee", + func() { + msg.PacketFee.Fee.TimeoutFee = sdk.Coins{} + }, + true, + }, + { + "should fail if all fees are empty", + func() { + msg.PacketFee.Fee.AckFee = sdk.Coins{} + msg.PacketFee.Fee.RecvFee = sdk.Coins{} + msg.PacketFee.Fee.TimeoutFee = sdk.Coins{} + }, + false, + }, + } + + for _, tc := range testCases { + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + packetFee := types.NewPacketFee(fee, defaultAccAddress, nil) + + msg = types.NewMsgPayPacketFeeAsync(packetID, packetFee) + + tc.malleate() // malleate mutates test data + + err := msg.ValidateBasic() + + if tc.expPass { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } +} + +func TestPayPacketFeeAsyncGetSigners(t *testing.T) { + refundAddr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + packetFee := types.NewPacketFee(fee, refundAddr.String(), nil) + + msg := types.NewMsgPayPacketFeeAsync(packetID, packetFee) + + require.Equal(t, []sdk.AccAddress{refundAddr}, msg.GetSigners()) +} + +func TestMsgPayPacketFeeAsyncRoute(t *testing.T) { + var msg types.MsgPayPacketFeeAsync + require.Equal(t, types.RouterKey, msg.Route()) +} + +func TestMsgPayPacketFeeAsyncType(t *testing.T) { + var msg types.MsgPayPacketFeeAsync + require.Equal(t, "payPacketFeeAsync", msg.Type()) +} + +func TestMsgPayPacketFeeAsyncGetSignBytes(t *testing.T) { + packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + packetFee := types.NewPacketFee(fee, defaultAccAddress, nil) + + msg := types.NewMsgPayPacketFeeAsync(packetID, packetFee) + + require.NotPanics(t, func() { + _ = msg.GetSignBytes() + }) +} diff --git a/modules/apps/29-fee/types/query.pb.go b/modules/apps/29-fee/types/query.pb.go new file mode 100644 index 00000000000..dd130bcc3fd --- /dev/null +++ b/modules/apps/29-fee/types/query.pb.go @@ -0,0 +1,2845 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/fee/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/cosmos-sdk/types" + query "github.com/cosmos/cosmos-sdk/types/query" + types "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryIncentivizedPacketsRequest defines the request type for the IncentivizedPackets rpc +type QueryIncentivizedPacketsRequest struct { + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` + // block height at which to query + QueryHeight uint64 `protobuf:"varint,2,opt,name=query_height,json=queryHeight,proto3" json:"query_height,omitempty"` +} + +func (m *QueryIncentivizedPacketsRequest) Reset() { *m = QueryIncentivizedPacketsRequest{} } +func (m *QueryIncentivizedPacketsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryIncentivizedPacketsRequest) ProtoMessage() {} +func (*QueryIncentivizedPacketsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{0} +} +func (m *QueryIncentivizedPacketsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIncentivizedPacketsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIncentivizedPacketsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryIncentivizedPacketsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIncentivizedPacketsRequest.Merge(m, src) +} +func (m *QueryIncentivizedPacketsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryIncentivizedPacketsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIncentivizedPacketsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIncentivizedPacketsRequest proto.InternalMessageInfo + +func (m *QueryIncentivizedPacketsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *QueryIncentivizedPacketsRequest) GetQueryHeight() uint64 { + if m != nil { + return m.QueryHeight + } + return 0 +} + +// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPackets rpc +type QueryIncentivizedPacketsResponse struct { + // list of identified fees for incentivized packets + IncentivizedPackets []IdentifiedPacketFees `protobuf:"bytes,1,rep,name=incentivized_packets,json=incentivizedPackets,proto3" json:"incentivized_packets"` +} + +func (m *QueryIncentivizedPacketsResponse) Reset() { *m = QueryIncentivizedPacketsResponse{} } +func (m *QueryIncentivizedPacketsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryIncentivizedPacketsResponse) ProtoMessage() {} +func (*QueryIncentivizedPacketsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{1} +} +func (m *QueryIncentivizedPacketsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIncentivizedPacketsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIncentivizedPacketsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryIncentivizedPacketsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIncentivizedPacketsResponse.Merge(m, src) +} +func (m *QueryIncentivizedPacketsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryIncentivizedPacketsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIncentivizedPacketsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIncentivizedPacketsResponse proto.InternalMessageInfo + +func (m *QueryIncentivizedPacketsResponse) GetIncentivizedPackets() []IdentifiedPacketFees { + if m != nil { + return m.IncentivizedPackets + } + return nil +} + +// QueryIncentivizedPacketRequest defines the request type for the IncentivizedPacket rpc +type QueryIncentivizedPacketRequest struct { + // unique packet identifier comprised of channel ID, port ID and sequence + PacketId types.PacketId `protobuf:"bytes,1,opt,name=packet_id,json=packetId,proto3" json:"packet_id"` + // block height at which to query + QueryHeight uint64 `protobuf:"varint,2,opt,name=query_height,json=queryHeight,proto3" json:"query_height,omitempty"` +} + +func (m *QueryIncentivizedPacketRequest) Reset() { *m = QueryIncentivizedPacketRequest{} } +func (m *QueryIncentivizedPacketRequest) String() string { return proto.CompactTextString(m) } +func (*QueryIncentivizedPacketRequest) ProtoMessage() {} +func (*QueryIncentivizedPacketRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{2} +} +func (m *QueryIncentivizedPacketRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIncentivizedPacketRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIncentivizedPacketRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryIncentivizedPacketRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIncentivizedPacketRequest.Merge(m, src) +} +func (m *QueryIncentivizedPacketRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryIncentivizedPacketRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIncentivizedPacketRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIncentivizedPacketRequest proto.InternalMessageInfo + +func (m *QueryIncentivizedPacketRequest) GetPacketId() types.PacketId { + if m != nil { + return m.PacketId + } + return types.PacketId{} +} + +func (m *QueryIncentivizedPacketRequest) GetQueryHeight() uint64 { + if m != nil { + return m.QueryHeight + } + return 0 +} + +// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPacket rpc +type QueryIncentivizedPacketResponse struct { + // the identified fees for the incentivized packet + IncentivizedPacket IdentifiedPacketFees `protobuf:"bytes,1,opt,name=incentivized_packet,json=incentivizedPacket,proto3" json:"incentivized_packet"` +} + +func (m *QueryIncentivizedPacketResponse) Reset() { *m = QueryIncentivizedPacketResponse{} } +func (m *QueryIncentivizedPacketResponse) String() string { return proto.CompactTextString(m) } +func (*QueryIncentivizedPacketResponse) ProtoMessage() {} +func (*QueryIncentivizedPacketResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{3} +} +func (m *QueryIncentivizedPacketResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIncentivizedPacketResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIncentivizedPacketResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryIncentivizedPacketResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIncentivizedPacketResponse.Merge(m, src) +} +func (m *QueryIncentivizedPacketResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryIncentivizedPacketResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIncentivizedPacketResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIncentivizedPacketResponse proto.InternalMessageInfo + +func (m *QueryIncentivizedPacketResponse) GetIncentivizedPacket() IdentifiedPacketFees { + if m != nil { + return m.IncentivizedPacket + } + return IdentifiedPacketFees{} +} + +// QueryIncentivizedPacketsForChannelRequest defines the request type for querying for all incentivized packets +// for a specific channel +type QueryIncentivizedPacketsForChannelRequest struct { + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` + PortId string `protobuf:"bytes,2,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + // Height to query at + QueryHeight uint64 `protobuf:"varint,4,opt,name=query_height,json=queryHeight,proto3" json:"query_height,omitempty"` +} + +func (m *QueryIncentivizedPacketsForChannelRequest) Reset() { + *m = QueryIncentivizedPacketsForChannelRequest{} +} +func (m *QueryIncentivizedPacketsForChannelRequest) String() string { + return proto.CompactTextString(m) +} +func (*QueryIncentivizedPacketsForChannelRequest) ProtoMessage() {} +func (*QueryIncentivizedPacketsForChannelRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{4} +} +func (m *QueryIncentivizedPacketsForChannelRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIncentivizedPacketsForChannelRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIncentivizedPacketsForChannelRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryIncentivizedPacketsForChannelRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIncentivizedPacketsForChannelRequest.Merge(m, src) +} +func (m *QueryIncentivizedPacketsForChannelRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryIncentivizedPacketsForChannelRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIncentivizedPacketsForChannelRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIncentivizedPacketsForChannelRequest proto.InternalMessageInfo + +func (m *QueryIncentivizedPacketsForChannelRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *QueryIncentivizedPacketsForChannelRequest) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func (m *QueryIncentivizedPacketsForChannelRequest) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +func (m *QueryIncentivizedPacketsForChannelRequest) GetQueryHeight() uint64 { + if m != nil { + return m.QueryHeight + } + return 0 +} + +// QueryIncentivizedPacketsResponse defines the response type for the incentivized packets RPC +type QueryIncentivizedPacketsForChannelResponse struct { + // Map of all incentivized_packets + IncentivizedPackets []*IdentifiedPacketFees `protobuf:"bytes,1,rep,name=incentivized_packets,json=incentivizedPackets,proto3" json:"incentivized_packets,omitempty"` +} + +func (m *QueryIncentivizedPacketsForChannelResponse) Reset() { + *m = QueryIncentivizedPacketsForChannelResponse{} +} +func (m *QueryIncentivizedPacketsForChannelResponse) String() string { + return proto.CompactTextString(m) +} +func (*QueryIncentivizedPacketsForChannelResponse) ProtoMessage() {} +func (*QueryIncentivizedPacketsForChannelResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{5} +} +func (m *QueryIncentivizedPacketsForChannelResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIncentivizedPacketsForChannelResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIncentivizedPacketsForChannelResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryIncentivizedPacketsForChannelResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIncentivizedPacketsForChannelResponse.Merge(m, src) +} +func (m *QueryIncentivizedPacketsForChannelResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryIncentivizedPacketsForChannelResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIncentivizedPacketsForChannelResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIncentivizedPacketsForChannelResponse proto.InternalMessageInfo + +func (m *QueryIncentivizedPacketsForChannelResponse) GetIncentivizedPackets() []*IdentifiedPacketFees { + if m != nil { + return m.IncentivizedPackets + } + return nil +} + +// QueryTotalRecvFeesRequest defines the request type for the TotalRecvFees rpc +type QueryTotalRecvFeesRequest struct { + // the packet identifier for the associated fees + PacketId types.PacketId `protobuf:"bytes,1,opt,name=packet_id,json=packetId,proto3" json:"packet_id"` +} + +func (m *QueryTotalRecvFeesRequest) Reset() { *m = QueryTotalRecvFeesRequest{} } +func (m *QueryTotalRecvFeesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTotalRecvFeesRequest) ProtoMessage() {} +func (*QueryTotalRecvFeesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{6} +} +func (m *QueryTotalRecvFeesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalRecvFeesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalRecvFeesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTotalRecvFeesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalRecvFeesRequest.Merge(m, src) +} +func (m *QueryTotalRecvFeesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalRecvFeesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalRecvFeesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalRecvFeesRequest proto.InternalMessageInfo + +func (m *QueryTotalRecvFeesRequest) GetPacketId() types.PacketId { + if m != nil { + return m.PacketId + } + return types.PacketId{} +} + +// QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees rpc +type QueryTotalRecvFeesResponse struct { + // the total packet receive fees + RecvFees github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=recv_fees,json=recvFees,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"recv_fees" yaml:"recv_fees"` +} + +func (m *QueryTotalRecvFeesResponse) Reset() { *m = QueryTotalRecvFeesResponse{} } +func (m *QueryTotalRecvFeesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTotalRecvFeesResponse) ProtoMessage() {} +func (*QueryTotalRecvFeesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{7} +} +func (m *QueryTotalRecvFeesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalRecvFeesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalRecvFeesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTotalRecvFeesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalRecvFeesResponse.Merge(m, src) +} +func (m *QueryTotalRecvFeesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalRecvFeesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalRecvFeesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalRecvFeesResponse proto.InternalMessageInfo + +func (m *QueryTotalRecvFeesResponse) GetRecvFees() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.RecvFees + } + return nil +} + +// QueryTotalAckFeesRequest defines the request type for the TotalAckFees rpc +type QueryTotalAckFeesRequest struct { + // the packet identifier for the associated fees + PacketId types.PacketId `protobuf:"bytes,1,opt,name=packet_id,json=packetId,proto3" json:"packet_id"` +} + +func (m *QueryTotalAckFeesRequest) Reset() { *m = QueryTotalAckFeesRequest{} } +func (m *QueryTotalAckFeesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTotalAckFeesRequest) ProtoMessage() {} +func (*QueryTotalAckFeesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{8} +} +func (m *QueryTotalAckFeesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalAckFeesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalAckFeesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTotalAckFeesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalAckFeesRequest.Merge(m, src) +} +func (m *QueryTotalAckFeesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalAckFeesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalAckFeesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalAckFeesRequest proto.InternalMessageInfo + +func (m *QueryTotalAckFeesRequest) GetPacketId() types.PacketId { + if m != nil { + return m.PacketId + } + return types.PacketId{} +} + +// QueryTotalAckFeesResponse defines the response type for the TotalAckFees rpc +type QueryTotalAckFeesResponse struct { + // the total packet acknowledgement fees + AckFees github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=ack_fees,json=ackFees,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"ack_fees" yaml:"ack_fees"` +} + +func (m *QueryTotalAckFeesResponse) Reset() { *m = QueryTotalAckFeesResponse{} } +func (m *QueryTotalAckFeesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTotalAckFeesResponse) ProtoMessage() {} +func (*QueryTotalAckFeesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{9} +} +func (m *QueryTotalAckFeesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalAckFeesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalAckFeesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTotalAckFeesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalAckFeesResponse.Merge(m, src) +} +func (m *QueryTotalAckFeesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalAckFeesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalAckFeesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalAckFeesResponse proto.InternalMessageInfo + +func (m *QueryTotalAckFeesResponse) GetAckFees() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.AckFees + } + return nil +} + +// QueryTotalTimeoutFeesRequest defines the request type for the TotalTimeoutFees rpc +type QueryTotalTimeoutFeesRequest struct { + // the packet identifier for the associated fees + PacketId types.PacketId `protobuf:"bytes,1,opt,name=packet_id,json=packetId,proto3" json:"packet_id"` +} + +func (m *QueryTotalTimeoutFeesRequest) Reset() { *m = QueryTotalTimeoutFeesRequest{} } +func (m *QueryTotalTimeoutFeesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTotalTimeoutFeesRequest) ProtoMessage() {} +func (*QueryTotalTimeoutFeesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{10} +} +func (m *QueryTotalTimeoutFeesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalTimeoutFeesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalTimeoutFeesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTotalTimeoutFeesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalTimeoutFeesRequest.Merge(m, src) +} +func (m *QueryTotalTimeoutFeesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalTimeoutFeesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalTimeoutFeesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalTimeoutFeesRequest proto.InternalMessageInfo + +func (m *QueryTotalTimeoutFeesRequest) GetPacketId() types.PacketId { + if m != nil { + return m.PacketId + } + return types.PacketId{} +} + +// QueryTotalTimeoutFeesResponse defines the response type for the TotalTimeoutFees rpc +type QueryTotalTimeoutFeesResponse struct { + // the total packet timeout fees + TimeoutFees github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=timeout_fees,json=timeoutFees,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"timeout_fees" yaml:"timeout_fees"` +} + +func (m *QueryTotalTimeoutFeesResponse) Reset() { *m = QueryTotalTimeoutFeesResponse{} } +func (m *QueryTotalTimeoutFeesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTotalTimeoutFeesResponse) ProtoMessage() {} +func (*QueryTotalTimeoutFeesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{11} +} +func (m *QueryTotalTimeoutFeesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTotalTimeoutFeesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTotalTimeoutFeesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryTotalTimeoutFeesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTotalTimeoutFeesResponse.Merge(m, src) +} +func (m *QueryTotalTimeoutFeesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTotalTimeoutFeesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTotalTimeoutFeesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTotalTimeoutFeesResponse proto.InternalMessageInfo + +func (m *QueryTotalTimeoutFeesResponse) GetTimeoutFees() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.TimeoutFees + } + return nil +} + +func init() { + proto.RegisterType((*QueryIncentivizedPacketsRequest)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketsRequest") + proto.RegisterType((*QueryIncentivizedPacketsResponse)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketsResponse") + proto.RegisterType((*QueryIncentivizedPacketRequest)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketRequest") + proto.RegisterType((*QueryIncentivizedPacketResponse)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketResponse") + proto.RegisterType((*QueryIncentivizedPacketsForChannelRequest)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest") + proto.RegisterType((*QueryIncentivizedPacketsForChannelResponse)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse") + proto.RegisterType((*QueryTotalRecvFeesRequest)(nil), "ibc.applications.fee.v1.QueryTotalRecvFeesRequest") + proto.RegisterType((*QueryTotalRecvFeesResponse)(nil), "ibc.applications.fee.v1.QueryTotalRecvFeesResponse") + proto.RegisterType((*QueryTotalAckFeesRequest)(nil), "ibc.applications.fee.v1.QueryTotalAckFeesRequest") + proto.RegisterType((*QueryTotalAckFeesResponse)(nil), "ibc.applications.fee.v1.QueryTotalAckFeesResponse") + proto.RegisterType((*QueryTotalTimeoutFeesRequest)(nil), "ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest") + proto.RegisterType((*QueryTotalTimeoutFeesResponse)(nil), "ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse") +} + +func init() { + proto.RegisterFile("ibc/applications/fee/v1/query.proto", fileDescriptor_0638a8a78ca2503c) +} + +var fileDescriptor_0638a8a78ca2503c = []byte{ + // 956 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcf, 0x6f, 0xdc, 0x44, + 0x14, 0xce, 0xa4, 0xa1, 0x4d, 0x66, 0x83, 0xa8, 0x26, 0x95, 0x9a, 0x5a, 0x8d, 0x93, 0x1a, 0x01, + 0xa1, 0xd2, 0x7a, 0x94, 0x8d, 0x0a, 0x2d, 0x42, 0x08, 0x92, 0x2a, 0x90, 0x13, 0x65, 0xd5, 0x13, + 0x02, 0x6d, 0xbd, 0xe3, 0x59, 0x67, 0x94, 0x5d, 0x8f, 0xbb, 0xf6, 0x1a, 0xb6, 0x69, 0x90, 0xa8, + 0x14, 0x21, 0xa1, 0x0a, 0x21, 0x21, 0x71, 0xe0, 0x1f, 0x40, 0xe2, 0x3f, 0xe0, 0xc0, 0xbd, 0x27, + 0x54, 0x89, 0x0b, 0xa7, 0x82, 0x12, 0xce, 0x1c, 0x10, 0x07, 0x8e, 0x68, 0x7e, 0xd8, 0xeb, 0xe0, + 0x75, 0xb1, 0xd3, 0xcd, 0x29, 0xf6, 0xbc, 0xf7, 0xe6, 0x7d, 0xdf, 0xf7, 0xc6, 0xdf, 0x64, 0xe1, + 0x8b, 0xac, 0x4d, 0xb0, 0x13, 0x04, 0x5d, 0x46, 0x9c, 0x88, 0x71, 0x3f, 0xc4, 0x1d, 0x4a, 0x71, + 0xbc, 0x86, 0xef, 0x0e, 0x68, 0x7f, 0x68, 0x07, 0x7d, 0x1e, 0x71, 0x74, 0x91, 0xb5, 0x89, 0x9d, + 0x4d, 0xb2, 0x3b, 0x94, 0xda, 0xf1, 0x9a, 0x71, 0xc1, 0xe3, 0x1e, 0x97, 0x39, 0x58, 0x3c, 0xa9, + 0x74, 0xe3, 0xb2, 0xc7, 0xb9, 0xd7, 0xa5, 0xd8, 0x09, 0x18, 0x76, 0x7c, 0x9f, 0x47, 0xba, 0x48, + 0x45, 0x4d, 0xc2, 0xc3, 0x1e, 0x0f, 0x71, 0xdb, 0x09, 0x45, 0xa3, 0x36, 0x8d, 0x9c, 0x35, 0x4c, + 0x38, 0xf3, 0x75, 0xfc, 0x6a, 0x36, 0x2e, 0x51, 0xa4, 0x59, 0x81, 0xe3, 0x31, 0x5f, 0x6e, 0xa6, + 0x73, 0xaf, 0x14, 0xa1, 0x17, 0xf8, 0x32, 0x29, 0x84, 0xf7, 0x29, 0x26, 0x3b, 0x8e, 0xef, 0xd3, + 0xae, 0x08, 0xeb, 0x47, 0x95, 0x62, 0x3d, 0x04, 0x70, 0xf9, 0x03, 0xd1, 0x68, 0xdb, 0x27, 0xd4, + 0x8f, 0x58, 0xcc, 0xee, 0x51, 0xf7, 0x96, 0x43, 0x76, 0x69, 0x14, 0x36, 0xe9, 0xdd, 0x01, 0x0d, + 0x23, 0xb4, 0x05, 0xe1, 0xa8, 0xfb, 0x22, 0x58, 0x01, 0xab, 0xb5, 0xc6, 0xcb, 0xb6, 0x82, 0x6a, + 0x0b, 0xa8, 0xb6, 0x12, 0x4c, 0x43, 0xb5, 0x6f, 0x39, 0x1e, 0xd5, 0xb5, 0xcd, 0x4c, 0x25, 0xba, + 0x02, 0xe7, 0x65, 0x62, 0x6b, 0x87, 0x32, 0x6f, 0x27, 0x5a, 0x9c, 0x5e, 0x01, 0xab, 0x33, 0xcd, + 0x9a, 0x5c, 0x7b, 0x4f, 0x2e, 0x59, 0x5f, 0x02, 0xb8, 0x52, 0x0c, 0x27, 0x0c, 0xb8, 0x1f, 0x52, + 0xd4, 0x81, 0x17, 0x58, 0x26, 0xdc, 0x0a, 0x54, 0x7c, 0x11, 0xac, 0x9c, 0x59, 0xad, 0x35, 0xea, + 0x76, 0xc1, 0xc4, 0xec, 0x6d, 0x57, 0xd4, 0x74, 0x58, 0xb2, 0xe3, 0x16, 0xa5, 0xe1, 0xc6, 0xcc, + 0xa3, 0x27, 0xcb, 0x53, 0xcd, 0x05, 0x96, 0xef, 0x67, 0x1d, 0x00, 0x68, 0x16, 0x80, 0x49, 0xa4, + 0x79, 0x1b, 0xce, 0xa9, 0xee, 0x2d, 0xe6, 0x6a, 0x65, 0x96, 0x64, 0x7f, 0xa1, 0xba, 0x9d, 0x48, + 0x1d, 0x0b, 0x4d, 0x44, 0xd6, 0xb6, 0xab, 0xfb, 0xcd, 0x06, 0xfa, 0xbd, 0x8c, 0x28, 0x5f, 0x14, + 0xcf, 0x28, 0xd5, 0xc4, 0x85, 0x0b, 0x63, 0x34, 0xd1, 0x90, 0x4e, 0x24, 0x09, 0xca, 0x4b, 0x62, + 0xfd, 0x0c, 0xe0, 0xab, 0x45, 0xe3, 0xd9, 0xe2, 0xfd, 0x4d, 0xc5, 0x77, 0xd2, 0xe7, 0xe6, 0x22, + 0x3c, 0x17, 0xf0, 0xbe, 0x94, 0x58, 0xa8, 0x33, 0xd7, 0x3c, 0x2b, 0x5e, 0xb7, 0x5d, 0xb4, 0x04, + 0xa1, 0x96, 0x58, 0xc4, 0xce, 0xc8, 0xd8, 0x9c, 0x5e, 0x19, 0x23, 0xed, 0x4c, 0x5e, 0xda, 0xaf, + 0x00, 0xbc, 0x5a, 0x86, 0x90, 0x56, 0xf9, 0xce, 0x04, 0x4f, 0xde, 0xf8, 0x33, 0xf7, 0x31, 0xbc, + 0x24, 0xf1, 0xdc, 0xe6, 0x91, 0xd3, 0x6d, 0x52, 0x12, 0xcb, 0xd4, 0x49, 0x9d, 0x36, 0xeb, 0x3b, + 0x00, 0x8d, 0x71, 0xfb, 0x6b, 0x7e, 0xf7, 0xe1, 0x5c, 0x9f, 0x92, 0xb8, 0xd5, 0xa1, 0x34, 0x21, + 0x75, 0xe9, 0xd8, 0xc0, 0x92, 0x51, 0x6d, 0x72, 0xe6, 0x6f, 0xdc, 0x14, 0x9b, 0xff, 0xf5, 0x64, + 0xf9, 0xfc, 0xd0, 0xe9, 0x75, 0xdf, 0xb0, 0xd2, 0x4a, 0xeb, 0x87, 0xdf, 0x96, 0x57, 0x3d, 0x16, + 0xed, 0x0c, 0xda, 0x36, 0xe1, 0x3d, 0xac, 0x4d, 0x4d, 0xfd, 0xa9, 0x87, 0xee, 0x2e, 0x8e, 0x86, + 0x01, 0x0d, 0xe5, 0x26, 0x61, 0x73, 0xb6, 0xaf, 0x51, 0x58, 0x1f, 0xc1, 0xc5, 0x11, 0xb6, 0x77, + 0xc8, 0xee, 0x64, 0xa9, 0x7f, 0x0b, 0xb2, 0xd2, 0xa6, 0xdb, 0x6b, 0xe6, 0x43, 0x38, 0xeb, 0x90, + 0xdd, 0x92, 0xc4, 0x37, 0x35, 0xf1, 0x17, 0x14, 0xf1, 0xa4, 0xb0, 0x1a, 0xef, 0x73, 0x8e, 0x82, + 0x60, 0xdd, 0x81, 0x97, 0x47, 0xb8, 0x6e, 0xb3, 0x1e, 0xe5, 0x83, 0x68, 0xb2, 0xd4, 0xbf, 0x07, + 0x70, 0xa9, 0xa0, 0x85, 0xa6, 0x7f, 0x00, 0xe0, 0x7c, 0xa4, 0xd6, 0x4b, 0x6a, 0xf0, 0xae, 0xd6, + 0x60, 0x41, 0x69, 0x90, 0x2d, 0xae, 0xa6, 0x43, 0x2d, 0x1a, 0xe1, 0x69, 0xfc, 0x54, 0x83, 0xcf, + 0x49, 0xa4, 0xe8, 0x47, 0x00, 0x17, 0xc6, 0x7c, 0x94, 0xe8, 0x7a, 0xe1, 0x47, 0xf6, 0x3f, 0xd7, + 0x98, 0x71, 0xe3, 0x04, 0x95, 0x4a, 0x1e, 0xab, 0xfe, 0xe0, 0x97, 0x3f, 0xbe, 0x99, 0x7e, 0x05, + 0xbd, 0x84, 0xf5, 0xa5, 0x9b, 0x5e, 0xb6, 0xe3, 0xec, 0x00, 0x3d, 0x9c, 0x86, 0x28, 0xbf, 0x1d, + 0x7a, 0xbd, 0x2a, 0x80, 0x04, 0xf9, 0xf5, 0xea, 0x85, 0x1a, 0xf8, 0x03, 0x20, 0x91, 0xdf, 0x47, + 0xf7, 0xca, 0x20, 0xc7, 0xc2, 0x57, 0xf1, 0x5e, 0x7a, 0xda, 0x6c, 0x6d, 0xbb, 0xfb, 0xe9, 0xff, + 0x0f, 0x99, 0xd8, 0xc8, 0x79, 0xf7, 0x71, 0x28, 0x80, 0xfa, 0x84, 0x66, 0xe3, 0xc9, 0xda, 0x3e, + 0xfa, 0x13, 0xc0, 0xa5, 0xa7, 0xfa, 0x2b, 0xda, 0xa8, 0x3c, 0x9a, 0xdc, 0x6d, 0x63, 0x6c, 0x3e, + 0xd3, 0x1e, 0x5a, 0xaf, 0x9b, 0x52, 0xae, 0xb7, 0xd0, 0x9b, 0xa5, 0x06, 0x8d, 0xf7, 0x52, 0x81, + 0xf6, 0x32, 0x72, 0xa0, 0x7f, 0x00, 0x7c, 0xfe, 0x98, 0xc1, 0xa2, 0xc6, 0xd3, 0xc1, 0x8d, 0x73, + 0x7b, 0x63, 0xbd, 0x52, 0x8d, 0x26, 0xf0, 0x99, 0x24, 0xf0, 0x29, 0x8a, 0x73, 0x04, 0x22, 0x91, + 0xdf, 0x4a, 0x4d, 0xfa, 0x94, 0x66, 0xfd, 0x37, 0x80, 0xf3, 0x59, 0x83, 0x45, 0x6b, 0x25, 0x58, + 0x1c, 0xf7, 0x7a, 0xa3, 0x51, 0xa5, 0x44, 0xf3, 0xde, 0x97, 0xbc, 0x3f, 0x41, 0x83, 0x02, 0xde, + 0x89, 0x47, 0x9f, 0x12, 0xed, 0x83, 0x69, 0x78, 0xfe, 0xbf, 0xe6, 0x8a, 0xae, 0x95, 0xe0, 0x91, + 0xf7, 0x7b, 0xe3, 0xb5, 0xaa, 0x65, 0x5a, 0x82, 0xcf, 0xd5, 0xb7, 0xbe, 0x87, 0x86, 0x05, 0x1a, + 0x64, 0x3d, 0xfa, 0x74, 0x74, 0xd8, 0x78, 0xff, 0xd1, 0xa1, 0x09, 0x1e, 0x1f, 0x9a, 0xe0, 0xf7, + 0x43, 0x13, 0x7c, 0x7d, 0x64, 0x4e, 0x3d, 0x3e, 0x32, 0xa7, 0x7e, 0x3d, 0x32, 0xa7, 0x3e, 0xbc, + 0x96, 0xbf, 0x10, 0x58, 0x9b, 0xd4, 0x3d, 0x8e, 0xe3, 0x75, 0xdc, 0xe3, 0xee, 0xa0, 0x4b, 0x43, + 0x85, 0xb9, 0x71, 0xa3, 0x2e, 0x60, 0xcb, 0x3b, 0xa2, 0x7d, 0x56, 0xfe, 0x4c, 0x59, 0xff, 0x37, + 0x00, 0x00, 0xff, 0xff, 0x54, 0xbb, 0x0e, 0x52, 0xac, 0x0d, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // IncentivizedPackets returns all incentivized packets and their associated fees + IncentivizedPackets(ctx context.Context, in *QueryIncentivizedPacketsRequest, opts ...grpc.CallOption) (*QueryIncentivizedPacketsResponse, error) + // IncentivizedPacket returns all packet fees for a packet given its identifier + IncentivizedPacket(ctx context.Context, in *QueryIncentivizedPacketRequest, opts ...grpc.CallOption) (*QueryIncentivizedPacketResponse, error) + // Gets all incentivized packets for a specific channel + IncentivizedPacketsForChannel(ctx context.Context, in *QueryIncentivizedPacketsForChannelRequest, opts ...grpc.CallOption) (*QueryIncentivizedPacketsForChannelResponse, error) + // TotalRecvFees returns the total receive fees for a packet given its identifier + TotalRecvFees(ctx context.Context, in *QueryTotalRecvFeesRequest, opts ...grpc.CallOption) (*QueryTotalRecvFeesResponse, error) + // TotalAckFees returns the total acknowledgement fees for a packet given its identifier + TotalAckFees(ctx context.Context, in *QueryTotalAckFeesRequest, opts ...grpc.CallOption) (*QueryTotalAckFeesResponse, error) + // TotalTimeoutFees returns the total timeout fees for a packet given its identifier + TotalTimeoutFees(ctx context.Context, in *QueryTotalTimeoutFeesRequest, opts ...grpc.CallOption) (*QueryTotalTimeoutFeesResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) IncentivizedPackets(ctx context.Context, in *QueryIncentivizedPacketsRequest, opts ...grpc.CallOption) (*QueryIncentivizedPacketsResponse, error) { + out := new(QueryIncentivizedPacketsResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/IncentivizedPackets", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) IncentivizedPacket(ctx context.Context, in *QueryIncentivizedPacketRequest, opts ...grpc.CallOption) (*QueryIncentivizedPacketResponse, error) { + out := new(QueryIncentivizedPacketResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/IncentivizedPacket", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) IncentivizedPacketsForChannel(ctx context.Context, in *QueryIncentivizedPacketsForChannelRequest, opts ...grpc.CallOption) (*QueryIncentivizedPacketsForChannelResponse, error) { + out := new(QueryIncentivizedPacketsForChannelResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/IncentivizedPacketsForChannel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) TotalRecvFees(ctx context.Context, in *QueryTotalRecvFeesRequest, opts ...grpc.CallOption) (*QueryTotalRecvFeesResponse, error) { + out := new(QueryTotalRecvFeesResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/TotalRecvFees", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) TotalAckFees(ctx context.Context, in *QueryTotalAckFeesRequest, opts ...grpc.CallOption) (*QueryTotalAckFeesResponse, error) { + out := new(QueryTotalAckFeesResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/TotalAckFees", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) TotalTimeoutFees(ctx context.Context, in *QueryTotalTimeoutFeesRequest, opts ...grpc.CallOption) (*QueryTotalTimeoutFeesResponse, error) { + out := new(QueryTotalTimeoutFeesResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/TotalTimeoutFees", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // IncentivizedPackets returns all incentivized packets and their associated fees + IncentivizedPackets(context.Context, *QueryIncentivizedPacketsRequest) (*QueryIncentivizedPacketsResponse, error) + // IncentivizedPacket returns all packet fees for a packet given its identifier + IncentivizedPacket(context.Context, *QueryIncentivizedPacketRequest) (*QueryIncentivizedPacketResponse, error) + // Gets all incentivized packets for a specific channel + IncentivizedPacketsForChannel(context.Context, *QueryIncentivizedPacketsForChannelRequest) (*QueryIncentivizedPacketsForChannelResponse, error) + // TotalRecvFees returns the total receive fees for a packet given its identifier + TotalRecvFees(context.Context, *QueryTotalRecvFeesRequest) (*QueryTotalRecvFeesResponse, error) + // TotalAckFees returns the total acknowledgement fees for a packet given its identifier + TotalAckFees(context.Context, *QueryTotalAckFeesRequest) (*QueryTotalAckFeesResponse, error) + // TotalTimeoutFees returns the total timeout fees for a packet given its identifier + TotalTimeoutFees(context.Context, *QueryTotalTimeoutFeesRequest) (*QueryTotalTimeoutFeesResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) IncentivizedPackets(ctx context.Context, req *QueryIncentivizedPacketsRequest) (*QueryIncentivizedPacketsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method IncentivizedPackets not implemented") +} +func (*UnimplementedQueryServer) IncentivizedPacket(ctx context.Context, req *QueryIncentivizedPacketRequest) (*QueryIncentivizedPacketResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method IncentivizedPacket not implemented") +} +func (*UnimplementedQueryServer) IncentivizedPacketsForChannel(ctx context.Context, req *QueryIncentivizedPacketsForChannelRequest) (*QueryIncentivizedPacketsForChannelResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method IncentivizedPacketsForChannel not implemented") +} +func (*UnimplementedQueryServer) TotalRecvFees(ctx context.Context, req *QueryTotalRecvFeesRequest) (*QueryTotalRecvFeesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TotalRecvFees not implemented") +} +func (*UnimplementedQueryServer) TotalAckFees(ctx context.Context, req *QueryTotalAckFeesRequest) (*QueryTotalAckFeesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TotalAckFees not implemented") +} +func (*UnimplementedQueryServer) TotalTimeoutFees(ctx context.Context, req *QueryTotalTimeoutFeesRequest) (*QueryTotalTimeoutFeesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TotalTimeoutFees not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_IncentivizedPackets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryIncentivizedPacketsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).IncentivizedPackets(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/IncentivizedPackets", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).IncentivizedPackets(ctx, req.(*QueryIncentivizedPacketsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_IncentivizedPacket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryIncentivizedPacketRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).IncentivizedPacket(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/IncentivizedPacket", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).IncentivizedPacket(ctx, req.(*QueryIncentivizedPacketRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_IncentivizedPacketsForChannel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryIncentivizedPacketsForChannelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).IncentivizedPacketsForChannel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/IncentivizedPacketsForChannel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).IncentivizedPacketsForChannel(ctx, req.(*QueryIncentivizedPacketsForChannelRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_TotalRecvFees_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTotalRecvFeesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TotalRecvFees(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/TotalRecvFees", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TotalRecvFees(ctx, req.(*QueryTotalRecvFeesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_TotalAckFees_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTotalAckFeesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TotalAckFees(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/TotalAckFees", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TotalAckFees(ctx, req.(*QueryTotalAckFeesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_TotalTimeoutFees_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTotalTimeoutFeesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TotalTimeoutFees(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/TotalTimeoutFees", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TotalTimeoutFees(ctx, req.(*QueryTotalTimeoutFeesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ibc.applications.fee.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "IncentivizedPackets", + Handler: _Query_IncentivizedPackets_Handler, + }, + { + MethodName: "IncentivizedPacket", + Handler: _Query_IncentivizedPacket_Handler, + }, + { + MethodName: "IncentivizedPacketsForChannel", + Handler: _Query_IncentivizedPacketsForChannel_Handler, + }, + { + MethodName: "TotalRecvFees", + Handler: _Query_TotalRecvFees_Handler, + }, + { + MethodName: "TotalAckFees", + Handler: _Query_TotalAckFees_Handler, + }, + { + MethodName: "TotalTimeoutFees", + Handler: _Query_TotalTimeoutFees_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ibc/applications/fee/v1/query.proto", +} + +func (m *QueryIncentivizedPacketsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryIncentivizedPacketsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIncentivizedPacketsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.QueryHeight != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.QueryHeight)) + i-- + dAtA[i] = 0x10 + } + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryIncentivizedPacketsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryIncentivizedPacketsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIncentivizedPacketsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.IncentivizedPackets) > 0 { + for iNdEx := len(m.IncentivizedPackets) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IncentivizedPackets[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryIncentivizedPacketRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryIncentivizedPacketRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIncentivizedPacketRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.QueryHeight != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.QueryHeight)) + i-- + dAtA[i] = 0x10 + } + { + size, err := m.PacketId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryIncentivizedPacketResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryIncentivizedPacketResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIncentivizedPacketResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.IncentivizedPacket.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryIncentivizedPacketsForChannelRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryIncentivizedPacketsForChannelRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIncentivizedPacketsForChannelRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.QueryHeight != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.QueryHeight)) + i-- + dAtA[i] = 0x20 + } + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0x12 + } + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryIncentivizedPacketsForChannelResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryIncentivizedPacketsForChannelResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIncentivizedPacketsForChannelResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.IncentivizedPackets) > 0 { + for iNdEx := len(m.IncentivizedPackets) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IncentivizedPackets[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryTotalRecvFeesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryTotalRecvFeesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalRecvFeesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.PacketId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryTotalRecvFeesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryTotalRecvFeesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalRecvFeesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RecvFees) > 0 { + for iNdEx := len(m.RecvFees) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RecvFees[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryTotalAckFeesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryTotalAckFeesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalAckFeesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.PacketId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryTotalAckFeesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryTotalAckFeesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalAckFeesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AckFees) > 0 { + for iNdEx := len(m.AckFees) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AckFees[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryTotalTimeoutFeesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryTotalTimeoutFeesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalTimeoutFeesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.PacketId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryTotalTimeoutFeesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryTotalTimeoutFeesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTotalTimeoutFeesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TimeoutFees) > 0 { + for iNdEx := len(m.TimeoutFees) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TimeoutFees[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryIncentivizedPacketsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + if m.QueryHeight != 0 { + n += 1 + sovQuery(uint64(m.QueryHeight)) + } + return n +} + +func (m *QueryIncentivizedPacketsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.IncentivizedPackets) > 0 { + for _, e := range m.IncentivizedPackets { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryIncentivizedPacketRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.PacketId.Size() + n += 1 + l + sovQuery(uint64(l)) + if m.QueryHeight != 0 { + n += 1 + sovQuery(uint64(m.QueryHeight)) + } + return n +} + +func (m *QueryIncentivizedPacketResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.IncentivizedPacket.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryIncentivizedPacketsForChannelRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.QueryHeight != 0 { + n += 1 + sovQuery(uint64(m.QueryHeight)) + } + return n +} + +func (m *QueryIncentivizedPacketsForChannelResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.IncentivizedPackets) > 0 { + for _, e := range m.IncentivizedPackets { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryTotalRecvFeesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.PacketId.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryTotalRecvFeesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RecvFees) > 0 { + for _, e := range m.RecvFees { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryTotalAckFeesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.PacketId.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryTotalAckFeesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.AckFees) > 0 { + for _, e := range m.AckFees { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryTotalTimeoutFeesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.PacketId.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryTotalTimeoutFeesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TimeoutFees) > 0 { + for _, e := range m.TimeoutFees { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryIncentivizedPacketsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryIncentivizedPacketsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIncentivizedPacketsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryHeight", wireType) + } + m.QueryHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.QueryHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIncentivizedPacketsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryIncentivizedPacketsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIncentivizedPacketsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IncentivizedPackets", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IncentivizedPackets = append(m.IncentivizedPackets, IdentifiedPacketFees{}) + if err := m.IncentivizedPackets[len(m.IncentivizedPackets)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIncentivizedPacketRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryIncentivizedPacketRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIncentivizedPacketRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PacketId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryHeight", wireType) + } + m.QueryHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.QueryHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIncentivizedPacketResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryIncentivizedPacketResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIncentivizedPacketResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IncentivizedPacket", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.IncentivizedPacket.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIncentivizedPacketsForChannelRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryIncentivizedPacketsForChannelRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIncentivizedPacketsForChannelRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryHeight", wireType) + } + m.QueryHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.QueryHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryIncentivizedPacketsForChannelResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryIncentivizedPacketsForChannelResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIncentivizedPacketsForChannelResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IncentivizedPackets", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IncentivizedPackets = append(m.IncentivizedPackets, &IdentifiedPacketFees{}) + if err := m.IncentivizedPackets[len(m.IncentivizedPackets)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTotalRecvFeesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalRecvFeesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalRecvFeesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PacketId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTotalRecvFeesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalRecvFeesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalRecvFeesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RecvFees", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RecvFees = append(m.RecvFees, types1.Coin{}) + if err := m.RecvFees[len(m.RecvFees)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTotalAckFeesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalAckFeesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalAckFeesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PacketId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTotalAckFeesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalAckFeesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalAckFeesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AckFees", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AckFees = append(m.AckFees, types1.Coin{}) + if err := m.AckFees[len(m.AckFees)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTotalTimeoutFeesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalTimeoutFeesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalTimeoutFeesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PacketId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryTotalTimeoutFeesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryTotalTimeoutFeesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTotalTimeoutFeesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeoutFees", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TimeoutFees = append(m.TimeoutFees, types1.Coin{}) + if err := m.TimeoutFees[len(m.TimeoutFees)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/29-fee/types/query.pb.gw.go b/modules/apps/29-fee/types/query.pb.gw.go new file mode 100644 index 00000000000..8775f7404fd --- /dev/null +++ b/modules/apps/29-fee/types/query.pb.gw.go @@ -0,0 +1,944 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: ibc/applications/fee/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +var ( + filter_Query_IncentivizedPackets_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_IncentivizedPackets_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIncentivizedPacketsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_IncentivizedPackets_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.IncentivizedPackets(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_IncentivizedPackets_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIncentivizedPacketsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_IncentivizedPackets_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.IncentivizedPackets(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_IncentivizedPacket_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "port_id": 1, "channel_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} +) + +func request_Query_IncentivizedPacket_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIncentivizedPacketRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["packet_id.port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + } + + val, ok = pathParams["packet_id.channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + } + + val, ok = pathParams["packet_id.sequence"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.sequence") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.sequence", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.sequence", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_IncentivizedPacket_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.IncentivizedPacket(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_IncentivizedPacket_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIncentivizedPacketRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["packet_id.port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + } + + val, ok = pathParams["packet_id.channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + } + + val, ok = pathParams["packet_id.sequence"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.sequence") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.sequence", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.sequence", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_IncentivizedPacket_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.IncentivizedPacket(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_IncentivizedPacketsForChannel_0 = &utilities.DoubleArray{Encoding: map[string]int{"port_id": 0, "channel_id": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} +) + +func request_Query_IncentivizedPacketsForChannel_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIncentivizedPacketsForChannelRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_IncentivizedPacketsForChannel_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.IncentivizedPacketsForChannel(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_IncentivizedPacketsForChannel_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIncentivizedPacketsForChannelRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_IncentivizedPacketsForChannel_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.IncentivizedPacketsForChannel(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_TotalRecvFees_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "port_id": 1, "channel_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} +) + +func request_Query_TotalRecvFees_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalRecvFeesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["packet_id.port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + } + + val, ok = pathParams["packet_id.channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + } + + val, ok = pathParams["packet_id.sequence"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.sequence") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.sequence", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.sequence", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalRecvFees_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.TotalRecvFees(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TotalRecvFees_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalRecvFeesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["packet_id.port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + } + + val, ok = pathParams["packet_id.channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + } + + val, ok = pathParams["packet_id.sequence"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.sequence") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.sequence", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.sequence", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalRecvFees_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.TotalRecvFees(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_TotalAckFees_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "port_id": 1, "channel_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} +) + +func request_Query_TotalAckFees_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalAckFeesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["packet_id.port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + } + + val, ok = pathParams["packet_id.channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + } + + val, ok = pathParams["packet_id.sequence"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.sequence") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.sequence", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.sequence", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalAckFees_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.TotalAckFees(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TotalAckFees_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalAckFeesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["packet_id.port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + } + + val, ok = pathParams["packet_id.channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + } + + val, ok = pathParams["packet_id.sequence"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.sequence") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.sequence", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.sequence", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalAckFees_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.TotalAckFees(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_TotalTimeoutFees_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "port_id": 1, "channel_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} +) + +func request_Query_TotalTimeoutFees_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalTimeoutFeesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["packet_id.port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + } + + val, ok = pathParams["packet_id.channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + } + + val, ok = pathParams["packet_id.sequence"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.sequence") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.sequence", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.sequence", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalTimeoutFees_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.TotalTimeoutFees(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TotalTimeoutFees_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTotalTimeoutFeesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["packet_id.port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + } + + val, ok = pathParams["packet_id.channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + } + + val, ok = pathParams["packet_id.sequence"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.sequence") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.sequence", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.sequence", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_TotalTimeoutFees_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.TotalTimeoutFees(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_IncentivizedPackets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_IncentivizedPackets_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_IncentivizedPackets_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_IncentivizedPacket_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_IncentivizedPacket_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_IncentivizedPacket_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_IncentivizedPacketsForChannel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_IncentivizedPacketsForChannel_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_IncentivizedPacketsForChannel_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TotalRecvFees_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_TotalRecvFees_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TotalRecvFees_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TotalAckFees_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_TotalAckFees_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TotalAckFees_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TotalTimeoutFees_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_TotalTimeoutFees_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TotalTimeoutFees_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_IncentivizedPackets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_IncentivizedPackets_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_IncentivizedPackets_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_IncentivizedPacket_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_IncentivizedPacket_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_IncentivizedPacket_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_IncentivizedPacketsForChannel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_IncentivizedPacketsForChannel_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_IncentivizedPacketsForChannel_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TotalRecvFees_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_TotalRecvFees_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TotalRecvFees_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TotalAckFees_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_TotalAckFees_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TotalAckFees_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TotalTimeoutFees_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_TotalTimeoutFees_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_TotalTimeoutFees_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_IncentivizedPackets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "apps", "fee", "v1", "incentivized_packets"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_IncentivizedPacket_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "incentivized_packet", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_IncentivizedPacketsForChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"ibc", "apps", "fee", "v1", "incentivized_packets", "port_id", "channel_id"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_TotalRecvFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_recv_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_TotalAckFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_ack_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_TotalTimeoutFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_timeout_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Query_IncentivizedPackets_0 = runtime.ForwardResponseMessage + + forward_Query_IncentivizedPacket_0 = runtime.ForwardResponseMessage + + forward_Query_IncentivizedPacketsForChannel_0 = runtime.ForwardResponseMessage + + forward_Query_TotalRecvFees_0 = runtime.ForwardResponseMessage + + forward_Query_TotalAckFees_0 = runtime.ForwardResponseMessage + + forward_Query_TotalTimeoutFees_0 = runtime.ForwardResponseMessage +) diff --git a/modules/apps/29-fee/types/tx.pb.go b/modules/apps/29-fee/types/tx.pb.go new file mode 100644 index 00000000000..1cecc607dc9 --- /dev/null +++ b/modules/apps/29-fee/types/tx.pb.go @@ -0,0 +1,1544 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/fee/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc +type MsgRegisterCounterpartyAddress struct { + // the relayer address + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // the counterparty relayer address + CounterpartyAddress string `protobuf:"bytes,2,opt,name=counterparty_address,json=counterpartyAddress,proto3" json:"counterparty_address,omitempty" yaml:"counterparty_address"` + // unique channel identifier + ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` +} + +func (m *MsgRegisterCounterpartyAddress) Reset() { *m = MsgRegisterCounterpartyAddress{} } +func (m *MsgRegisterCounterpartyAddress) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterCounterpartyAddress) ProtoMessage() {} +func (*MsgRegisterCounterpartyAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_05c93128649f1b96, []int{0} +} +func (m *MsgRegisterCounterpartyAddress) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterCounterpartyAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterCounterpartyAddress.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRegisterCounterpartyAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterCounterpartyAddress.Merge(m, src) +} +func (m *MsgRegisterCounterpartyAddress) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterCounterpartyAddress) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterCounterpartyAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterCounterpartyAddress proto.InternalMessageInfo + +// MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc +type MsgRegisterCounterpartyAddressResponse struct { +} + +func (m *MsgRegisterCounterpartyAddressResponse) Reset() { + *m = MsgRegisterCounterpartyAddressResponse{} +} +func (m *MsgRegisterCounterpartyAddressResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterCounterpartyAddressResponse) ProtoMessage() {} +func (*MsgRegisterCounterpartyAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_05c93128649f1b96, []int{1} +} +func (m *MsgRegisterCounterpartyAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterCounterpartyAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterCounterpartyAddressResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRegisterCounterpartyAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterCounterpartyAddressResponse.Merge(m, src) +} +func (m *MsgRegisterCounterpartyAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterCounterpartyAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterCounterpartyAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterCounterpartyAddressResponse proto.InternalMessageInfo + +// MsgPayPacketFee defines the request type for the PayPacketFee rpc +// This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be +// paid for +type MsgPayPacketFee struct { + // fee encapsulates the recv, ack and timeout fees associated with an IBC packet + Fee Fee `protobuf:"bytes,1,opt,name=fee,proto3" json:"fee"` + // the source port unique identifier + SourcePortId string `protobuf:"bytes,2,opt,name=source_port_id,json=sourcePortId,proto3" json:"source_port_id,omitempty" yaml:"source_port_id"` + // the source channel unique identifer + SourceChannelId string `protobuf:"bytes,3,opt,name=source_channel_id,json=sourceChannelId,proto3" json:"source_channel_id,omitempty" yaml:"source_channel_id"` + // account address to refund fee if necessary + Signer string `protobuf:"bytes,4,opt,name=signer,proto3" json:"signer,omitempty"` + // optional list of relayers permitted to the receive packet fees + Relayers []string `protobuf:"bytes,5,rep,name=relayers,proto3" json:"relayers,omitempty"` +} + +func (m *MsgPayPacketFee) Reset() { *m = MsgPayPacketFee{} } +func (m *MsgPayPacketFee) String() string { return proto.CompactTextString(m) } +func (*MsgPayPacketFee) ProtoMessage() {} +func (*MsgPayPacketFee) Descriptor() ([]byte, []int) { + return fileDescriptor_05c93128649f1b96, []int{2} +} +func (m *MsgPayPacketFee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgPayPacketFee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgPayPacketFee.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgPayPacketFee) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgPayPacketFee.Merge(m, src) +} +func (m *MsgPayPacketFee) XXX_Size() int { + return m.Size() +} +func (m *MsgPayPacketFee) XXX_DiscardUnknown() { + xxx_messageInfo_MsgPayPacketFee.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgPayPacketFee proto.InternalMessageInfo + +// MsgPayPacketFeeResponse defines the response type for the PayPacketFee rpc +type MsgPayPacketFeeResponse struct { +} + +func (m *MsgPayPacketFeeResponse) Reset() { *m = MsgPayPacketFeeResponse{} } +func (m *MsgPayPacketFeeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgPayPacketFeeResponse) ProtoMessage() {} +func (*MsgPayPacketFeeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_05c93128649f1b96, []int{3} +} +func (m *MsgPayPacketFeeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgPayPacketFeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgPayPacketFeeResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgPayPacketFeeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgPayPacketFeeResponse.Merge(m, src) +} +func (m *MsgPayPacketFeeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgPayPacketFeeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgPayPacketFeeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgPayPacketFeeResponse proto.InternalMessageInfo + +// MsgPayPacketFeeAsync defines the request type for the PayPacketFeeAsync rpc +// This Msg can be used to pay for a packet at a specified sequence (instead of the next sequence send) +type MsgPayPacketFeeAsync struct { + // unique packet identifier comprised of the channel ID, port ID and sequence + PacketId types.PacketId `protobuf:"bytes,1,opt,name=packet_id,json=packetId,proto3" json:"packet_id" yaml:"packet_id"` + // the packet fee associated with a particular IBC packet + PacketFee PacketFee `protobuf:"bytes,2,opt,name=packet_fee,json=packetFee,proto3" json:"packet_fee" yaml:"packet_fee"` +} + +func (m *MsgPayPacketFeeAsync) Reset() { *m = MsgPayPacketFeeAsync{} } +func (m *MsgPayPacketFeeAsync) String() string { return proto.CompactTextString(m) } +func (*MsgPayPacketFeeAsync) ProtoMessage() {} +func (*MsgPayPacketFeeAsync) Descriptor() ([]byte, []int) { + return fileDescriptor_05c93128649f1b96, []int{4} +} +func (m *MsgPayPacketFeeAsync) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgPayPacketFeeAsync) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgPayPacketFeeAsync.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgPayPacketFeeAsync) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgPayPacketFeeAsync.Merge(m, src) +} +func (m *MsgPayPacketFeeAsync) XXX_Size() int { + return m.Size() +} +func (m *MsgPayPacketFeeAsync) XXX_DiscardUnknown() { + xxx_messageInfo_MsgPayPacketFeeAsync.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgPayPacketFeeAsync proto.InternalMessageInfo + +// MsgPayPacketFeeAsyncResponse defines the response type for the PayPacketFeeAsync rpc +type MsgPayPacketFeeAsyncResponse struct { +} + +func (m *MsgPayPacketFeeAsyncResponse) Reset() { *m = MsgPayPacketFeeAsyncResponse{} } +func (m *MsgPayPacketFeeAsyncResponse) String() string { return proto.CompactTextString(m) } +func (*MsgPayPacketFeeAsyncResponse) ProtoMessage() {} +func (*MsgPayPacketFeeAsyncResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_05c93128649f1b96, []int{5} +} +func (m *MsgPayPacketFeeAsyncResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgPayPacketFeeAsyncResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgPayPacketFeeAsyncResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgPayPacketFeeAsyncResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgPayPacketFeeAsyncResponse.Merge(m, src) +} +func (m *MsgPayPacketFeeAsyncResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgPayPacketFeeAsyncResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgPayPacketFeeAsyncResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgPayPacketFeeAsyncResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgRegisterCounterpartyAddress)(nil), "ibc.applications.fee.v1.MsgRegisterCounterpartyAddress") + proto.RegisterType((*MsgRegisterCounterpartyAddressResponse)(nil), "ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse") + proto.RegisterType((*MsgPayPacketFee)(nil), "ibc.applications.fee.v1.MsgPayPacketFee") + proto.RegisterType((*MsgPayPacketFeeResponse)(nil), "ibc.applications.fee.v1.MsgPayPacketFeeResponse") + proto.RegisterType((*MsgPayPacketFeeAsync)(nil), "ibc.applications.fee.v1.MsgPayPacketFeeAsync") + proto.RegisterType((*MsgPayPacketFeeAsyncResponse)(nil), "ibc.applications.fee.v1.MsgPayPacketFeeAsyncResponse") +} + +func init() { proto.RegisterFile("ibc/applications/fee/v1/tx.proto", fileDescriptor_05c93128649f1b96) } + +var fileDescriptor_05c93128649f1b96 = []byte{ + // 630 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4d, 0x4f, 0xdb, 0x40, + 0x10, 0x8d, 0x09, 0xa5, 0x64, 0x8b, 0x4a, 0xb3, 0x85, 0x62, 0x0c, 0xb5, 0xa9, 0x0f, 0x55, 0x2e, + 0xd8, 0xe5, 0x4b, 0x55, 0xb9, 0x20, 0x82, 0x84, 0xca, 0x01, 0x15, 0x59, 0x3d, 0x55, 0x95, 0x90, + 0xb3, 0x9e, 0x18, 0xb7, 0x89, 0xd7, 0xda, 0x75, 0xa2, 0xfa, 0x0f, 0x54, 0x3d, 0x72, 0xeb, 0x95, + 0x9f, 0xc3, 0xa9, 0xe2, 0xd0, 0x43, 0x4f, 0x56, 0x05, 0x97, 0x9e, 0xf3, 0x0b, 0xaa, 0xf5, 0x97, + 0x1c, 0x48, 0x22, 0xda, 0x9b, 0x77, 0xe6, 0xcd, 0xdb, 0x37, 0x6f, 0xc6, 0x8b, 0xd6, 0xbc, 0x16, + 0x31, 0xed, 0x20, 0xe8, 0x78, 0xc4, 0x0e, 0x3d, 0xea, 0x73, 0xb3, 0x0d, 0x60, 0xf6, 0x37, 0xcc, + 0xf0, 0x8b, 0x11, 0x30, 0x1a, 0x52, 0xbc, 0xe4, 0xb5, 0x88, 0x51, 0x46, 0x18, 0x6d, 0x00, 0xa3, + 0xbf, 0xa1, 0x2c, 0xb8, 0xd4, 0xa5, 0x09, 0xc6, 0x14, 0x5f, 0x29, 0x5c, 0x79, 0x31, 0x8e, 0x50, + 0x54, 0x95, 0x20, 0x84, 0x32, 0x30, 0xc9, 0x99, 0xed, 0xfb, 0xd0, 0x11, 0xe9, 0xec, 0x33, 0x85, + 0xe8, 0x3f, 0x24, 0xa4, 0x1e, 0x73, 0xd7, 0x02, 0xd7, 0xe3, 0x21, 0xb0, 0x03, 0xda, 0xf3, 0x43, + 0x60, 0x81, 0xcd, 0xc2, 0x68, 0xdf, 0x71, 0x18, 0x70, 0x8e, 0x65, 0xf4, 0xd0, 0x4e, 0x3f, 0x65, + 0x69, 0x4d, 0x6a, 0xd4, 0xac, 0xfc, 0x88, 0x2d, 0xb4, 0x40, 0x4a, 0x05, 0xa7, 0x39, 0x6c, 0x4a, + 0xc0, 0x9a, 0xda, 0x20, 0xd6, 0x56, 0x22, 0xbb, 0xdb, 0xd9, 0xd5, 0x47, 0xa1, 0x74, 0xeb, 0x29, + 0x19, 0x71, 0xdb, 0x36, 0x42, 0x99, 0xc2, 0x53, 0xcf, 0x91, 0xab, 0x09, 0xd3, 0xe2, 0x20, 0xd6, + 0xea, 0x19, 0x53, 0x91, 0xd3, 0xad, 0x5a, 0x76, 0x38, 0x72, 0x76, 0x67, 0xbf, 0x5d, 0x68, 0x95, + 0x3f, 0x17, 0x5a, 0x45, 0x6f, 0xa0, 0x97, 0x93, 0xfb, 0xb1, 0x80, 0x07, 0xd4, 0xe7, 0xa0, 0x9f, + 0x4f, 0xa1, 0xf9, 0x63, 0xee, 0x9e, 0xd8, 0xd1, 0x89, 0x4d, 0x3e, 0x43, 0x78, 0x08, 0x80, 0xb7, + 0x51, 0xb5, 0x0d, 0x90, 0xf4, 0xf9, 0x68, 0x73, 0xd5, 0x18, 0x33, 0x11, 0xe3, 0x10, 0xa0, 0x39, + 0x7d, 0x19, 0x6b, 0x15, 0x4b, 0xc0, 0xf1, 0x1e, 0x7a, 0xcc, 0x69, 0x8f, 0x11, 0x38, 0x0d, 0x28, + 0x0b, 0x85, 0xee, 0xd4, 0x81, 0xe5, 0x41, 0xac, 0x2d, 0xa6, 0xba, 0x87, 0xf3, 0xba, 0x35, 0x97, + 0x06, 0x4e, 0x28, 0x0b, 0x8f, 0x1c, 0xfc, 0x16, 0xd5, 0x33, 0xc0, 0x9d, 0xde, 0x57, 0x07, 0xb1, + 0x26, 0x0f, 0x71, 0x94, 0x2d, 0x98, 0x4f, 0x63, 0x07, 0xb9, 0x11, 0xf8, 0x19, 0x9a, 0xe1, 0x9e, + 0xeb, 0x03, 0x93, 0xa7, 0x93, 0x59, 0x65, 0x27, 0xac, 0xa0, 0x59, 0x06, 0x1d, 0x3b, 0x02, 0xc6, + 0xe5, 0x07, 0x6b, 0xd5, 0x46, 0xcd, 0x2a, 0xce, 0x25, 0xf3, 0x96, 0xd1, 0xd2, 0x2d, 0x47, 0x0a, + 0xb7, 0x7e, 0x4a, 0x68, 0xe1, 0x56, 0x6e, 0x9f, 0x47, 0x3e, 0xc1, 0xef, 0x51, 0x2d, 0x48, 0x22, + 0x42, 0x73, 0x6a, 0xdc, 0xf3, 0xc4, 0x38, 0xb1, 0x78, 0x46, 0xbe, 0x6d, 0xfd, 0x0d, 0x23, 0xad, + 0x3b, 0x72, 0x9a, 0xb2, 0x70, 0x6e, 0x10, 0x6b, 0x4f, 0xd2, 0xb6, 0x8a, 0x6a, 0xdd, 0x9a, 0x0d, + 0x32, 0x0c, 0xfe, 0x88, 0x50, 0x16, 0x17, 0xf3, 0x98, 0x4a, 0x68, 0xf5, 0xb1, 0xf3, 0x28, 0x24, + 0x35, 0x97, 0x33, 0xee, 0xfa, 0x10, 0x77, 0x1b, 0x40, 0xb7, 0x32, 0x99, 0x87, 0x00, 0xa5, 0x8e, + 0x55, 0xb4, 0x3a, 0xaa, 0xab, 0xbc, 0xed, 0xcd, 0xaf, 0x55, 0x54, 0x3d, 0xe6, 0x2e, 0xfe, 0x2e, + 0xa1, 0x95, 0x49, 0x3f, 0xc9, 0xeb, 0xb1, 0xda, 0x26, 0x6f, 0xa3, 0xb2, 0xf7, 0x9f, 0x85, 0xb9, + 0x42, 0xfc, 0x09, 0xcd, 0x0d, 0xad, 0x70, 0x63, 0x12, 0x61, 0x19, 0xa9, 0xbc, 0xba, 0x2f, 0xb2, + 0xb8, 0x2b, 0x42, 0xf5, 0xbb, 0x0b, 0xb0, 0x7e, 0x5f, 0x9a, 0x04, 0xae, 0xec, 0xfc, 0x13, 0x3c, + 0xbf, 0xba, 0xf9, 0xee, 0xf2, 0x5a, 0x95, 0xae, 0xae, 0x55, 0xe9, 0xf7, 0xb5, 0x2a, 0x9d, 0xdf, + 0xa8, 0x95, 0xab, 0x1b, 0xb5, 0xf2, 0xeb, 0x46, 0xad, 0x7c, 0xd8, 0x71, 0xbd, 0xf0, 0xac, 0xd7, + 0x32, 0x08, 0xed, 0x9a, 0x84, 0xf2, 0x2e, 0xe5, 0xa6, 0xd7, 0x22, 0xeb, 0x2e, 0x35, 0xfb, 0x5b, + 0x66, 0x97, 0x3a, 0xbd, 0x0e, 0x70, 0xf1, 0x50, 0x72, 0x73, 0xf3, 0xcd, 0xba, 0x78, 0x23, 0xc3, + 0x28, 0x00, 0xde, 0x9a, 0x49, 0x1e, 0xc0, 0xad, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xf7, + 0x58, 0xab, 0x99, 0x05, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress + // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their + // counterparty address before relaying. This ensures they will be properly compensated for forward relaying since + // destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function + // may be called more than once by a relayer, in which case, latest counterparty address is always used. + RegisterCounterpartyAddress(ctx context.Context, in *MsgRegisterCounterpartyAddress, opts ...grpc.CallOption) (*MsgRegisterCounterpartyAddressResponse, error) + // PayPacketFee defines a rpc handler method for MsgPayPacketFee + // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to + // incentivize the relaying of the packet at the next sequence + // NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows + // initiates the lifecycle of the incentivized packet + PayPacketFee(ctx context.Context, in *MsgPayPacketFee, opts ...grpc.CallOption) (*MsgPayPacketFeeResponse, error) + // PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync + // PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to + // incentivize the relaying of a known packet (i.e. at a particular sequence) + PayPacketFeeAsync(ctx context.Context, in *MsgPayPacketFeeAsync, opts ...grpc.CallOption) (*MsgPayPacketFeeAsyncResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) RegisterCounterpartyAddress(ctx context.Context, in *MsgRegisterCounterpartyAddress, opts ...grpc.CallOption) (*MsgRegisterCounterpartyAddressResponse, error) { + out := new(MsgRegisterCounterpartyAddressResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Msg/RegisterCounterpartyAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) PayPacketFee(ctx context.Context, in *MsgPayPacketFee, opts ...grpc.CallOption) (*MsgPayPacketFeeResponse, error) { + out := new(MsgPayPacketFeeResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Msg/PayPacketFee", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) PayPacketFeeAsync(ctx context.Context, in *MsgPayPacketFeeAsync, opts ...grpc.CallOption) (*MsgPayPacketFeeAsyncResponse, error) { + out := new(MsgPayPacketFeeAsyncResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Msg/PayPacketFeeAsync", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress + // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their + // counterparty address before relaying. This ensures they will be properly compensated for forward relaying since + // destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function + // may be called more than once by a relayer, in which case, latest counterparty address is always used. + RegisterCounterpartyAddress(context.Context, *MsgRegisterCounterpartyAddress) (*MsgRegisterCounterpartyAddressResponse, error) + // PayPacketFee defines a rpc handler method for MsgPayPacketFee + // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to + // incentivize the relaying of the packet at the next sequence + // NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows + // initiates the lifecycle of the incentivized packet + PayPacketFee(context.Context, *MsgPayPacketFee) (*MsgPayPacketFeeResponse, error) + // PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync + // PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to + // incentivize the relaying of a known packet (i.e. at a particular sequence) + PayPacketFeeAsync(context.Context, *MsgPayPacketFeeAsync) (*MsgPayPacketFeeAsyncResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) RegisterCounterpartyAddress(ctx context.Context, req *MsgRegisterCounterpartyAddress) (*MsgRegisterCounterpartyAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterCounterpartyAddress not implemented") +} +func (*UnimplementedMsgServer) PayPacketFee(ctx context.Context, req *MsgPayPacketFee) (*MsgPayPacketFeeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PayPacketFee not implemented") +} +func (*UnimplementedMsgServer) PayPacketFeeAsync(ctx context.Context, req *MsgPayPacketFeeAsync) (*MsgPayPacketFeeAsyncResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PayPacketFeeAsync not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_RegisterCounterpartyAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRegisterCounterpartyAddress) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RegisterCounterpartyAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Msg/RegisterCounterpartyAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RegisterCounterpartyAddress(ctx, req.(*MsgRegisterCounterpartyAddress)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_PayPacketFee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgPayPacketFee) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).PayPacketFee(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Msg/PayPacketFee", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).PayPacketFee(ctx, req.(*MsgPayPacketFee)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_PayPacketFeeAsync_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgPayPacketFeeAsync) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).PayPacketFeeAsync(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Msg/PayPacketFeeAsync", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).PayPacketFeeAsync(ctx, req.(*MsgPayPacketFeeAsync)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ibc.applications.fee.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "RegisterCounterpartyAddress", + Handler: _Msg_RegisterCounterpartyAddress_Handler, + }, + { + MethodName: "PayPacketFee", + Handler: _Msg_PayPacketFee_Handler, + }, + { + MethodName: "PayPacketFeeAsync", + Handler: _Msg_PayPacketFeeAsync_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ibc/applications/fee/v1/tx.proto", +} + +func (m *MsgRegisterCounterpartyAddress) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRegisterCounterpartyAddress) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterCounterpartyAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.CounterpartyAddress) > 0 { + i -= len(m.CounterpartyAddress) + copy(dAtA[i:], m.CounterpartyAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.CounterpartyAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRegisterCounterpartyAddressResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRegisterCounterpartyAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterCounterpartyAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgPayPacketFee) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgPayPacketFee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgPayPacketFee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Relayers) > 0 { + for iNdEx := len(m.Relayers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Relayers[iNdEx]) + copy(dAtA[i:], m.Relayers[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Relayers[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x22 + } + if len(m.SourceChannelId) > 0 { + i -= len(m.SourceChannelId) + copy(dAtA[i:], m.SourceChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.SourceChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.SourcePortId) > 0 { + i -= len(m.SourcePortId) + copy(dAtA[i:], m.SourcePortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.SourcePortId))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgPayPacketFeeResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgPayPacketFeeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgPayPacketFeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgPayPacketFeeAsync) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgPayPacketFeeAsync) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgPayPacketFeeAsync) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.PacketFee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.PacketId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *MsgPayPacketFeeAsyncResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgPayPacketFeeAsyncResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgPayPacketFeeAsyncResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgRegisterCounterpartyAddress) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.CounterpartyAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRegisterCounterpartyAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgPayPacketFee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Fee.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.SourcePortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.SourceChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Relayers) > 0 { + for _, s := range m.Relayers { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgPayPacketFeeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgPayPacketFeeAsync) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.PacketId.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.PacketFee.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgPayPacketFeeAsyncResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRegisterCounterpartyAddress: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterCounterpartyAddress: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CounterpartyAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRegisterCounterpartyAddressResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRegisterCounterpartyAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterCounterpartyAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgPayPacketFee) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgPayPacketFee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgPayPacketFee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourcePortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SourcePortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourceChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SourceChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Relayers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Relayers = append(m.Relayers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgPayPacketFeeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgPayPacketFeeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgPayPacketFeeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgPayPacketFeeAsync) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgPayPacketFeeAsync: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgPayPacketFeeAsync: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketId", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PacketId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PacketFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgPayPacketFeeAsyncResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgPayPacketFeeAsyncResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgPayPacketFeeAsyncResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 92d0f30d4c7..3dcb5518cbb 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -13,9 +13,10 @@ import ( func (suite *TransferTestSuite) TestOnChanOpenInit() { var ( - channel *channeltypes.Channel - path *ibctesting.Path - chanCap *capabilitytypes.Capability + channel *channeltypes.Channel + path *ibctesting.Path + chanCap *capabilitytypes.Capability + counterparty channeltypes.Counterparty ) testCases := []struct { @@ -64,7 +65,7 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { suite.coordinator.SetupConnections(path) path.EndpointA.ChannelID = ibctesting.FirstChannelID - counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + counterparty = channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) channel = &channeltypes.Channel{ State: channeltypes.INIT, Ordering: channeltypes.UNORDERED, @@ -85,7 +86,7 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { tc.malleate() // explicitly change fields in channel and testChannel err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, counterparty, channel.GetVersion(), ) if tc.expPass { @@ -103,6 +104,7 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { channel *channeltypes.Channel chanCap *capabilitytypes.Capability path *ibctesting.Path + counterparty channeltypes.Counterparty counterpartyVersion string ) @@ -153,7 +155,7 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { suite.coordinator.SetupConnections(path) path.EndpointA.ChannelID = ibctesting.FirstChannelID - counterparty := channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + counterparty = channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) channel = &channeltypes.Channel{ State: channeltypes.TRYOPEN, Ordering: channeltypes.UNORDERED, diff --git a/modules/core/04-channel/types/channel.pb.go b/modules/core/04-channel/types/channel.pb.go index 4ebbe01c977..3ce5ce3a2e1 100644 --- a/modules/core/04-channel/types/channel.pb.go +++ b/modules/core/04-channel/types/channel.pb.go @@ -347,6 +347,51 @@ func (m *PacketState) XXX_DiscardUnknown() { var xxx_messageInfo_PacketState proto.InternalMessageInfo +// PacketId is an identifer for a unique Packet +// Source chains refer to packets by source port/channel +// Destination chains refer to packets by destination port/channel +type PacketId struct { + // channel port identifier + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + // channel unique identifier + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + // packet sequence + Sequence uint64 `protobuf:"varint,3,opt,name=sequence,proto3" json:"sequence,omitempty"` +} + +func (m *PacketId) Reset() { *m = PacketId{} } +func (m *PacketId) String() string { return proto.CompactTextString(m) } +func (*PacketId) ProtoMessage() {} +func (*PacketId) Descriptor() ([]byte, []int) { + return fileDescriptor_c3a07336710636a0, []int{5} +} +func (m *PacketId) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PacketId) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PacketId.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PacketId) XXX_Merge(src proto.Message) { + xxx_messageInfo_PacketId.Merge(m, src) +} +func (m *PacketId) XXX_Size() int { + return m.Size() +} +func (m *PacketId) XXX_DiscardUnknown() { + xxx_messageInfo_PacketId.DiscardUnknown(m) +} + +var xxx_messageInfo_PacketId proto.InternalMessageInfo + // Acknowledgement is the recommended acknowledgement format to be used by // app-specific protocols. // NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental @@ -367,7 +412,7 @@ func (m *Acknowledgement) Reset() { *m = Acknowledgement{} } func (m *Acknowledgement) String() string { return proto.CompactTextString(m) } func (*Acknowledgement) ProtoMessage() {} func (*Acknowledgement) Descriptor() ([]byte, []int) { - return fileDescriptor_c3a07336710636a0, []int{5} + return fileDescriptor_c3a07336710636a0, []int{6} } func (m *Acknowledgement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -449,70 +494,72 @@ func init() { proto.RegisterType((*Counterparty)(nil), "ibc.core.channel.v1.Counterparty") proto.RegisterType((*Packet)(nil), "ibc.core.channel.v1.Packet") proto.RegisterType((*PacketState)(nil), "ibc.core.channel.v1.PacketState") + proto.RegisterType((*PacketId)(nil), "ibc.core.channel.v1.PacketId") proto.RegisterType((*Acknowledgement)(nil), "ibc.core.channel.v1.Acknowledgement") } func init() { proto.RegisterFile("ibc/core/channel/v1/channel.proto", fileDescriptor_c3a07336710636a0) } var fileDescriptor_c3a07336710636a0 = []byte{ - // 911 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x55, 0xcd, 0x8e, 0xda, 0x56, - 0x14, 0xc6, 0x83, 0xf9, 0x3b, 0x0c, 0x0c, 0x73, 0xd3, 0x21, 0xae, 0x9b, 0x60, 0x62, 0x75, 0x31, - 0x4a, 0x15, 0xc8, 0x24, 0x51, 0xab, 0x66, 0xd5, 0xe1, 0x27, 0x1a, 0xab, 0x11, 0x8c, 0x0c, 0xb3, - 0x68, 0x36, 0x14, 0xec, 0x5b, 0xb0, 0x02, 0xbe, 0xd4, 0xbe, 0x30, 0x9a, 0x37, 0x88, 0x58, 0xf5, - 0x05, 0x90, 0x2a, 0x55, 0xed, 0x2b, 0xf4, 0x15, 0xb2, 0xcc, 0xb2, 0x2b, 0xab, 0x9a, 0x59, 0x74, - 0xcf, 0x0b, 0xb4, 0xf2, 0xbd, 0xd7, 0xfc, 0x4c, 0xa2, 0x2c, 0xbb, 0xca, 0x8a, 0x7b, 0xbe, 0xef, - 0x3b, 0x3f, 0x3e, 0xe7, 0x70, 0x2f, 0x3c, 0x70, 0x06, 0x56, 0xd5, 0x22, 0x1e, 0xae, 0x5a, 0xa3, - 0xbe, 0xeb, 0xe2, 0x71, 0x75, 0x7e, 0x12, 0x1d, 0x2b, 0x53, 0x8f, 0x50, 0x82, 0xee, 0x38, 0x03, - 0xab, 0x12, 0x4a, 0x2a, 0x11, 0x3e, 0x3f, 0x51, 0x3f, 0x1b, 0x92, 0x21, 0x61, 0x7c, 0x35, 0x3c, - 0x71, 0xa9, 0xaa, 0x6d, 0xa2, 0x8d, 0x1d, 0xec, 0x52, 0x16, 0x8c, 0x9d, 0xb8, 0x40, 0xff, 0x7d, - 0x0f, 0x52, 0x75, 0x1e, 0x05, 0x3d, 0x86, 0x84, 0x4f, 0xfb, 0x14, 0x2b, 0x52, 0x59, 0x3a, 0xce, - 0x3f, 0x51, 0x2b, 0x1f, 0xc8, 0x53, 0xe9, 0x84, 0x0a, 0x93, 0x0b, 0xd1, 0xd7, 0x90, 0x26, 0x9e, - 0x8d, 0x3d, 0xc7, 0x1d, 0x2a, 0x7b, 0x1f, 0x71, 0x6a, 0x87, 0x22, 0x73, 0xad, 0x45, 0xdf, 0xc3, - 0xbe, 0x45, 0x66, 0x2e, 0xc5, 0xde, 0xb4, 0xef, 0xd1, 0x2b, 0x25, 0x5e, 0x96, 0x8e, 0xb3, 0x4f, - 0x1e, 0x7c, 0xd0, 0xb7, 0xbe, 0x25, 0xac, 0xc9, 0x6f, 0x03, 0x2d, 0x66, 0xee, 0x38, 0xa3, 0x3a, - 0x1c, 0x58, 0xc4, 0x75, 0xb1, 0x45, 0x1d, 0xe2, 0xf6, 0x46, 0x64, 0xea, 0x2b, 0x72, 0x39, 0x7e, - 0x9c, 0xa9, 0xa9, 0xab, 0x40, 0x2b, 0x5e, 0xf5, 0x27, 0xe3, 0xe7, 0xfa, 0x2d, 0x81, 0x6e, 0xe6, - 0x37, 0xc8, 0x19, 0x99, 0xfa, 0x48, 0x81, 0xd4, 0x1c, 0x7b, 0xbe, 0x43, 0x5c, 0x25, 0x51, 0x96, - 0x8e, 0x33, 0x66, 0x64, 0x3e, 0x97, 0xdf, 0xfc, 0xaa, 0xc5, 0xf4, 0x7f, 0xf6, 0xe0, 0xd0, 0xb0, - 0xb1, 0x4b, 0x9d, 0x9f, 0x1c, 0x6c, 0x7f, 0xea, 0xd8, 0x47, 0x3a, 0x86, 0xee, 0x42, 0x6a, 0x4a, - 0x3c, 0xda, 0x73, 0x6c, 0x25, 0xc9, 0x98, 0x64, 0x68, 0x1a, 0x36, 0xba, 0x0f, 0x20, 0xca, 0x0c, - 0xb9, 0x14, 0xe3, 0x32, 0x02, 0x31, 0x6c, 0xd1, 0xe9, 0x4b, 0xd8, 0xdf, 0xfe, 0x00, 0xf4, 0xd5, - 0x26, 0x5a, 0xd8, 0xe5, 0x4c, 0x0d, 0xad, 0x02, 0x2d, 0xcf, 0x8b, 0x14, 0x84, 0xbe, 0xce, 0xf0, - 0x6c, 0x27, 0xc3, 0x1e, 0xd3, 0x1f, 0xad, 0x02, 0xed, 0x50, 0x7c, 0xd4, 0x9a, 0xd3, 0xdf, 0x4f, - 0xfc, 0x6f, 0x1c, 0x92, 0xe7, 0x7d, 0xeb, 0x35, 0xa6, 0x48, 0x85, 0xb4, 0x8f, 0x7f, 0x9e, 0x61, - 0xd7, 0xe2, 0xa3, 0x95, 0xcd, 0xb5, 0x8d, 0xbe, 0x81, 0xac, 0x4f, 0x66, 0x9e, 0x85, 0x7b, 0x61, - 0x4e, 0x91, 0xa3, 0xb8, 0x0a, 0x34, 0xc4, 0x73, 0x6c, 0x91, 0xba, 0x09, 0xdc, 0x3a, 0x27, 0x1e, - 0x45, 0xdf, 0x41, 0x5e, 0x70, 0x22, 0x33, 0x1b, 0x62, 0xa6, 0xf6, 0xf9, 0x2a, 0xd0, 0x8e, 0x76, - 0x7c, 0x05, 0xaf, 0x9b, 0x39, 0x0e, 0x44, 0xeb, 0xf6, 0x02, 0x0a, 0x36, 0xf6, 0xa9, 0xe3, 0xf6, - 0xd9, 0x5c, 0x58, 0x7e, 0x99, 0xc5, 0xf8, 0x62, 0x15, 0x68, 0x77, 0x79, 0x8c, 0xdb, 0x0a, 0xdd, - 0x3c, 0xd8, 0x82, 0x58, 0x25, 0x6d, 0xb8, 0xb3, 0xad, 0x8a, 0xca, 0x61, 0x63, 0xac, 0x95, 0x56, - 0x81, 0xa6, 0xbe, 0x1f, 0x6a, 0x5d, 0x13, 0xda, 0x42, 0xa3, 0xc2, 0x10, 0xc8, 0x76, 0x9f, 0xf6, - 0xd9, 0xb8, 0xf7, 0x4d, 0x76, 0x46, 0x3f, 0x42, 0x9e, 0x3a, 0x13, 0x4c, 0x66, 0xb4, 0x37, 0xc2, - 0xce, 0x70, 0x44, 0xd9, 0xc0, 0xb3, 0x3b, 0xfb, 0xce, 0x6f, 0xa2, 0xf9, 0x49, 0xe5, 0x8c, 0x29, - 0x6a, 0xf7, 0xc3, 0x65, 0xdd, 0xb4, 0x63, 0xd7, 0x5f, 0x37, 0x73, 0x02, 0xe0, 0x6a, 0x64, 0xc0, - 0x61, 0xa4, 0x08, 0x7f, 0x7d, 0xda, 0x9f, 0x4c, 0x95, 0x74, 0x38, 0xae, 0xda, 0xbd, 0x55, 0xa0, - 0x29, 0xbb, 0x41, 0xd6, 0x12, 0xdd, 0x2c, 0x08, 0xac, 0x1b, 0x41, 0x62, 0x03, 0xfe, 0x90, 0x20, - 0xcb, 0x37, 0x80, 0xfd, 0x67, 0xff, 0x87, 0xd5, 0xdb, 0xd9, 0xb4, 0xf8, 0xad, 0x4d, 0x8b, 0xba, - 0x2a, 0x6f, 0xba, 0x2a, 0x0a, 0x6d, 0xc3, 0xc1, 0xa9, 0xf5, 0xda, 0x25, 0x97, 0x63, 0x6c, 0x0f, - 0xf1, 0x04, 0xbb, 0x14, 0x29, 0x90, 0xf4, 0xb0, 0x3f, 0x1b, 0x53, 0xe5, 0x28, 0x94, 0x9f, 0xc5, - 0x4c, 0x61, 0xa3, 0x22, 0x24, 0xb0, 0xe7, 0x11, 0x4f, 0x29, 0x86, 0x35, 0x9d, 0xc5, 0x4c, 0x6e, - 0xd6, 0x00, 0xd2, 0x1e, 0xf6, 0xa7, 0xc4, 0xf5, 0xf1, 0xc3, 0x3f, 0x25, 0x48, 0x74, 0xc4, 0x05, - 0xa5, 0x75, 0xba, 0xa7, 0xdd, 0x66, 0xef, 0xa2, 0x65, 0xb4, 0x8c, 0xae, 0x71, 0xfa, 0xd2, 0x78, - 0xd5, 0x6c, 0xf4, 0x2e, 0x5a, 0x9d, 0xf3, 0x66, 0xdd, 0x78, 0x61, 0x34, 0x1b, 0x85, 0x98, 0x7a, - 0xb8, 0x58, 0x96, 0x73, 0x3b, 0x02, 0xa4, 0x00, 0x70, 0xbf, 0x10, 0x2c, 0x48, 0x6a, 0x7a, 0xb1, - 0x2c, 0xcb, 0xe1, 0x19, 0x95, 0x20, 0xc7, 0x99, 0xae, 0xf9, 0x43, 0xfb, 0xbc, 0xd9, 0x2a, 0xec, - 0xa9, 0xd9, 0xc5, 0xb2, 0x9c, 0x12, 0xe6, 0xc6, 0x93, 0x91, 0x71, 0xee, 0xc9, 0x98, 0x7b, 0xb0, - 0xcf, 0x99, 0xfa, 0xcb, 0x76, 0xa7, 0xd9, 0x28, 0xc8, 0x2a, 0x2c, 0x96, 0xe5, 0x24, 0xb7, 0x54, - 0xf9, 0xcd, 0x6f, 0xa5, 0xd8, 0xc3, 0x4b, 0x48, 0xb0, 0xbb, 0x12, 0x7d, 0x09, 0xc5, 0xb6, 0xd9, - 0x68, 0x9a, 0xbd, 0x56, 0xbb, 0xd5, 0xbc, 0x55, 0x2f, 0x0b, 0x19, 0xe2, 0x48, 0x87, 0x03, 0xae, - 0xba, 0x68, 0xb1, 0xdf, 0x66, 0xa3, 0x20, 0xa9, 0xb9, 0xc5, 0xb2, 0x9c, 0x59, 0x03, 0x61, 0xc1, - 0x5c, 0x13, 0x29, 0x44, 0xc1, 0xc2, 0xe4, 0x89, 0x6b, 0x9d, 0xb7, 0xd7, 0x25, 0xe9, 0xdd, 0x75, - 0x49, 0xfa, 0xfb, 0xba, 0x24, 0xfd, 0x72, 0x53, 0x8a, 0xbd, 0xbb, 0x29, 0xc5, 0xfe, 0xba, 0x29, - 0xc5, 0x5e, 0x7d, 0x3b, 0x74, 0xe8, 0x68, 0x36, 0xa8, 0x58, 0x64, 0x52, 0xb5, 0x88, 0x3f, 0x21, - 0x7e, 0xd5, 0x19, 0x58, 0x8f, 0x86, 0xa4, 0x3a, 0x7f, 0x5a, 0x9d, 0x10, 0x7b, 0x36, 0xc6, 0x3e, - 0x7f, 0x94, 0x1f, 0x3f, 0x7b, 0x14, 0xbd, 0xf2, 0xf4, 0x6a, 0x8a, 0xfd, 0x41, 0x92, 0xbd, 0xca, - 0x4f, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xa8, 0x31, 0x31, 0xe5, 0x06, 0x08, 0x00, 0x00, + // 925 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xcd, 0x8e, 0x1a, 0x47, + 0x10, 0x66, 0x60, 0xf8, 0x2b, 0x16, 0x96, 0x6d, 0x67, 0xf1, 0x64, 0x62, 0x33, 0x78, 0x94, 0xc3, + 0xca, 0x91, 0xc1, 0x6b, 0x5b, 0x89, 0xe2, 0x53, 0x96, 0x1f, 0x6b, 0x47, 0xb1, 0x60, 0x35, 0xb0, + 0x87, 0xf8, 0x42, 0x60, 0xa6, 0x03, 0x23, 0xc3, 0x34, 0x99, 0x69, 0x58, 0xed, 0x1b, 0x58, 0x5c, + 0x92, 0x17, 0x40, 0x8a, 0x14, 0x25, 0xaf, 0x90, 0x57, 0xf0, 0xd1, 0xc7, 0x9c, 0x50, 0xb4, 0x7b, + 0xc8, 0x9d, 0x17, 0x48, 0x34, 0xdd, 0x3d, 0xfc, 0xac, 0xad, 0x3d, 0x26, 0x17, 0x9f, 0xe8, 0xaa, + 0xef, 0xab, 0xaa, 0x6f, 0xaa, 0x8a, 0x56, 0xc3, 0x03, 0xa7, 0x6f, 0x55, 0x2c, 0xe2, 0xe1, 0x8a, + 0x35, 0xec, 0xb9, 0x2e, 0x1e, 0x55, 0x66, 0xc7, 0xe1, 0xb1, 0x3c, 0xf1, 0x08, 0x25, 0xe8, 0x8e, + 0xd3, 0xb7, 0xca, 0x01, 0xa5, 0x1c, 0xfa, 0x67, 0xc7, 0xea, 0x27, 0x03, 0x32, 0x20, 0x0c, 0xaf, + 0x04, 0x27, 0x4e, 0x55, 0xb5, 0x4d, 0xb6, 0x91, 0x83, 0x5d, 0xca, 0x92, 0xb1, 0x13, 0x27, 0xe8, + 0xbf, 0x45, 0x21, 0x59, 0xe3, 0x59, 0xd0, 0x63, 0x88, 0xfb, 0xb4, 0x47, 0xb1, 0x22, 0x95, 0xa4, + 0xa3, 0xdc, 0x13, 0xb5, 0xfc, 0x81, 0x3a, 0xe5, 0x76, 0xc0, 0x30, 0x39, 0x11, 0x7d, 0x09, 0x29, + 0xe2, 0xd9, 0xd8, 0x73, 0xdc, 0x81, 0x12, 0xbd, 0x25, 0xa8, 0x15, 0x90, 0xcc, 0x35, 0x17, 0x7d, + 0x0b, 0x7b, 0x16, 0x99, 0xba, 0x14, 0x7b, 0x93, 0x9e, 0x47, 0x2f, 0x95, 0x58, 0x49, 0x3a, 0xca, + 0x3c, 0x79, 0xf0, 0xc1, 0xd8, 0xda, 0x16, 0xb1, 0x2a, 0xbf, 0x5d, 0x6a, 0x11, 0x73, 0x27, 0x18, + 0xd5, 0x60, 0xdf, 0x22, 0xae, 0x8b, 0x2d, 0xea, 0x10, 0xb7, 0x3b, 0x24, 0x13, 0x5f, 0x91, 0x4b, + 0xb1, 0xa3, 0x74, 0x55, 0x5d, 0x2d, 0xb5, 0xc2, 0x65, 0x6f, 0x3c, 0x7a, 0xae, 0xdf, 0x20, 0xe8, + 0x66, 0x6e, 0xe3, 0x39, 0x25, 0x13, 0x1f, 0x29, 0x90, 0x9c, 0x61, 0xcf, 0x77, 0x88, 0xab, 0xc4, + 0x4b, 0xd2, 0x51, 0xda, 0x0c, 0xcd, 0xe7, 0xf2, 0x9b, 0x5f, 0xb4, 0x88, 0xfe, 0x77, 0x14, 0x0e, + 0x0c, 0x1b, 0xbb, 0xd4, 0xf9, 0xc1, 0xc1, 0xf6, 0xc7, 0x8e, 0xdd, 0xd2, 0x31, 0x74, 0x17, 0x92, + 0x13, 0xe2, 0xd1, 0xae, 0x63, 0x2b, 0x09, 0x86, 0x24, 0x02, 0xd3, 0xb0, 0xd1, 0x7d, 0x00, 0x21, + 0x33, 0xc0, 0x92, 0x0c, 0x4b, 0x0b, 0x8f, 0x61, 0x8b, 0x4e, 0x5f, 0xc0, 0xde, 0xf6, 0x07, 0xa0, + 0x2f, 0x36, 0xd9, 0x82, 0x2e, 0xa7, 0xab, 0x68, 0xb5, 0xd4, 0x72, 0x5c, 0xa4, 0x00, 0xf4, 0x75, + 0x85, 0x67, 0x3b, 0x15, 0xa2, 0x8c, 0x7f, 0xb8, 0x5a, 0x6a, 0x07, 0xe2, 0xa3, 0xd6, 0x98, 0xfe, + 0x7e, 0xe1, 0x7f, 0x62, 0x90, 0x38, 0xeb, 0x59, 0xaf, 0x31, 0x45, 0x2a, 0xa4, 0x7c, 0xfc, 0xe3, + 0x14, 0xbb, 0x16, 0x1f, 0xad, 0x6c, 0xae, 0x6d, 0xf4, 0x15, 0x64, 0x7c, 0x32, 0xf5, 0x2c, 0xdc, + 0x0d, 0x6a, 0x8a, 0x1a, 0x85, 0xd5, 0x52, 0x43, 0xbc, 0xc6, 0x16, 0xa8, 0x9b, 0xc0, 0xad, 0x33, + 0xe2, 0x51, 0xf4, 0x0d, 0xe4, 0x04, 0x26, 0x2a, 0xb3, 0x21, 0xa6, 0xab, 0x9f, 0xae, 0x96, 0xda, + 0xe1, 0x4e, 0xac, 0xc0, 0x75, 0x33, 0xcb, 0x1d, 0xe1, 0xba, 0xbd, 0x80, 0xbc, 0x8d, 0x7d, 0xea, + 0xb8, 0x3d, 0x36, 0x17, 0x56, 0x5f, 0x66, 0x39, 0x3e, 0x5b, 0x2d, 0xb5, 0xbb, 0x3c, 0xc7, 0x4d, + 0x86, 0x6e, 0xee, 0x6f, 0xb9, 0x98, 0x92, 0x16, 0xdc, 0xd9, 0x66, 0x85, 0x72, 0xd8, 0x18, 0xab, + 0xc5, 0xd5, 0x52, 0x53, 0xdf, 0x4f, 0xb5, 0xd6, 0x84, 0xb6, 0xbc, 0xa1, 0x30, 0x04, 0xb2, 0xdd, + 0xa3, 0x3d, 0x36, 0xee, 0x3d, 0x93, 0x9d, 0xd1, 0xf7, 0x90, 0xa3, 0xce, 0x18, 0x93, 0x29, 0xed, + 0x0e, 0xb1, 0x33, 0x18, 0x52, 0x36, 0xf0, 0xcc, 0xce, 0xbe, 0xf3, 0x9b, 0x68, 0x76, 0x5c, 0x3e, + 0x65, 0x8c, 0xea, 0xfd, 0x60, 0x59, 0x37, 0xed, 0xd8, 0x8d, 0xd7, 0xcd, 0xac, 0x70, 0x70, 0x36, + 0x32, 0xe0, 0x20, 0x64, 0x04, 0xbf, 0x3e, 0xed, 0x8d, 0x27, 0x4a, 0x2a, 0x18, 0x57, 0xf5, 0xde, + 0x6a, 0xa9, 0x29, 0xbb, 0x49, 0xd6, 0x14, 0xdd, 0xcc, 0x0b, 0x5f, 0x27, 0x74, 0x89, 0x0d, 0xf8, + 0x5d, 0x82, 0x0c, 0xdf, 0x00, 0xf6, 0x9f, 0xfd, 0x0f, 0x56, 0x6f, 0x67, 0xd3, 0x62, 0x37, 0x36, + 0x2d, 0xec, 0xaa, 0xbc, 0xe9, 0xaa, 0x10, 0xfa, 0x93, 0x04, 0x29, 0x2e, 0xd4, 0xb0, 0xff, 0x67, + 0x95, 0x42, 0x51, 0x0b, 0xf6, 0x4f, 0xac, 0xd7, 0x2e, 0xb9, 0x18, 0x61, 0x7b, 0x80, 0xc7, 0xd8, + 0xa5, 0x48, 0x81, 0x84, 0x87, 0xfd, 0xe9, 0x88, 0x2a, 0x87, 0xc1, 0x07, 0x9c, 0x46, 0x4c, 0x61, + 0xa3, 0x02, 0xc4, 0xb1, 0xe7, 0x11, 0x4f, 0x29, 0x04, 0xf5, 0x4f, 0x23, 0x26, 0x37, 0xab, 0x00, + 0x29, 0x0f, 0xfb, 0x13, 0xe2, 0xfa, 0xf8, 0xe1, 0x1f, 0x12, 0xc4, 0xdb, 0xe2, 0xca, 0xd4, 0xda, + 0x9d, 0x93, 0x4e, 0xa3, 0x7b, 0xde, 0x34, 0x9a, 0x46, 0xc7, 0x38, 0x79, 0x69, 0xbc, 0x6a, 0xd4, + 0xbb, 0xe7, 0xcd, 0xf6, 0x59, 0xa3, 0x66, 0xbc, 0x30, 0x1a, 0xf5, 0x7c, 0x44, 0x3d, 0x98, 0x2f, + 0x4a, 0xd9, 0x1d, 0x02, 0x52, 0x00, 0x78, 0x5c, 0xe0, 0xcc, 0x4b, 0x6a, 0x6a, 0xbe, 0x28, 0xc9, + 0xc1, 0x19, 0x15, 0x21, 0xcb, 0x91, 0x8e, 0xf9, 0x5d, 0xeb, 0xac, 0xd1, 0xcc, 0x47, 0xd5, 0xcc, + 0x7c, 0x51, 0x4a, 0x0a, 0x73, 0x13, 0xc9, 0xc0, 0x18, 0x8f, 0x64, 0xc8, 0x3d, 0xd8, 0xe3, 0x48, + 0xed, 0x65, 0xab, 0xdd, 0xa8, 0xe7, 0x65, 0x15, 0xe6, 0x8b, 0x52, 0x82, 0x5b, 0xaa, 0xfc, 0xe6, + 0xd7, 0x62, 0xe4, 0xe1, 0x05, 0xc4, 0xd9, 0xed, 0x8d, 0x3e, 0x87, 0x42, 0xcb, 0xac, 0x37, 0xcc, + 0x6e, 0xb3, 0xd5, 0x6c, 0xdc, 0xd0, 0xcb, 0x52, 0x06, 0x7e, 0xa4, 0xc3, 0x3e, 0x67, 0x9d, 0x37, + 0xd9, 0x6f, 0xa3, 0x9e, 0x97, 0xd4, 0xec, 0x7c, 0x51, 0x4a, 0xaf, 0x1d, 0x81, 0x60, 0xce, 0x09, + 0x19, 0x42, 0xb0, 0x30, 0x79, 0xe1, 0x6a, 0xfb, 0xed, 0x55, 0x51, 0x7a, 0x77, 0x55, 0x94, 0xfe, + 0xba, 0x2a, 0x4a, 0x3f, 0x5f, 0x17, 0x23, 0xef, 0xae, 0x8b, 0x91, 0x3f, 0xaf, 0x8b, 0x91, 0x57, + 0x5f, 0x0f, 0x1c, 0x3a, 0x9c, 0xf6, 0xcb, 0x16, 0x19, 0x57, 0x2c, 0xe2, 0x8f, 0x89, 0x5f, 0x71, + 0xfa, 0xd6, 0xa3, 0x01, 0xa9, 0xcc, 0x9e, 0x56, 0xc6, 0xc4, 0x9e, 0x8e, 0xb0, 0xcf, 0x9f, 0x09, + 0x8f, 0x9f, 0x3d, 0x0a, 0xdf, 0x1d, 0xf4, 0x72, 0x82, 0xfd, 0x7e, 0x82, 0xbd, 0x13, 0x9e, 0xfe, + 0x1b, 0x00, 0x00, 0xff, 0xff, 0x47, 0xf5, 0x82, 0xa6, 0x98, 0x08, 0x00, 0x00, } func (m *Channel) Marshal() (dAtA []byte, err error) { @@ -811,6 +858,48 @@ func (m *PacketState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *PacketId) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PacketId) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PacketId) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sequence != 0 { + i = encodeVarintChannel(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x18 + } + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintChannel(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintChannel(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Acknowledgement) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1028,6 +1117,26 @@ func (m *PacketState) Size() (n int) { return n } +func (m *PacketId) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovChannel(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovChannel(uint64(l)) + } + if m.Sequence != 0 { + n += 1 + sovChannel(uint64(m.Sequence)) + } + return n +} + func (m *Acknowledgement) Size() (n int) { if m == nil { return 0 @@ -2067,6 +2176,139 @@ func (m *PacketState) Unmarshal(dAtA []byte) error { } return nil } +func (m *PacketId) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChannel + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PacketId: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PacketId: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChannel + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthChannel + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthChannel + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChannel + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthChannel + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthChannel + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) + } + m.Sequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowChannel + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipChannel(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthChannel + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Acknowledgement) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/core/04-channel/types/packet.go b/modules/core/04-channel/types/packet.go index 0df4d8edd8d..1b69dafa758 100644 --- a/modules/core/04-channel/types/packet.go +++ b/modules/core/04-channel/types/packet.go @@ -12,6 +12,11 @@ import ( "github.com/cosmos/ibc-go/v3/modules/core/exported" ) +// NewPacketId returns a new instance of PacketId +func NewPacketId(channelId, portId string, seq uint64) PacketId { + return PacketId{ChannelId: channelId, PortId: portId, Sequence: seq} +} + // CommitPacket returns the packet commitment bytes. The commitment consists of: // sha256_hash(timeout_timestamp + timeout_height.RevisionNumber + timeout_height.RevisionHeight + sha256_hash(data)) // from a given packet. This results in a fixed length preimage. @@ -111,3 +116,20 @@ func (p Packet) ValidateBasic() error { } return nil } + +// Validates a PacketId +func (p PacketId) Validate() error { + if err := host.PortIdentifierValidator(p.PortId); err != nil { + return sdkerrors.Wrap(err, "invalid source port ID") + } + + if err := host.ChannelIdentifierValidator(p.ChannelId); err != nil { + return sdkerrors.Wrap(err, "invalid source channel ID") + } + + if p.Sequence == 0 { + return sdkerrors.Wrap(ErrInvalidPacket, "packet sequence cannot be 0") + } + + return nil +} diff --git a/modules/core/04-channel/types/version.go b/modules/core/04-channel/types/version.go index 15477635e7f..a2696d291ed 100644 --- a/modules/core/04-channel/types/version.go +++ b/modules/core/04-channel/types/version.go @@ -4,7 +4,7 @@ import "strings" const ChannelVersionDelimiter = ":" -// SplitChannelVersion splits the channel version string +// SplitChannelVersion middleware version will split the channel version string // into the outermost middleware version and the underlying app version. // It will use the default delimiter `:` for middleware versions. // In case there's no delimeter, this function returns an empty string for the middleware version (first return argument), diff --git a/proto/ibc/applications/fee/v1/ack.proto b/proto/ibc/applications/fee/v1/ack.proto new file mode 100644 index 00000000000..728c7536c6b --- /dev/null +++ b/proto/ibc/applications/fee/v1/ack.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; + +import "gogoproto/gogo.proto"; + +// IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware +message IncentivizedAcknowledgement { + // the underlying app acknowledgement result bytes + bytes result = 1; + // the relayer address which submits the recv packet message + string forward_relayer_address = 2 [(gogoproto.moretags) = "yaml:\"forward_relayer_address\""]; + // success flag of the base application callback + bool underlying_app_success = 3 [(gogoproto.moretags) = "yaml:\"underlying_app_successl\""]; +} diff --git a/proto/ibc/applications/fee/v1/fee.proto b/proto/ibc/applications/fee/v1/fee.proto new file mode 100644 index 00000000000..e7a1fa438df --- /dev/null +++ b/proto/ibc/applications/fee/v1/fee.proto @@ -0,0 +1,56 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; + +import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// Fee defines the ICS29 receive, acknowledgement and timeout fees +message Fee { + // the packet receive fee + repeated cosmos.base.v1beta1.Coin recv_fee = 1 [ + (gogoproto.moretags) = "yaml:\"recv_fee\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + // the packet acknowledgement fee + repeated cosmos.base.v1beta1.Coin ack_fee = 2 [ + (gogoproto.moretags) = "yaml:\"ack_fee\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + // the packet timeout fee + repeated cosmos.base.v1beta1.Coin timeout_fee = 3 [ + (gogoproto.moretags) = "yaml:\"timeout_fee\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers +message PacketFee { + // fee encapsulates the recv, ack and timeout fees associated with an IBC packet + Fee fee = 1 [(gogoproto.nullable) = false]; + // the refund address for unspent fees + string refund_address = 2 [(gogoproto.moretags) = "yaml:\"refund_address\""]; + // optional list of relayers permitted to receive fees + repeated string relayers = 3; +} + +// PacketFees contains a list of type PacketFee +message PacketFees { + // list of packet fees + repeated PacketFee packet_fees = 1 [(gogoproto.moretags) = "yaml:\"packet_fees\"", (gogoproto.nullable) = false]; +} + +// IdentifiedPacketFees contains a list of type PacketFee and associated PacketId +message IdentifiedPacketFees { + // unique packet identifier comprised of the channel ID, port ID and sequence + ibc.core.channel.v1.PacketId packet_id = 1 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"packet_id\""]; + // list of packet fees + repeated PacketFee packet_fees = 2 [(gogoproto.moretags) = "yaml:\"packet_fees\"", (gogoproto.nullable) = false]; +} diff --git a/proto/ibc/applications/fee/v1/genesis.proto b/proto/ibc/applications/fee/v1/genesis.proto new file mode 100644 index 00000000000..cae132239d6 --- /dev/null +++ b/proto/ibc/applications/fee/v1/genesis.proto @@ -0,0 +1,52 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; + +import "gogoproto/gogo.proto"; +import "ibc/applications/fee/v1/fee.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// GenesisState defines the ICS29 fee middleware genesis state +message GenesisState { + // list of identified packet fees + repeated IdentifiedPacketFees identified_fees = 1 + [(gogoproto.moretags) = "yaml:\"identified_fees\"", (gogoproto.nullable) = false]; + // list of fee enabled channels + repeated FeeEnabledChannel fee_enabled_channels = 2 + [(gogoproto.moretags) = "yaml:\"fee_enabled_channels\"", (gogoproto.nullable) = false]; + // list of registered relayer addresses + repeated RegisteredRelayerAddress registered_relayers = 3 + [(gogoproto.moretags) = "yaml:\"registered_relayers\"", (gogoproto.nullable) = false]; + // list of forward relayer addresses + repeated ForwardRelayerAddress forward_relayers = 4 + [(gogoproto.moretags) = "yaml:\"forward_relayers\"", (gogoproto.nullable) = false]; +} + +// FeeEnabledChannel contains the PortID & ChannelID for a fee enabled channel +message FeeEnabledChannel { + // unique port identifier + string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + // unique channel identifier + string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; +} + +// RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) +message RegisteredRelayerAddress { + // the relayer address + string address = 1; + // the counterparty relayer address + string counterparty_address = 2 [(gogoproto.moretags) = "yaml:\"counterparty_address\""]; + // unique channel identifier + string channel_id = 3 [(gogoproto.moretags) = "yaml:\"channel_id\""]; +} + +// ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements +message ForwardRelayerAddress { + // the forward relayer address + string address = 1; + // unique packet identifer comprised of the channel ID, port ID and sequence + ibc.core.channel.v1.PacketId packet_id = 2 + [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"packet_id\""]; +} diff --git a/proto/ibc/applications/fee/v1/metadata.proto b/proto/ibc/applications/fee/v1/metadata.proto new file mode 100644 index 00000000000..0afb3e09b2e --- /dev/null +++ b/proto/ibc/applications/fee/v1/metadata.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; + +import "gogoproto/gogo.proto"; + +// Metadata defines the ICS29 channel specific metadata encoded into the channel version bytestring +// See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning +message Metadata { + // fee_version defines the ICS29 fee version + string fee_version = 1 [(gogoproto.moretags) = "yaml:\"fee_version\""]; + // app_version defines the underlying application version, which may or may not be a JSON encoded bytestring + string app_version = 2 [(gogoproto.moretags) = "yaml:\"app_version\""]; +} diff --git a/proto/ibc/applications/fee/v1/query.proto b/proto/ibc/applications/fee/v1/query.proto new file mode 100644 index 00000000000..3e5d6b8740d --- /dev/null +++ b/proto/ibc/applications/fee/v1/query.proto @@ -0,0 +1,144 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "ibc/applications/fee/v1/fee.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// Query defines the ICS29 gRPC querier service. +service Query { + // IncentivizedPackets returns all incentivized packets and their associated fees + rpc IncentivizedPackets(QueryIncentivizedPacketsRequest) returns (QueryIncentivizedPacketsResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/incentivized_packets"; + } + + // IncentivizedPacket returns all packet fees for a packet given its identifier + rpc IncentivizedPacket(QueryIncentivizedPacketRequest) returns (QueryIncentivizedPacketResponse) { + option (google.api.http).get = + "/ibc/apps/fee/v1/incentivized_packet/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/" + "{packet_id.sequence}"; + } + + // Gets all incentivized packets for a specific channel + rpc IncentivizedPacketsForChannel(QueryIncentivizedPacketsForChannelRequest) + returns (QueryIncentivizedPacketsForChannelResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/incentivized_packets/{port_id}/{channel_id}"; + } + + // TotalRecvFees returns the total receive fees for a packet given its identifier + rpc TotalRecvFees(QueryTotalRecvFeesRequest) returns (QueryTotalRecvFeesResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/total_recv_fees/port/{packet_id.port_id}/channel/" + "{packet_id.channel_id}/sequence/{packet_id.sequence}"; + } + + // TotalAckFees returns the total acknowledgement fees for a packet given its identifier + rpc TotalAckFees(QueryTotalAckFeesRequest) returns (QueryTotalAckFeesResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/" + "{packet_id.channel_id}/sequence/{packet_id.sequence}"; + } + + // TotalTimeoutFees returns the total timeout fees for a packet given its identifier + rpc TotalTimeoutFees(QueryTotalTimeoutFeesRequest) returns (QueryTotalTimeoutFeesResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/" + "{packet_id.channel_id}/sequence/{packet_id.sequence}"; + } +} + +// QueryIncentivizedPacketsRequest defines the request type for the IncentivizedPackets rpc +message QueryIncentivizedPacketsRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; + // block height at which to query + uint64 query_height = 2; +} + +// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPackets rpc +message QueryIncentivizedPacketsResponse { + // list of identified fees for incentivized packets + repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1 [(gogoproto.nullable) = false]; +} + +// QueryIncentivizedPacketRequest defines the request type for the IncentivizedPacket rpc +message QueryIncentivizedPacketRequest { + // unique packet identifier comprised of channel ID, port ID and sequence + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; + // block height at which to query + uint64 query_height = 2; +} + +// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPacket rpc +message QueryIncentivizedPacketResponse { + // the identified fees for the incentivized packet + ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packet = 1 [(gogoproto.nullable) = false]; +} + +// QueryIncentivizedPacketsForChannelRequest defines the request type for querying for all incentivized packets +// for a specific channel +message QueryIncentivizedPacketsForChannelRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; + string port_id = 2; + string channel_id = 3; + // Height to query at + uint64 query_height = 4; +} + +// QueryIncentivizedPacketsResponse defines the response type for the incentivized packets RPC +message QueryIncentivizedPacketsForChannelResponse { + // Map of all incentivized_packets + repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1; +} + +// QueryTotalRecvFeesRequest defines the request type for the TotalRecvFees rpc +message QueryTotalRecvFeesRequest { + // the packet identifier for the associated fees + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; +} + +// QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees rpc +message QueryTotalRecvFeesResponse { + // the total packet receive fees + repeated cosmos.base.v1beta1.Coin recv_fees = 1 [ + (gogoproto.moretags) = "yaml:\"recv_fees\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// QueryTotalAckFeesRequest defines the request type for the TotalAckFees rpc +message QueryTotalAckFeesRequest { + // the packet identifier for the associated fees + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; +} + +// QueryTotalAckFeesResponse defines the response type for the TotalAckFees rpc +message QueryTotalAckFeesResponse { + // the total packet acknowledgement fees + repeated cosmos.base.v1beta1.Coin ack_fees = 1 [ + (gogoproto.moretags) = "yaml:\"ack_fees\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// QueryTotalTimeoutFeesRequest defines the request type for the TotalTimeoutFees rpc +message QueryTotalTimeoutFeesRequest { + // the packet identifier for the associated fees + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; +} + +// QueryTotalTimeoutFeesResponse defines the response type for the TotalTimeoutFees rpc +message QueryTotalTimeoutFeesResponse { + // the total packet timeout fees + repeated cosmos.base.v1beta1.Coin timeout_fees = 1 [ + (gogoproto.moretags) = "yaml:\"timeout_fees\"", + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} diff --git a/proto/ibc/applications/fee/v1/tx.proto b/proto/ibc/applications/fee/v1/tx.proto new file mode 100644 index 00000000000..7a0044cd363 --- /dev/null +++ b/proto/ibc/applications/fee/v1/tx.proto @@ -0,0 +1,85 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; + +import "gogoproto/gogo.proto"; +import "ibc/applications/fee/v1/fee.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// Msg defines the ICS29 Msg service. +service Msg { + // RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress + // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their + // counterparty address before relaying. This ensures they will be properly compensated for forward relaying since + // destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function + // may be called more than once by a relayer, in which case, latest counterparty address is always used. + rpc RegisterCounterpartyAddress(MsgRegisterCounterpartyAddress) returns (MsgRegisterCounterpartyAddressResponse); + + // PayPacketFee defines a rpc handler method for MsgPayPacketFee + // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to + // incentivize the relaying of the packet at the next sequence + // NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows + // initiates the lifecycle of the incentivized packet + rpc PayPacketFee(MsgPayPacketFee) returns (MsgPayPacketFeeResponse); + + // PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync + // PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to + // incentivize the relaying of a known packet (i.e. at a particular sequence) + rpc PayPacketFeeAsync(MsgPayPacketFeeAsync) returns (MsgPayPacketFeeAsyncResponse); +} + +// MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc +message MsgRegisterCounterpartyAddress { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // the relayer address + string address = 1; + // the counterparty relayer address + string counterparty_address = 2 [(gogoproto.moretags) = "yaml:\"counterparty_address\""]; + // unique channel identifier + string channel_id = 3 [(gogoproto.moretags) = "yaml:\"channel_id\""]; +} + +// MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc +message MsgRegisterCounterpartyAddressResponse {} + +// MsgPayPacketFee defines the request type for the PayPacketFee rpc +// This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be +// paid for +message MsgPayPacketFee { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // fee encapsulates the recv, ack and timeout fees associated with an IBC packet + ibc.applications.fee.v1.Fee fee = 1 [(gogoproto.nullable) = false]; + // the source port unique identifier + string source_port_id = 2 [(gogoproto.moretags) = "yaml:\"source_port_id\""]; + // the source channel unique identifer + string source_channel_id = 3 [(gogoproto.moretags) = "yaml:\"source_channel_id\""]; + // account address to refund fee if necessary + string signer = 4; + // optional list of relayers permitted to the receive packet fees + repeated string relayers = 5; +} + +// MsgPayPacketFeeResponse defines the response type for the PayPacketFee rpc +message MsgPayPacketFeeResponse {} + +// MsgPayPacketFeeAsync defines the request type for the PayPacketFeeAsync rpc +// This Msg can be used to pay for a packet at a specified sequence (instead of the next sequence send) +message MsgPayPacketFeeAsync { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // unique packet identifier comprised of the channel ID, port ID and sequence + ibc.core.channel.v1.PacketId packet_id = 1 + [(gogoproto.moretags) = "yaml:\"packet_id\"", (gogoproto.nullable) = false]; + // the packet fee associated with a particular IBC packet + PacketFee packet_fee = 2 [(gogoproto.moretags) = "yaml:\"packet_fee\"", (gogoproto.nullable) = false]; +} + +// MsgPayPacketFeeAsyncResponse defines the response type for the PayPacketFeeAsync rpc +message MsgPayPacketFeeAsyncResponse {} diff --git a/proto/ibc/core/channel/v1/channel.proto b/proto/ibc/core/channel/v1/channel.proto index 68c6ec17b19..177f2c85fd1 100644 --- a/proto/ibc/core/channel/v1/channel.proto +++ b/proto/ibc/core/channel/v1/channel.proto @@ -132,6 +132,20 @@ message PacketState { bytes data = 4; } +// PacketId is an identifer for a unique Packet +// Source chains refer to packets by source port/channel +// Destination chains refer to packets by destination port/channel +message PacketId { + option (gogoproto.goproto_getters) = false; + + // channel port identifier + string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + // channel unique identifier + string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + // packet sequence + uint64 sequence = 3; +} + // Acknowledgement is the recommended acknowledgement format to be used by // app-specific protocols. // NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index efcfb36b30a..4736b47540b 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -31,7 +31,8 @@ buf protoc \ -I "third_party/proto" \ --doc_out=./docs/ibc \ --doc_opt=./docs/protodoc-markdown.tmpl,proto-docs.md \ - $(find "$(pwd)/proto" -maxdepth 5 -name '*.proto') + $(find "$(pwd)/proto" -maxdepth 7 -name '*.proto') +go mod tidy # move proto files to the right places cp -r github.com/cosmos/ibc-go/v*/modules/* modules/ diff --git a/testing/simapp/app.go b/testing/simapp/app.go index ee148806852..738e29cdd59 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -89,6 +89,9 @@ import ( icahostkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + ibcfee "github.com/cosmos/ibc-go/v3/modules/apps/29-fee" + ibcfeekeeper "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/keeper" + ibcfeetypes "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" transfer "github.com/cosmos/ibc-go/v3/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" @@ -111,6 +114,11 @@ import ( const appName = "SimApp" +// IBC application testing ports +const ( + MockFeePort string = ibcmock.ModuleName + ibcfeetypes.ModuleName +) + var ( // DefaultNodeHome default home directories for the application daemon DefaultNodeHome string @@ -142,6 +150,7 @@ var ( ica.AppModuleBasic{}, authzmodule.AppModuleBasic{}, vesting.AppModuleBasic{}, + ibcfee.AppModuleBasic{}, ) // module account permissions @@ -153,6 +162,7 @@ var ( stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, govtypes.ModuleName: {authtypes.Burner}, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + ibcfeetypes.ModuleName: nil, icatypes.ModuleName: nil, } ) @@ -192,6 +202,7 @@ type SimApp struct { ParamsKeeper paramskeeper.Keeper AuthzKeeper authzkeeper.Keeper IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + IBCFeeKeeper ibcfeekeeper.Keeper ICAControllerKeeper icacontrollerkeeper.Keeper ICAHostKeeper icahostkeeper.Keeper EvidenceKeeper evidencekeeper.Keeper @@ -201,6 +212,8 @@ type SimApp struct { // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper ScopedTransferKeeper capabilitykeeper.ScopedKeeper + ScopedIBCFeeKeeper capabilitykeeper.ScopedKeeper + ScopedFeeMockKeeper capabilitykeeper.ScopedKeeper ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper ScopedICAHostKeeper capabilitykeeper.ScopedKeeper ScopedIBCMockKeeper capabilitykeeper.ScopedKeeper @@ -209,6 +222,7 @@ type SimApp struct { // make IBC modules public for test purposes // these modules are never directly routed to by the IBC Router ICAAuthModule ibcmock.IBCModule + FeeMockModule ibcmock.IBCModule // the module manager mm *module.Manager @@ -235,7 +249,6 @@ func NewSimApp( homePath string, invCheckPeriod uint, encodingConfig simappparams.EncodingConfig, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { - appCodec := encodingConfig.Marshaler legacyAmino := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry @@ -250,7 +263,7 @@ func NewSimApp( minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, icacontrollertypes.StoreKey, icahosttypes.StoreKey, capabilitytypes.StoreKey, - authzkeeper.StoreKey, + authzkeeper.StoreKey, ibcfeetypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -281,6 +294,7 @@ func NewSimApp( // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // not replicate if you do not need to test core IBC or light clients. scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName) + scopedFeeMockKeeper := app.CapabilityKeeper.ScopeToModule(MockFeePort) scopedICAMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName + icacontrollertypes.SubModuleName) // seal capability keeper after scoping modules @@ -339,18 +353,35 @@ func NewSimApp( &stakingKeeper, govRouter, ) - // Create Transfer Keepers + app.IBCFeeKeeper = ibcfeekeeper.NewKeeper(appCodec, keys[ibcfeetypes.StoreKey], app.GetSubspace(ibcfeetypes.ModuleName), + app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, + ) + + // Create Transfer Keeper and pass IBCFeeKeeper as expected Channel and PortKeeper + // since fee middleware will wrap the IBCKeeper for underlying application. app.TransferKeeper = ibctransferkeeper.NewKeeper( appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + app.IBCFeeKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, ) transferModule := transfer.NewAppModule(app.TransferKeeper) transferIBCModule := transfer.NewIBCModule(app.TransferKeeper) + // create fee-wrapped transfer module + feeTransferModule := ibcfee.NewIBCModule(app.IBCFeeKeeper, transferIBCModule) + + feeModule := ibcfee.NewAppModule(app.IBCFeeKeeper) + // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // not replicate if you do not need to test core IBC or light clients. mockModule := ibcmock.NewAppModule(&app.IBCKeeper.PortKeeper) + + // create fee wrapped mock module + feeMockModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp(MockFeePort, scopedFeeMockKeeper)) + app.FeeMockModule = feeMockModule + + feeWithMockModule := ibcfee.NewIBCModule(app.IBCFeeKeeper, feeMockModule) + mockIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp(ibcmock.ModuleName, scopedIBCMockKeeper)) app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( @@ -376,12 +407,15 @@ func NewSimApp( icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) // Create static IBC router, add app routes, then set and seal it + // pass in top-level (fully-wrapped) IBCModules to IBC Router ibcRouter := porttypes.NewRouter() ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerIBCModule). AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerIBCModule). // ica with mock auth module stack route to ica (top level of middleware stack) - AddRoute(ibctransfertypes.ModuleName, transferIBCModule). - AddRoute(ibcmock.ModuleName, mockIBCModule) + AddRoute(ibctransfertypes.ModuleName, feeTransferModule). + AddRoute(ibcmock.ModuleName, mockIBCModule). + AddRoute(MockFeePort, feeWithMockModule) + app.IBCKeeper.SetRouter(ibcRouter) // create evidence keeper with router @@ -421,6 +455,7 @@ func NewSimApp( params.NewAppModule(app.ParamsKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), transferModule, + feeModule, icaModule, mockModule, ) @@ -434,13 +469,13 @@ func NewSimApp( upgradetypes.ModuleName, capabilitytypes.ModuleName, minttypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName, ibctransfertypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, govtypes.ModuleName, crisistypes.ModuleName, genutiltypes.ModuleName, authz.ModuleName, feegrant.ModuleName, - paramstypes.ModuleName, vestingtypes.ModuleName, icatypes.ModuleName, ibcmock.ModuleName, + paramstypes.ModuleName, vestingtypes.ModuleName, icatypes.ModuleName, ibcfeetypes.ModuleName, ibcmock.ModuleName, ) app.mm.SetOrderEndBlockers( crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName, ibctransfertypes.ModuleName, capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, minttypes.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName, feegrant.ModuleName, paramstypes.ModuleName, - upgradetypes.ModuleName, vestingtypes.ModuleName, icatypes.ModuleName, ibcmock.ModuleName, + upgradetypes.ModuleName, vestingtypes.ModuleName, icatypes.ModuleName, ibcfeetypes.ModuleName, ibcmock.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -452,7 +487,7 @@ func NewSimApp( capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName, ibchost.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName, ibctransfertypes.ModuleName, - icatypes.ModuleName, ibcmock.ModuleName, feegrant.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, vestingtypes.ModuleName, + icatypes.ModuleName, ibcfeetypes.ModuleName, ibcmock.ModuleName, feegrant.ModuleName, paramstypes.ModuleName, upgradetypes.ModuleName, vestingtypes.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) @@ -529,6 +564,7 @@ func NewSimApp( // note replicate if you do not need to test core IBC or light clients. app.ScopedIBCMockKeeper = scopedIBCMockKeeper app.ScopedICAMockKeeper = scopedICAMockKeeper + app.ScopedFeeMockKeeper = scopedFeeMockKeeper return app } diff --git a/testing/values.go b/testing/values.go index 6bdf782c65a..655a4731a74 100644 --- a/testing/values.go +++ b/testing/values.go @@ -14,6 +14,7 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" "github.com/cosmos/ibc-go/v3/testing/mock" + "github.com/cosmos/ibc-go/v3/testing/simapp" ) const ( @@ -33,6 +34,7 @@ const ( // Application Ports TransferPort = ibctransfertypes.ModuleName MockPort = mock.ModuleName + MockFeePort = simapp.MockFeePort // used for testing proposals Title = "title" From 7447b601f0f6b148db9b2b55702eeb47cbdb3fcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Apr 2022 17:50:34 +0000 Subject: [PATCH 058/275] build(deps): bump codecov/codecov-action from 2.1.0 to 3 (#1222) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 2.1.0 to 3. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v2.1.0...v3) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 330ac7ffdfe..901d728b4cc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -150,7 +150,7 @@ jobs: sed -i.bak "/$(echo $filename | sed 's/\//\\\//g')/d" coverage.txt done if: env.GIT_DIFF - - uses: codecov/codecov-action@v2.1.0 + - uses: codecov/codecov-action@v3 with: file: ./coverage.txt if: env.GIT_DIFF From 76e0c24e340bcfa611823b136f359d3f4d64f387 Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 7 Apr 2022 17:09:48 +0200 Subject: [PATCH 059/275] ics29: feat: CLI query commands for packets (#1229) * feat: adding query for getting incentivized packet by packet-id * feat: add cli for getting all incentivized packets across all channels * nits: suggestions * Update modules/apps/29-fee/client/cli/query.go Co-authored-by: Damian Nolan * chore: changelog * nits: comments Co-authored-by: Damian Nolan --- CHANGELOG.md | 1 + modules/apps/29-fee/client/cli/cli.go | 2 + modules/apps/29-fee/client/cli/query.go | 87 +++++++++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a393565403b..80905a6931e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. ### Features +* (modules/apps/29-fee) [\#1229](https://github.com/cosmos/ibc-go/pull/1229) Adding CLI commands for getting all unrelayed incentivized packets and packet by packet-id. ### Bug Fixes diff --git a/modules/apps/29-fee/client/cli/cli.go b/modules/apps/29-fee/client/cli/cli.go index 292f1d7b3d8..5a53914bc58 100644 --- a/modules/apps/29-fee/client/cli/cli.go +++ b/modules/apps/29-fee/client/cli/cli.go @@ -18,6 +18,8 @@ func GetQueryCmd() *cobra.Command { GetCmdTotalRecvFees(), GetCmdTotalAckFees(), GetCmdTotalTimeoutFees(), + GetCmdIncentivizedPacket(), + GetCmdIncentivizedPackets(), ) return queryCmd diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index 95bb0959ba7..e16cc842360 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -149,3 +149,90 @@ func GetCmdTotalTimeoutFees() *cobra.Command { return cmd } + +// GetCmdIncentivizedPacket returns the unrelayed incentivized packet for a given packetID +func GetCmdIncentivizedPacket() *cobra.Command { + cmd := &cobra.Command{ + Use: "packet [port-id] [channel-id] [sequence]", + Short: "Query for an unrelayed incentivized packet by port-id, channel-id and packet sequence.", + Long: "Query for an unrelayed incentivized packet by port-id, channel-id and packet sequence.", + Args: cobra.ExactArgs(3), + Example: fmt.Sprintf("%s query ibc-fee packet-by-id", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + seq, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return err + } + + packetID := channeltypes.PacketId{ + PortId: args[0], + ChannelId: args[1], + Sequence: seq, + } + + req := &types.QueryIncentivizedPacketRequest{ + PacketId: packetID, + QueryHeight: uint64(clientCtx.Height), + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.IncentivizedPacket(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdIncentivizedPackets returns all of the unrelayed incentivized packets +func GetCmdIncentivizedPackets() *cobra.Command { + cmd := &cobra.Command{ + Use: "packets", + Short: "Query for all of the unrelayed incentivized packets and associated fees across all channels.", + Long: "Query for all of the unrelayed incentivized packets and associated fees across all channels.", + Args: cobra.NoArgs, + Example: fmt.Sprintf("%s query ibc-fee packets", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryIncentivizedPacketsRequest{ + Pagination: pageReq, + QueryHeight: uint64(clientCtx.Height), + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.IncentivizedPackets(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "packets") + + return cmd +} From 35427da7a63470501b33c4a1dc5e66b7fb6ea7ac Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 7 Apr 2022 17:19:46 +0200 Subject: [PATCH 060/275] add check for blocked addr for forward relayer distribution (#1231) --- modules/apps/29-fee/ibc_module_test.go | 2 +- modules/apps/29-fee/keeper/escrow.go | 2 +- modules/apps/29-fee/keeper/escrow_test.go | 6 ++++++ modules/apps/29-fee/types/expected_keepers.go | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/apps/29-fee/ibc_module_test.go b/modules/apps/29-fee/ibc_module_test.go index 8bdc92458f7..fb2bd8ecf01 100644 --- a/modules/apps/29-fee/ibc_module_test.go +++ b/modules/apps/29-fee/ibc_module_test.go @@ -622,6 +622,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { }.Acknowledgement() expectedRelayerBalance = packetFee.Fee.AckFee + expectedBalance = expectedBalance.Add(packetFee.Fee.RecvFee[0]) }, true, }, @@ -693,7 +694,6 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { expectedRelayerBalance, relayerBalance, ) - }) } } diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 37c9dd7e624..525ce258d05 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -56,7 +56,7 @@ func (k Keeper) DistributePacketFees(ctx sdk.Context, forwardRelayer string, rev } // distribute fee to valid forward relayer address otherwise refund the fee - if !forwardAddr.Empty() { + if !forwardAddr.Empty() && !k.bankKeeper.BlockedAddr(forwardAddr) { // distribute fee for forward relaying k.distributeFee(ctx, forwardAddr, packetFee.Fee.RecvFee) } else { diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 647b968f56d..2f6b2fe62b1 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -5,6 +5,7 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" ) @@ -141,6 +142,11 @@ func (suite *KeeperTestSuite) TestDistributeFee() { forwardRelayer = "invalid address" }, false, }, + { + "invalid forward address: blocked address", func() { + forwardRelayer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() + }, false, + }, } for _, tc := range testCases { diff --git a/modules/apps/29-fee/types/expected_keepers.go b/modules/apps/29-fee/types/expected_keepers.go index 0b42718ff02..3a58f0706b3 100644 --- a/modules/apps/29-fee/types/expected_keepers.go +++ b/modules/apps/29-fee/types/expected_keepers.go @@ -37,4 +37,5 @@ type BankKeeper interface { SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + BlockedAddr(sdk.AccAddress) bool } From 89c8cf8e287b76f9b8e62fa0c90f49f981507ae3 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 7 Apr 2022 17:35:30 +0200 Subject: [PATCH 061/275] feat: ics29 counterparty address grpc query and CLI (#1224) * generating codegen protobufs for query counterparty address * adding grpc query, tests and cli * Update modules/apps/29-fee/keeper/grpc_query_test.go Co-authored-by: Sean King * Update modules/apps/29-fee/keeper/grpc_query_test.go Co-authored-by: Sean King * updating godoc * adding changelog * updating cli descriptions for ics29 Co-authored-by: Sean King --- CHANGELOG.md | 2 + docs/ibc/proto-docs.md | 34 ++ go.mod | 2 +- go.sum | 120 +--- modules/apps/29-fee/client/cli/cli.go | 9 +- modules/apps/29-fee/client/cli/query.go | 162 +++-- modules/apps/29-fee/keeper/grpc_query.go | 18 + modules/apps/29-fee/keeper/grpc_query_test.go | 67 +++ modules/apps/29-fee/types/query.pb.go | 565 ++++++++++++++++-- modules/apps/29-fee/types/query.pb.gw.go | 120 ++++ proto/ibc/applications/fee/v1/query.proto | 19 + 11 files changed, 871 insertions(+), 247 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80905a6931e..d7b86ca8d39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features * (modules/apps/29-fee) [\#1229](https://github.com/cosmos/ibc-go/pull/1229) Adding CLI commands for getting all unrelayed incentivized packets and packet by packet-id. +* (apps/29-fee) [\#1224](https://github.com/cosmos/ibc-go/pull/1224) Adding Query/CounterpartyAddress and CLI to ICS29 fee middleware + ### Bug Fixes * (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 539b8bb2c77..ad54c1cf9d6 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -44,6 +44,8 @@ - [Metadata](#ibc.applications.fee.v1.Metadata) - [ibc/applications/fee/v1/query.proto](#ibc/applications/fee/v1/query.proto) + - [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) + - [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) - [QueryIncentivizedPacketRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketRequest) - [QueryIncentivizedPacketResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketResponse) - [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) @@ -906,6 +908,37 @@ See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel- + + +### QueryCounterpartyAddressRequest +QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `channel_id` | [string](#string) | | unique channel identifier | +| `relayer_address` | [string](#string) | | the relayer address to which the counterparty is registered | + + + + + + + + +### QueryCounterpartyAddressResponse +QueryCounterpartyAddressResponse defines the response type for the CounterpartyAddress rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `counterparty_address` | [string](#string) | | the counterparty address used to compensate forward relaying | + + + + + + ### QueryIncentivizedPacketRequest @@ -1111,6 +1144,7 @@ Query defines the ICS29 gRPC querier service. | `TotalRecvFees` | [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) | [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) | TotalRecvFees returns the total receive fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_recv_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| | `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| | `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| +| `CounterpartyAddress` | [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) | [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) | CounterpartyAddress returns the registered counterparty address for forward relaying | GET|/ibc/apps/fee/v1/counterparty_address/{relayer_address}/channel/{channel_id}| diff --git a/go.mod b/go.mod index 372b65ce148..d13f9bc4ef7 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,7 @@ require ( github.com/go-logfmt/logfmt v0.5.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/gateway v1.1.0 // indirect - github.com/golang/snappy v0.0.3 // indirect + github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 // indirect github.com/google/btree v1.0.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/gorilla/handlers v1.5.1 // indirect diff --git a/go.sum b/go.sum index 38008de3b95..a3904fbbaa6 100644 --- a/go.sum +++ b/go.sum @@ -18,14 +18,6 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -35,7 +27,6 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -112,7 +103,6 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -152,7 +142,6 @@ github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -176,9 +165,7 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg= @@ -267,9 +254,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -279,9 +264,7 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQD github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= @@ -345,7 +328,6 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -377,9 +359,8 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -395,7 +376,6 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= @@ -403,7 +383,6 @@ github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -417,17 +396,12 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -464,25 +438,18 @@ github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uM github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -498,11 +465,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87/go.mod h1:XGsKKeXxeRr95aEOgipvluMPlgjr7dGlk9ZTWOjcUcg= github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= @@ -510,7 +474,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/improbable-eng/grpc-web v0.14.1 h1:NrN4PY71A6tAz2sKDvC5JCauENWp0ykG8Oq1H3cpFvw= @@ -538,7 +501,6 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -576,7 +538,6 @@ github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoR github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= -github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -584,19 +545,12 @@ github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaW github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= @@ -606,14 +560,11 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -633,7 +584,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= @@ -729,7 +679,6 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= @@ -795,7 +744,6 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= @@ -820,7 +768,6 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -918,11 +865,8 @@ go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -955,7 +899,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1005,7 +948,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1056,11 +998,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1076,11 +1015,6 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1103,7 +1037,6 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1117,11 +1050,9 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1132,7 +1063,6 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1161,7 +1091,6 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1170,20 +1099,11 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1218,7 +1138,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1264,8 +1183,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1295,17 +1212,6 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1360,26 +1266,8 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1409,17 +1297,11 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/modules/apps/29-fee/client/cli/cli.go b/modules/apps/29-fee/client/cli/cli.go index 5a53914bc58..2279e741556 100644 --- a/modules/apps/29-fee/client/cli/cli.go +++ b/modules/apps/29-fee/client/cli/cli.go @@ -9,17 +9,18 @@ import ( func GetQueryCmd() *cobra.Command { queryCmd := &cobra.Command{ Use: "ibc-fee", - Short: "", // TODO + Short: "IBC relayer incentivization query subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, } queryCmd.AddCommand( + GetCmdIncentivizedPacket(), + GetCmdIncentivizedPackets(), GetCmdTotalRecvFees(), GetCmdTotalAckFees(), GetCmdTotalTimeoutFees(), - GetCmdIncentivizedPacket(), - GetCmdIncentivizedPackets(), + GetCmdCounterpartyAddress(), ) return queryCmd @@ -29,7 +30,7 @@ func GetQueryCmd() *cobra.Command { func NewTxCmd() *cobra.Command { txCmd := &cobra.Command{ Use: "ibc-fee", - Short: "Transaction subcommand for IBC relayer incentivization", + Short: "IBC relayer incentivization transaction subcommands", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index e16cc842360..9c96afc9478 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -6,45 +6,86 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" "github.com/spf13/cobra" ) -// GetCmdTotalRecvFees returns the command handler for the Query/TotalRecvFees rpc. -func GetCmdTotalRecvFees() *cobra.Command { +// GetCmdIncentivizedPacket returns the unrelayed incentivized packet for a given packetID +func GetCmdIncentivizedPacket() *cobra.Command { cmd := &cobra.Command{ - Use: "total-recv-fees [port-id] [channel-id] [sequence]", - Short: "Query the total receive fees for a packet", - Long: "Query the total receive fees for a packet", + Use: "packet [port-id] [channel-id] [sequence]", + Short: "Query for an unrelayed incentivized packet by port-id, channel-id and packet sequence.", + Long: "Query for an unrelayed incentivized packet by port-id, channel-id and packet sequence.", Args: cobra.ExactArgs(3), - Example: fmt.Sprintf("%s query ibc-fee total-recv-fees transfer channel-5 100", version.AppName), + Example: fmt.Sprintf("%s query ibc-fee packet-by-id", version.AppName), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } - portID, channelID := args[0], args[1] seq, err := strconv.ParseUint(args[2], 10, 64) if err != nil { return err } - packetID := channeltypes.NewPacketId(channelID, portID, seq) + packetID := channeltypes.PacketId{ + PortId: args[0], + ChannelId: args[1], + Sequence: seq, + } - if err := packetID.Validate(); err != nil { - return err + req := &types.QueryIncentivizedPacketRequest{ + PacketId: packetID, + QueryHeight: uint64(clientCtx.Height), } queryClient := types.NewQueryClient(clientCtx) - req := &types.QueryTotalRecvFeesRequest{ - PacketId: packetID, + res, err := queryClient.IncentivizedPacket(cmd.Context(), req) + if err != nil { + return err } - res, err := queryClient.TotalRecvFees(cmd.Context(), req) + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// GetCmdIncentivizedPackets returns all of the unrelayed incentivized packets +func GetCmdIncentivizedPackets() *cobra.Command { + cmd := &cobra.Command{ + Use: "packets", + Short: "Query for all of the unrelayed incentivized packets and associated fees across all channels.", + Long: "Query for all of the unrelayed incentivized packets and associated fees across all channels.", + Args: cobra.NoArgs, + Example: fmt.Sprintf("%s query ibc-fee packets", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryIncentivizedPacketsRequest{ + Pagination: pageReq, + QueryHeight: uint64(clientCtx.Height), + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.IncentivizedPackets(cmd.Context(), req) if err != nil { return err } @@ -54,18 +95,19 @@ func GetCmdTotalRecvFees() *cobra.Command { } flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "packets") return cmd } -// GetCmdTotalAckFees returns the command handler for the Query/TotalAckFees rpc. -func GetCmdTotalAckFees() *cobra.Command { +// GetCmdTotalRecvFees returns the command handler for the Query/TotalRecvFees rpc. +func GetCmdTotalRecvFees() *cobra.Command { cmd := &cobra.Command{ - Use: "total-ack-fees [port-id] [channel-id] [sequence]", - Short: "Query the total acknowledgement fees for a packet", - Long: "Query the total acknowledgement fees for a packet", + Use: "total-recv-fees [port-id] [channel-id] [sequence]", + Short: "Query the total receive fees for a packet", + Long: "Query the total receive fees for a packet", Args: cobra.ExactArgs(3), - Example: fmt.Sprintf("%s query ibc-fee total-ack-fees transfer channel-5 100", version.AppName), + Example: fmt.Sprintf("%s query ibc-fee total-recv-fees transfer channel-5 100", version.AppName), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { @@ -86,11 +128,11 @@ func GetCmdTotalAckFees() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) - req := &types.QueryTotalAckFeesRequest{ + req := &types.QueryTotalRecvFeesRequest{ PacketId: packetID, } - res, err := queryClient.TotalAckFees(cmd.Context(), req) + res, err := queryClient.TotalRecvFees(cmd.Context(), req) if err != nil { return err } @@ -104,14 +146,14 @@ func GetCmdTotalAckFees() *cobra.Command { return cmd } -// GetCmdTotalTimeoutFees returns the command handler for the Query/TotalTimeoutFees rpc. -func GetCmdTotalTimeoutFees() *cobra.Command { +// GetCmdTotalAckFees returns the command handler for the Query/TotalAckFees rpc. +func GetCmdTotalAckFees() *cobra.Command { cmd := &cobra.Command{ - Use: "total-timeout-fees [port-id] [channel-id] [sequence]", - Short: "Query the total timeout fees for a packet", - Long: "Query the total timeout fees for a packet", + Use: "total-ack-fees [port-id] [channel-id] [sequence]", + Short: "Query the total acknowledgement fees for a packet", + Long: "Query the total acknowledgement fees for a packet", Args: cobra.ExactArgs(3), - Example: fmt.Sprintf("%s query ibc-fee total-timeout-fees transfer channel-5 100", version.AppName), + Example: fmt.Sprintf("%s query ibc-fee total-ack-fees transfer channel-5 100", version.AppName), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { @@ -132,11 +174,11 @@ func GetCmdTotalTimeoutFees() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) - req := &types.QueryTotalTimeoutFeesRequest{ + req := &types.QueryTotalAckFeesRequest{ PacketId: packetID, } - res, err := queryClient.TotalTimeoutFees(cmd.Context(), req) + res, err := queryClient.TotalAckFees(cmd.Context(), req) if err != nil { return err } @@ -150,39 +192,39 @@ func GetCmdTotalTimeoutFees() *cobra.Command { return cmd } -// GetCmdIncentivizedPacket returns the unrelayed incentivized packet for a given packetID -func GetCmdIncentivizedPacket() *cobra.Command { +// GetCmdTotalTimeoutFees returns the command handler for the Query/TotalTimeoutFees rpc. +func GetCmdTotalTimeoutFees() *cobra.Command { cmd := &cobra.Command{ - Use: "packet [port-id] [channel-id] [sequence]", - Short: "Query for an unrelayed incentivized packet by port-id, channel-id and packet sequence.", - Long: "Query for an unrelayed incentivized packet by port-id, channel-id and packet sequence.", + Use: "total-timeout-fees [port-id] [channel-id] [sequence]", + Short: "Query the total timeout fees for a packet", + Long: "Query the total timeout fees for a packet", Args: cobra.ExactArgs(3), - Example: fmt.Sprintf("%s query ibc-fee packet-by-id", version.AppName), + Example: fmt.Sprintf("%s query ibc-fee total-timeout-fees transfer channel-5 100", version.AppName), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } + portID, channelID := args[0], args[1] seq, err := strconv.ParseUint(args[2], 10, 64) if err != nil { return err } - packetID := channeltypes.PacketId{ - PortId: args[0], - ChannelId: args[1], - Sequence: seq, - } + packetID := channeltypes.NewPacketId(channelID, portID, seq) - req := &types.QueryIncentivizedPacketRequest{ - PacketId: packetID, - QueryHeight: uint64(clientCtx.Height), + if err := packetID.Validate(); err != nil { + return err } queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.IncentivizedPacket(cmd.Context(), req) + req := &types.QueryTotalTimeoutFeesRequest{ + PacketId: packetID, + } + + res, err := queryClient.TotalTimeoutFees(cmd.Context(), req) if err != nil { return err } @@ -196,33 +238,32 @@ func GetCmdIncentivizedPacket() *cobra.Command { return cmd } -// GetCmdIncentivizedPackets returns all of the unrelayed incentivized packets -func GetCmdIncentivizedPackets() *cobra.Command { +// GetCmdCounterpartyAddress returns the command handler for the Query/CounterpartyAddress rpc. +func GetCmdCounterpartyAddress() *cobra.Command { cmd := &cobra.Command{ - Use: "packets", - Short: "Query for all of the unrelayed incentivized packets and associated fees across all channels.", - Long: "Query for all of the unrelayed incentivized packets and associated fees across all channels.", - Args: cobra.NoArgs, - Example: fmt.Sprintf("%s query ibc-fee packets", version.AppName), + Use: "counterparty-address [channel-id] [address]", + Short: "Query the relayer counterparty address on a given channel", + Long: "Query the relayer counterparty address on a given channel", + Args: cobra.ExactArgs(2), + Example: fmt.Sprintf("%s query ibc-fee counterparty-address channel-5 cosmos1layxcsmyye0dc0har9sdfzwckaz8sjwlfsj8zs", version.AppName), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } - pageReq, err := client.ReadPageRequest(cmd.Flags()) - if err != nil { + if _, err := sdk.AccAddressFromBech32(args[1]); err != nil { return err } - req := &types.QueryIncentivizedPacketsRequest{ - Pagination: pageReq, - QueryHeight: uint64(clientCtx.Height), - } - queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.IncentivizedPackets(cmd.Context(), req) + req := &types.QueryCounterpartyAddressRequest{ + ChannelId: args[0], + RelayerAddress: args[1], + } + + res, err := queryClient.CounterpartyAddress(cmd.Context(), req) if err != nil { return err } @@ -231,8 +272,5 @@ func GetCmdIncentivizedPackets() *cobra.Command { }, } - flags.AddQueryFlagsToCmd(cmd) - flags.AddPaginationFlagsToCmd(cmd, "packets") - return cmd } diff --git a/modules/apps/29-fee/keeper/grpc_query.go b/modules/apps/29-fee/keeper/grpc_query.go index 68f2cb332ca..6fbb598945f 100644 --- a/modules/apps/29-fee/keeper/grpc_query.go +++ b/modules/apps/29-fee/keeper/grpc_query.go @@ -173,3 +173,21 @@ func (k Keeper) TotalTimeoutFees(goCtx context.Context, req *types.QueryTotalTim TimeoutFees: timeoutFees, }, nil } + +// CounterpartyAddress implements the Query/CounterpartyAddress gRPC method and returns the registered counterparty address for forward relaying +func (k Keeper) CounterpartyAddress(goCtx context.Context, req *types.QueryCounterpartyAddressRequest) (*types.QueryCounterpartyAddressResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + counterpartyAddr, found := k.GetCounterpartyAddress(ctx, req.RelayerAddress, req.ChannelId) + if !found { + return nil, status.Errorf(codes.NotFound, "counterparty address not found for address: %s on channel: %s", req.RelayerAddress, req.ChannelId) + } + + return &types.QueryCounterpartyAddressResponse{ + CounterpartyAddress: counterpartyAddr, + }, nil +} diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index 4bd55b92903..9802dd9216c 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -2,8 +2,10 @@ package keeper_test import ( "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" + "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -426,3 +428,68 @@ func (suite *KeeperTestSuite) TestQueryTotalTimeoutFees() { }) } } + +func (suite *KeeperTestSuite) TestQueryCounterpartyAddress() { + var ( + req *types.QueryCounterpartyAddressRequest + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "counterparty address not found: invalid channel", + func() { + req.ChannelId = "invalid-channel-id" + }, + false, + }, + { + "counterparty address not found: invalid address", + func() { + req.RelayerAddress = "invalid-addr" + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + pk := secp256k1.GenPrivKey().PubKey() + expectedCounterpartyAddr := sdk.AccAddress(pk.Address()) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + expectedCounterpartyAddr.String(), + suite.path.EndpointA.ChannelID, + ) + + req = &types.QueryCounterpartyAddressRequest{ + ChannelId: suite.path.EndpointA.ChannelID, + RelayerAddress: suite.chainA.SenderAccount.GetAddress().String(), + } + + tc.malleate() + + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.queryClient.CounterpartyAddress(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expectedCounterpartyAddr.String(), res.CounterpartyAddress) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/apps/29-fee/types/query.pb.go b/modules/apps/29-fee/types/query.pb.go index dd130bcc3fd..850bb1eb19a 100644 --- a/modules/apps/29-fee/types/query.pb.go +++ b/modules/apps/29-fee/types/query.pb.go @@ -637,6 +637,107 @@ func (m *QueryTotalTimeoutFeesResponse) GetTimeoutFees() github_com_cosmos_cosmo return nil } +// QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc +type QueryCounterpartyAddressRequest struct { + // unique channel identifier + ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + // the relayer address to which the counterparty is registered + RelayerAddress string `protobuf:"bytes,2,opt,name=relayer_address,json=relayerAddress,proto3" json:"relayer_address,omitempty" yaml:"relayer_address"` +} + +func (m *QueryCounterpartyAddressRequest) Reset() { *m = QueryCounterpartyAddressRequest{} } +func (m *QueryCounterpartyAddressRequest) String() string { return proto.CompactTextString(m) } +func (*QueryCounterpartyAddressRequest) ProtoMessage() {} +func (*QueryCounterpartyAddressRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{12} +} +func (m *QueryCounterpartyAddressRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryCounterpartyAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryCounterpartyAddressRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryCounterpartyAddressRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCounterpartyAddressRequest.Merge(m, src) +} +func (m *QueryCounterpartyAddressRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryCounterpartyAddressRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCounterpartyAddressRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryCounterpartyAddressRequest proto.InternalMessageInfo + +func (m *QueryCounterpartyAddressRequest) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +func (m *QueryCounterpartyAddressRequest) GetRelayerAddress() string { + if m != nil { + return m.RelayerAddress + } + return "" +} + +// QueryCounterpartyAddressResponse defines the response type for the CounterpartyAddress rpc +type QueryCounterpartyAddressResponse struct { + // the counterparty address used to compensate forward relaying + CounterpartyAddress string `protobuf:"bytes,1,opt,name=counterparty_address,json=counterpartyAddress,proto3" json:"counterparty_address,omitempty" yaml:"counterparty_address"` +} + +func (m *QueryCounterpartyAddressResponse) Reset() { *m = QueryCounterpartyAddressResponse{} } +func (m *QueryCounterpartyAddressResponse) String() string { return proto.CompactTextString(m) } +func (*QueryCounterpartyAddressResponse) ProtoMessage() {} +func (*QueryCounterpartyAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{13} +} +func (m *QueryCounterpartyAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryCounterpartyAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryCounterpartyAddressResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryCounterpartyAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCounterpartyAddressResponse.Merge(m, src) +} +func (m *QueryCounterpartyAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryCounterpartyAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCounterpartyAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryCounterpartyAddressResponse proto.InternalMessageInfo + +func (m *QueryCounterpartyAddressResponse) GetCounterpartyAddress() string { + if m != nil { + return m.CounterpartyAddress + } + return "" +} + func init() { proto.RegisterType((*QueryIncentivizedPacketsRequest)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketsRequest") proto.RegisterType((*QueryIncentivizedPacketsResponse)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketsResponse") @@ -650,6 +751,8 @@ func init() { proto.RegisterType((*QueryTotalAckFeesResponse)(nil), "ibc.applications.fee.v1.QueryTotalAckFeesResponse") proto.RegisterType((*QueryTotalTimeoutFeesRequest)(nil), "ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest") proto.RegisterType((*QueryTotalTimeoutFeesResponse)(nil), "ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse") + proto.RegisterType((*QueryCounterpartyAddressRequest)(nil), "ibc.applications.fee.v1.QueryCounterpartyAddressRequest") + proto.RegisterType((*QueryCounterpartyAddressResponse)(nil), "ibc.applications.fee.v1.QueryCounterpartyAddressResponse") } func init() { @@ -657,67 +760,76 @@ func init() { } var fileDescriptor_0638a8a78ca2503c = []byte{ - // 956 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcf, 0x6f, 0xdc, 0x44, - 0x14, 0xce, 0xa4, 0xa1, 0x4d, 0x66, 0x83, 0xa8, 0x26, 0x95, 0x9a, 0x5a, 0x8d, 0x93, 0x1a, 0x01, - 0xa1, 0xd2, 0x7a, 0x94, 0x8d, 0x0a, 0x2d, 0x42, 0x08, 0x92, 0x2a, 0x90, 0x13, 0x65, 0xd5, 0x13, - 0x02, 0x6d, 0xbd, 0xe3, 0x59, 0x67, 0x94, 0x5d, 0x8f, 0xbb, 0xf6, 0x1a, 0xb6, 0x69, 0x90, 0xa8, - 0x14, 0x21, 0xa1, 0x0a, 0x21, 0x21, 0x71, 0xe0, 0x1f, 0x40, 0xe2, 0x3f, 0xe0, 0xc0, 0xbd, 0x27, - 0x54, 0x89, 0x0b, 0xa7, 0x82, 0x12, 0xce, 0x1c, 0x10, 0x07, 0x8e, 0x68, 0x7e, 0xd8, 0xeb, 0xe0, - 0x75, 0xb1, 0xd3, 0xcd, 0x29, 0xf6, 0xbc, 0xf7, 0xe6, 0x7d, 0xdf, 0xf7, 0xc6, 0xdf, 0x64, 0xe1, - 0x8b, 0xac, 0x4d, 0xb0, 0x13, 0x04, 0x5d, 0x46, 0x9c, 0x88, 0x71, 0x3f, 0xc4, 0x1d, 0x4a, 0x71, - 0xbc, 0x86, 0xef, 0x0e, 0x68, 0x7f, 0x68, 0x07, 0x7d, 0x1e, 0x71, 0x74, 0x91, 0xb5, 0x89, 0x9d, - 0x4d, 0xb2, 0x3b, 0x94, 0xda, 0xf1, 0x9a, 0x71, 0xc1, 0xe3, 0x1e, 0x97, 0x39, 0x58, 0x3c, 0xa9, - 0x74, 0xe3, 0xb2, 0xc7, 0xb9, 0xd7, 0xa5, 0xd8, 0x09, 0x18, 0x76, 0x7c, 0x9f, 0x47, 0xba, 0x48, - 0x45, 0x4d, 0xc2, 0xc3, 0x1e, 0x0f, 0x71, 0xdb, 0x09, 0x45, 0xa3, 0x36, 0x8d, 0x9c, 0x35, 0x4c, - 0x38, 0xf3, 0x75, 0xfc, 0x6a, 0x36, 0x2e, 0x51, 0xa4, 0x59, 0x81, 0xe3, 0x31, 0x5f, 0x6e, 0xa6, - 0x73, 0xaf, 0x14, 0xa1, 0x17, 0xf8, 0x32, 0x29, 0x84, 0xf7, 0x29, 0x26, 0x3b, 0x8e, 0xef, 0xd3, - 0xae, 0x08, 0xeb, 0x47, 0x95, 0x62, 0x3d, 0x04, 0x70, 0xf9, 0x03, 0xd1, 0x68, 0xdb, 0x27, 0xd4, - 0x8f, 0x58, 0xcc, 0xee, 0x51, 0xf7, 0x96, 0x43, 0x76, 0x69, 0x14, 0x36, 0xe9, 0xdd, 0x01, 0x0d, - 0x23, 0xb4, 0x05, 0xe1, 0xa8, 0xfb, 0x22, 0x58, 0x01, 0xab, 0xb5, 0xc6, 0xcb, 0xb6, 0x82, 0x6a, - 0x0b, 0xa8, 0xb6, 0x12, 0x4c, 0x43, 0xb5, 0x6f, 0x39, 0x1e, 0xd5, 0xb5, 0xcd, 0x4c, 0x25, 0xba, - 0x02, 0xe7, 0x65, 0x62, 0x6b, 0x87, 0x32, 0x6f, 0x27, 0x5a, 0x9c, 0x5e, 0x01, 0xab, 0x33, 0xcd, - 0x9a, 0x5c, 0x7b, 0x4f, 0x2e, 0x59, 0x5f, 0x02, 0xb8, 0x52, 0x0c, 0x27, 0x0c, 0xb8, 0x1f, 0x52, - 0xd4, 0x81, 0x17, 0x58, 0x26, 0xdc, 0x0a, 0x54, 0x7c, 0x11, 0xac, 0x9c, 0x59, 0xad, 0x35, 0xea, - 0x76, 0xc1, 0xc4, 0xec, 0x6d, 0x57, 0xd4, 0x74, 0x58, 0xb2, 0xe3, 0x16, 0xa5, 0xe1, 0xc6, 0xcc, - 0xa3, 0x27, 0xcb, 0x53, 0xcd, 0x05, 0x96, 0xef, 0x67, 0x1d, 0x00, 0x68, 0x16, 0x80, 0x49, 0xa4, - 0x79, 0x1b, 0xce, 0xa9, 0xee, 0x2d, 0xe6, 0x6a, 0x65, 0x96, 0x64, 0x7f, 0xa1, 0xba, 0x9d, 0x48, - 0x1d, 0x0b, 0x4d, 0x44, 0xd6, 0xb6, 0xab, 0xfb, 0xcd, 0x06, 0xfa, 0xbd, 0x8c, 0x28, 0x5f, 0x14, - 0xcf, 0x28, 0xd5, 0xc4, 0x85, 0x0b, 0x63, 0x34, 0xd1, 0x90, 0x4e, 0x24, 0x09, 0xca, 0x4b, 0x62, - 0xfd, 0x0c, 0xe0, 0xab, 0x45, 0xe3, 0xd9, 0xe2, 0xfd, 0x4d, 0xc5, 0x77, 0xd2, 0xe7, 0xe6, 0x22, - 0x3c, 0x17, 0xf0, 0xbe, 0x94, 0x58, 0xa8, 0x33, 0xd7, 0x3c, 0x2b, 0x5e, 0xb7, 0x5d, 0xb4, 0x04, - 0xa1, 0x96, 0x58, 0xc4, 0xce, 0xc8, 0xd8, 0x9c, 0x5e, 0x19, 0x23, 0xed, 0x4c, 0x5e, 0xda, 0xaf, - 0x00, 0xbc, 0x5a, 0x86, 0x90, 0x56, 0xf9, 0xce, 0x04, 0x4f, 0xde, 0xf8, 0x33, 0xf7, 0x31, 0xbc, - 0x24, 0xf1, 0xdc, 0xe6, 0x91, 0xd3, 0x6d, 0x52, 0x12, 0xcb, 0xd4, 0x49, 0x9d, 0x36, 0xeb, 0x3b, - 0x00, 0x8d, 0x71, 0xfb, 0x6b, 0x7e, 0xf7, 0xe1, 0x5c, 0x9f, 0x92, 0xb8, 0xd5, 0xa1, 0x34, 0x21, - 0x75, 0xe9, 0xd8, 0xc0, 0x92, 0x51, 0x6d, 0x72, 0xe6, 0x6f, 0xdc, 0x14, 0x9b, 0xff, 0xf5, 0x64, - 0xf9, 0xfc, 0xd0, 0xe9, 0x75, 0xdf, 0xb0, 0xd2, 0x4a, 0xeb, 0x87, 0xdf, 0x96, 0x57, 0x3d, 0x16, - 0xed, 0x0c, 0xda, 0x36, 0xe1, 0x3d, 0xac, 0x4d, 0x4d, 0xfd, 0xa9, 0x87, 0xee, 0x2e, 0x8e, 0x86, - 0x01, 0x0d, 0xe5, 0x26, 0x61, 0x73, 0xb6, 0xaf, 0x51, 0x58, 0x1f, 0xc1, 0xc5, 0x11, 0xb6, 0x77, - 0xc8, 0xee, 0x64, 0xa9, 0x7f, 0x0b, 0xb2, 0xd2, 0xa6, 0xdb, 0x6b, 0xe6, 0x43, 0x38, 0xeb, 0x90, - 0xdd, 0x92, 0xc4, 0x37, 0x35, 0xf1, 0x17, 0x14, 0xf1, 0xa4, 0xb0, 0x1a, 0xef, 0x73, 0x8e, 0x82, - 0x60, 0xdd, 0x81, 0x97, 0x47, 0xb8, 0x6e, 0xb3, 0x1e, 0xe5, 0x83, 0x68, 0xb2, 0xd4, 0xbf, 0x07, - 0x70, 0xa9, 0xa0, 0x85, 0xa6, 0x7f, 0x00, 0xe0, 0x7c, 0xa4, 0xd6, 0x4b, 0x6a, 0xf0, 0xae, 0xd6, - 0x60, 0x41, 0x69, 0x90, 0x2d, 0xae, 0xa6, 0x43, 0x2d, 0x1a, 0xe1, 0x69, 0xfc, 0x54, 0x83, 0xcf, - 0x49, 0xa4, 0xe8, 0x47, 0x00, 0x17, 0xc6, 0x7c, 0x94, 0xe8, 0x7a, 0xe1, 0x47, 0xf6, 0x3f, 0xd7, - 0x98, 0x71, 0xe3, 0x04, 0x95, 0x4a, 0x1e, 0xab, 0xfe, 0xe0, 0x97, 0x3f, 0xbe, 0x99, 0x7e, 0x05, - 0xbd, 0x84, 0xf5, 0xa5, 0x9b, 0x5e, 0xb6, 0xe3, 0xec, 0x00, 0x3d, 0x9c, 0x86, 0x28, 0xbf, 0x1d, - 0x7a, 0xbd, 0x2a, 0x80, 0x04, 0xf9, 0xf5, 0xea, 0x85, 0x1a, 0xf8, 0x03, 0x20, 0x91, 0xdf, 0x47, - 0xf7, 0xca, 0x20, 0xc7, 0xc2, 0x57, 0xf1, 0x5e, 0x7a, 0xda, 0x6c, 0x6d, 0xbb, 0xfb, 0xe9, 0xff, - 0x0f, 0x99, 0xd8, 0xc8, 0x79, 0xf7, 0x71, 0x28, 0x80, 0xfa, 0x84, 0x66, 0xe3, 0xc9, 0xda, 0x3e, - 0xfa, 0x13, 0xc0, 0xa5, 0xa7, 0xfa, 0x2b, 0xda, 0xa8, 0x3c, 0x9a, 0xdc, 0x6d, 0x63, 0x6c, 0x3e, - 0xd3, 0x1e, 0x5a, 0xaf, 0x9b, 0x52, 0xae, 0xb7, 0xd0, 0x9b, 0xa5, 0x06, 0x8d, 0xf7, 0x52, 0x81, - 0xf6, 0x32, 0x72, 0xa0, 0x7f, 0x00, 0x7c, 0xfe, 0x98, 0xc1, 0xa2, 0xc6, 0xd3, 0xc1, 0x8d, 0x73, - 0x7b, 0x63, 0xbd, 0x52, 0x8d, 0x26, 0xf0, 0x99, 0x24, 0xf0, 0x29, 0x8a, 0x73, 0x04, 0x22, 0x91, - 0xdf, 0x4a, 0x4d, 0xfa, 0x94, 0x66, 0xfd, 0x37, 0x80, 0xf3, 0x59, 0x83, 0x45, 0x6b, 0x25, 0x58, - 0x1c, 0xf7, 0x7a, 0xa3, 0x51, 0xa5, 0x44, 0xf3, 0xde, 0x97, 0xbc, 0x3f, 0x41, 0x83, 0x02, 0xde, - 0x89, 0x47, 0x9f, 0x12, 0xed, 0x83, 0x69, 0x78, 0xfe, 0xbf, 0xe6, 0x8a, 0xae, 0x95, 0xe0, 0x91, - 0xf7, 0x7b, 0xe3, 0xb5, 0xaa, 0x65, 0x5a, 0x82, 0xcf, 0xd5, 0xb7, 0xbe, 0x87, 0x86, 0x05, 0x1a, - 0x64, 0x3d, 0xfa, 0x74, 0x74, 0xd8, 0x78, 0xff, 0xd1, 0xa1, 0x09, 0x1e, 0x1f, 0x9a, 0xe0, 0xf7, - 0x43, 0x13, 0x7c, 0x7d, 0x64, 0x4e, 0x3d, 0x3e, 0x32, 0xa7, 0x7e, 0x3d, 0x32, 0xa7, 0x3e, 0xbc, - 0x96, 0xbf, 0x10, 0x58, 0x9b, 0xd4, 0x3d, 0x8e, 0xe3, 0x75, 0xdc, 0xe3, 0xee, 0xa0, 0x4b, 0x43, - 0x85, 0xb9, 0x71, 0xa3, 0x2e, 0x60, 0xcb, 0x3b, 0xa2, 0x7d, 0x56, 0xfe, 0x4c, 0x59, 0xff, 0x37, - 0x00, 0x00, 0xff, 0xff, 0x54, 0xbb, 0x0e, 0x52, 0xac, 0x0d, 0x00, 0x00, + // 1097 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1b, 0x45, + 0x1c, 0xcd, 0xa4, 0xa1, 0x8d, 0x27, 0x29, 0x2d, 0xe3, 0x40, 0x53, 0xd3, 0xd8, 0xe9, 0x22, 0x20, + 0x54, 0xf2, 0x8e, 0xe2, 0x50, 0x68, 0x11, 0x42, 0xd4, 0xae, 0x02, 0x91, 0x10, 0x94, 0x55, 0x4e, + 0x08, 0xe4, 0xae, 0x77, 0xc7, 0xce, 0x2a, 0xf6, 0xce, 0x76, 0x77, 0x6d, 0x70, 0xdd, 0x20, 0x51, + 0x29, 0x42, 0x42, 0x15, 0x42, 0x42, 0xe2, 0x80, 0x38, 0x70, 0x43, 0xe2, 0x1b, 0xf0, 0x0d, 0x7a, + 0x42, 0x95, 0xb8, 0x70, 0x32, 0x55, 0xc2, 0x99, 0x43, 0xc4, 0x81, 0x23, 0x9a, 0x3f, 0xbb, 0x5e, + 0x77, 0x77, 0x13, 0x3b, 0x75, 0x4e, 0xb1, 0xe7, 0xf7, 0xef, 0xbd, 0x37, 0xe3, 0x79, 0x13, 0xf8, + 0x92, 0x55, 0x33, 0xb0, 0xee, 0x38, 0x4d, 0xcb, 0xd0, 0x7d, 0x8b, 0xda, 0x1e, 0xae, 0x13, 0x82, + 0x3b, 0xab, 0xf8, 0x4e, 0x9b, 0xb8, 0x5d, 0xd5, 0x71, 0xa9, 0x4f, 0xd1, 0x05, 0xab, 0x66, 0xa8, + 0xd1, 0x24, 0xb5, 0x4e, 0x88, 0xda, 0x59, 0xcd, 0x2d, 0x34, 0x68, 0x83, 0xf2, 0x1c, 0xcc, 0x3e, + 0x89, 0xf4, 0xdc, 0xa5, 0x06, 0xa5, 0x8d, 0x26, 0xc1, 0xba, 0x63, 0x61, 0xdd, 0xb6, 0xa9, 0x2f, + 0x8b, 0x44, 0x34, 0x6f, 0x50, 0xaf, 0x45, 0x3d, 0x5c, 0xd3, 0x3d, 0x36, 0xa8, 0x46, 0x7c, 0x7d, + 0x15, 0x1b, 0xd4, 0xb2, 0x65, 0xfc, 0x4a, 0x34, 0xce, 0x51, 0x84, 0x59, 0x8e, 0xde, 0xb0, 0x6c, + 0xde, 0x4c, 0xe6, 0x5e, 0x4e, 0x43, 0xcf, 0xf0, 0x45, 0x52, 0x0c, 0xea, 0x12, 0x6c, 0x6c, 0xe9, + 0xb6, 0x4d, 0x9a, 0x2c, 0x2c, 0x3f, 0x8a, 0x14, 0xe5, 0x01, 0x80, 0x85, 0x8f, 0xd9, 0xa0, 0x0d, + 0xdb, 0x20, 0xb6, 0x6f, 0x75, 0xac, 0xbb, 0xc4, 0xbc, 0xa5, 0x1b, 0xdb, 0xc4, 0xf7, 0x34, 0x72, + 0xa7, 0x4d, 0x3c, 0x1f, 0xad, 0x43, 0x38, 0x98, 0xbe, 0x08, 0x96, 0xc1, 0xca, 0x5c, 0xe9, 0x15, + 0x55, 0x40, 0x55, 0x19, 0x54, 0x55, 0x08, 0x26, 0xa1, 0xaa, 0xb7, 0xf4, 0x06, 0x91, 0xb5, 0x5a, + 0xa4, 0x12, 0x5d, 0x86, 0xf3, 0x3c, 0xb1, 0xba, 0x45, 0xac, 0xc6, 0x96, 0xbf, 0x38, 0xbd, 0x0c, + 0x56, 0x66, 0xb4, 0x39, 0xbe, 0xf6, 0x3e, 0x5f, 0x52, 0xbe, 0x01, 0x70, 0x39, 0x1d, 0x8e, 0xe7, + 0x50, 0xdb, 0x23, 0xa8, 0x0e, 0x17, 0xac, 0x48, 0xb8, 0xea, 0x88, 0xf8, 0x22, 0x58, 0x3e, 0xb5, + 0x32, 0x57, 0x2a, 0xaa, 0x29, 0x3b, 0xa6, 0x6e, 0x98, 0xac, 0xa6, 0x6e, 0x05, 0x1d, 0xd7, 0x09, + 0xf1, 0xca, 0x33, 0x0f, 0xfb, 0x85, 0x29, 0x2d, 0x6b, 0xc5, 0xe7, 0x29, 0xbb, 0x00, 0xe6, 0x53, + 0xc0, 0x04, 0xd2, 0xbc, 0x0b, 0x33, 0x62, 0x7a, 0xd5, 0x32, 0xa5, 0x32, 0x4b, 0x7c, 0x3e, 0x53, + 0x5d, 0x0d, 0xa4, 0xee, 0x30, 0x4d, 0x58, 0xd6, 0x86, 0x29, 0xe7, 0xcd, 0x3a, 0xf2, 0xfb, 0x28, + 0xa2, 0x7c, 0x9d, 0xbe, 0x47, 0xa1, 0x26, 0x26, 0xcc, 0x26, 0x68, 0x22, 0x21, 0x1d, 0x4b, 0x12, + 0x14, 0x97, 0x44, 0xf9, 0x1d, 0xc0, 0xd7, 0xd2, 0xb6, 0x67, 0x9d, 0xba, 0x15, 0xc1, 0x77, 0xd2, + 0xe7, 0xe6, 0x02, 0x3c, 0xe3, 0x50, 0x97, 0x4b, 0xcc, 0xd4, 0xc9, 0x68, 0xa7, 0xd9, 0xd7, 0x0d, + 0x13, 0x2d, 0x41, 0x28, 0x25, 0x66, 0xb1, 0x53, 0x3c, 0x96, 0x91, 0x2b, 0x09, 0xd2, 0xce, 0xc4, + 0xa5, 0xfd, 0x16, 0xc0, 0x2b, 0xa3, 0x10, 0x92, 0x2a, 0xdf, 0x9e, 0xe0, 0xc9, 0x4b, 0x3e, 0x73, + 0x9f, 0xc1, 0x8b, 0x1c, 0xcf, 0x26, 0xf5, 0xf5, 0xa6, 0x46, 0x8c, 0x0e, 0x4f, 0x9d, 0xd4, 0x69, + 0x53, 0x7e, 0x04, 0x30, 0x97, 0xd4, 0x5f, 0xf2, 0xbb, 0x07, 0x33, 0x2e, 0x31, 0x3a, 0xd5, 0x3a, + 0x21, 0x01, 0xa9, 0x8b, 0x43, 0x1b, 0x16, 0x6c, 0x55, 0x85, 0x5a, 0x76, 0xf9, 0x26, 0x6b, 0x7e, + 0xd0, 0x2f, 0x9c, 0xef, 0xea, 0xad, 0xe6, 0x5b, 0x4a, 0x58, 0xa9, 0xfc, 0xfa, 0x57, 0x61, 0xa5, + 0x61, 0xf9, 0x5b, 0xed, 0x9a, 0x6a, 0xd0, 0x16, 0x96, 0x97, 0x9a, 0xf8, 0x53, 0xf4, 0xcc, 0x6d, + 0xec, 0x77, 0x1d, 0xe2, 0xf1, 0x26, 0x9e, 0x36, 0xeb, 0x4a, 0x14, 0xca, 0xa7, 0x70, 0x71, 0x80, + 0xed, 0x86, 0xb1, 0x3d, 0x59, 0xea, 0x3f, 0x80, 0xa8, 0xb4, 0x61, 0x7b, 0xc9, 0xbc, 0x0b, 0x67, + 0x75, 0x63, 0x7b, 0x44, 0xe2, 0x15, 0x49, 0xfc, 0x9c, 0x20, 0x1e, 0x14, 0x8e, 0xc7, 0xfb, 0x8c, + 0x2e, 0x20, 0x28, 0xb7, 0xe1, 0xa5, 0x01, 0xae, 0x4d, 0xab, 0x45, 0x68, 0xdb, 0x9f, 0x2c, 0xf5, + 0x5f, 0x00, 0x5c, 0x4a, 0x19, 0x21, 0xe9, 0xef, 0x02, 0x38, 0xef, 0x8b, 0xf5, 0x11, 0x35, 0x78, + 0x4f, 0x6a, 0x90, 0x15, 0x1a, 0x44, 0x8b, 0xc7, 0xd3, 0x61, 0xce, 0x1f, 0xe0, 0x51, 0x7e, 0x0a, + 0xae, 0xba, 0x0a, 0x6d, 0xdb, 0x3e, 0x71, 0x1d, 0xdd, 0xf5, 0xbb, 0x37, 0x4c, 0xd3, 0x25, 0x5e, + 0xa8, 0xc7, 0xeb, 0x43, 0xbf, 0x7a, 0x26, 0x48, 0xa6, 0xfc, 0xfc, 0x41, 0xbf, 0xf0, 0x9c, 0x40, + 0x32, 0x88, 0x29, 0xd1, 0xcb, 0xa0, 0x02, 0xcf, 0xb9, 0xa4, 0xa9, 0x77, 0x89, 0x5b, 0xd5, 0x45, + 0x3f, 0x71, 0x99, 0x94, 0x73, 0x07, 0xfd, 0xc2, 0x0b, 0xc1, 0x09, 0x1e, 0x4a, 0x50, 0xb4, 0x67, + 0xe5, 0x8a, 0x44, 0xa0, 0x74, 0xa4, 0x3b, 0x25, 0xa2, 0x93, 0x52, 0x6a, 0x70, 0xc1, 0x88, 0x84, + 0xc3, 0x69, 0x02, 0x68, 0xe1, 0xa0, 0x5f, 0x78, 0x51, 0x02, 0x4d, 0xc8, 0x52, 0xb4, 0xac, 0x11, + 0xef, 0x5d, 0xfa, 0xf9, 0x2c, 0x7c, 0x86, 0x0f, 0x46, 0xbf, 0x01, 0x98, 0x4d, 0xb8, 0xab, 0xd0, + 0xb5, 0xd4, 0xbb, 0xe7, 0x08, 0x77, 0xcf, 0x5d, 0x3f, 0x46, 0xa5, 0xa0, 0xaa, 0x14, 0xef, 0xff, + 0xf1, 0xf7, 0xf7, 0xd3, 0xaf, 0xa2, 0x97, 0xb1, 0x7c, 0x8b, 0x84, 0x6f, 0x90, 0xa4, 0x5b, 0x12, + 0x3d, 0x98, 0x86, 0x28, 0xde, 0x0e, 0xbd, 0x39, 0x2e, 0x80, 0x00, 0xf9, 0xb5, 0xf1, 0x0b, 0x25, + 0xf0, 0xfb, 0x80, 0x23, 0xbf, 0x87, 0xee, 0x8e, 0x82, 0x1c, 0x33, 0xbb, 0xc1, 0xbd, 0xf0, 0x47, + 0xa8, 0x4a, 0x37, 0xda, 0x09, 0x9f, 0x55, 0x91, 0xd8, 0xe0, 0xf8, 0xed, 0x60, 0x8f, 0x01, 0xb5, + 0x0d, 0x12, 0x8d, 0x07, 0x6b, 0x3b, 0xe8, 0x1f, 0x00, 0x97, 0x0e, 0xb5, 0x1d, 0x54, 0x1e, 0x7b, + 0x6b, 0x62, 0x26, 0x9c, 0xab, 0x3c, 0x55, 0x0f, 0xa9, 0xd7, 0x4d, 0x2e, 0xd7, 0x3b, 0xe8, 0xed, + 0x91, 0x36, 0x1a, 0xf7, 0x42, 0x81, 0x7a, 0x11, 0x39, 0xd0, 0x7f, 0x00, 0x9e, 0x1d, 0xf2, 0x1d, + 0x54, 0x3a, 0x1c, 0x5c, 0x92, 0x09, 0xe6, 0xd6, 0xc6, 0xaa, 0x91, 0x04, 0xbe, 0xe4, 0x04, 0xbe, + 0x40, 0x9d, 0x18, 0x01, 0x9f, 0xe5, 0x57, 0x43, 0xef, 0x3a, 0xa1, 0xbd, 0xfe, 0x17, 0xc0, 0xf9, + 0xa8, 0xef, 0xa0, 0xd5, 0x11, 0x58, 0x0c, 0x5b, 0x60, 0xae, 0x34, 0x4e, 0x89, 0xe4, 0xbd, 0xc3, + 0x79, 0x7f, 0x8e, 0xda, 0x29, 0xbc, 0x03, 0xeb, 0x3a, 0x21, 0xda, 0xbb, 0xd3, 0xf0, 0xfc, 0x93, + 0x9e, 0x83, 0xae, 0x8e, 0xc0, 0x23, 0x6e, 0x83, 0xb9, 0x37, 0xc6, 0x2d, 0x93, 0x12, 0x7c, 0x25, + 0x7e, 0xeb, 0x3d, 0xd4, 0x4d, 0xd1, 0x20, 0x6a, 0x5d, 0x27, 0xa4, 0xc3, 0x63, 0x00, 0xb3, 0x09, + 0x9e, 0x71, 0xd4, 0xad, 0x9d, 0x6e, 0x82, 0x47, 0xdd, 0xda, 0x87, 0x18, 0x94, 0xb2, 0xc9, 0xf5, + 0xf8, 0x10, 0x7d, 0x10, 0xd3, 0x23, 0xc9, 0x91, 0x70, 0xef, 0x09, 0x57, 0x8c, 0x48, 0x11, 0x11, + 0xa0, 0xfc, 0xd1, 0xc3, 0xbd, 0x3c, 0x78, 0xb4, 0x97, 0x07, 0x8f, 0xf7, 0xf2, 0xe0, 0xbb, 0xfd, + 0xfc, 0xd4, 0xa3, 0xfd, 0xfc, 0xd4, 0x9f, 0xfb, 0xf9, 0xa9, 0x4f, 0xae, 0xc6, 0x9f, 0x02, 0x56, + 0xcd, 0x28, 0x36, 0x28, 0xee, 0xac, 0xe1, 0x16, 0x35, 0xdb, 0x4d, 0xe2, 0x09, 0x18, 0xa5, 0xeb, + 0x45, 0x86, 0x84, 0xbf, 0x0e, 0x6a, 0xa7, 0xf9, 0x3f, 0xa8, 0x6b, 0xff, 0x07, 0x00, 0x00, 0xff, + 0xff, 0x32, 0xba, 0xf3, 0xf8, 0xa6, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -744,6 +856,8 @@ type QueryClient interface { TotalAckFees(ctx context.Context, in *QueryTotalAckFeesRequest, opts ...grpc.CallOption) (*QueryTotalAckFeesResponse, error) // TotalTimeoutFees returns the total timeout fees for a packet given its identifier TotalTimeoutFees(ctx context.Context, in *QueryTotalTimeoutFeesRequest, opts ...grpc.CallOption) (*QueryTotalTimeoutFeesResponse, error) + // CounterpartyAddress returns the registered counterparty address for forward relaying + CounterpartyAddress(ctx context.Context, in *QueryCounterpartyAddressRequest, opts ...grpc.CallOption) (*QueryCounterpartyAddressResponse, error) } type queryClient struct { @@ -808,6 +922,15 @@ func (c *queryClient) TotalTimeoutFees(ctx context.Context, in *QueryTotalTimeou return out, nil } +func (c *queryClient) CounterpartyAddress(ctx context.Context, in *QueryCounterpartyAddressRequest, opts ...grpc.CallOption) (*QueryCounterpartyAddressResponse, error) { + out := new(QueryCounterpartyAddressResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/CounterpartyAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // IncentivizedPackets returns all incentivized packets and their associated fees @@ -822,6 +945,8 @@ type QueryServer interface { TotalAckFees(context.Context, *QueryTotalAckFeesRequest) (*QueryTotalAckFeesResponse, error) // TotalTimeoutFees returns the total timeout fees for a packet given its identifier TotalTimeoutFees(context.Context, *QueryTotalTimeoutFeesRequest) (*QueryTotalTimeoutFeesResponse, error) + // CounterpartyAddress returns the registered counterparty address for forward relaying + CounterpartyAddress(context.Context, *QueryCounterpartyAddressRequest) (*QueryCounterpartyAddressResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -846,6 +971,9 @@ func (*UnimplementedQueryServer) TotalAckFees(ctx context.Context, req *QueryTot func (*UnimplementedQueryServer) TotalTimeoutFees(ctx context.Context, req *QueryTotalTimeoutFeesRequest) (*QueryTotalTimeoutFeesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method TotalTimeoutFees not implemented") } +func (*UnimplementedQueryServer) CounterpartyAddress(ctx context.Context, req *QueryCounterpartyAddressRequest) (*QueryCounterpartyAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CounterpartyAddress not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -959,6 +1087,24 @@ func _Query_TotalTimeoutFees_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Query_CounterpartyAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryCounterpartyAddressRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).CounterpartyAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/CounterpartyAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).CounterpartyAddress(ctx, req.(*QueryCounterpartyAddressRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "ibc.applications.fee.v1.Query", HandlerType: (*QueryServer)(nil), @@ -987,6 +1133,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "TotalTimeoutFees", Handler: _Query_TotalTimeoutFees_Handler, }, + { + MethodName: "CounterpartyAddress", + Handler: _Query_CounterpartyAddress_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "ibc/applications/fee/v1/query.proto", @@ -1441,6 +1591,73 @@ func (m *QueryTotalTimeoutFeesResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *QueryCounterpartyAddressRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryCounterpartyAddressRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryCounterpartyAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RelayerAddress) > 0 { + i -= len(m.RelayerAddress) + copy(dAtA[i:], m.RelayerAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.RelayerAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryCounterpartyAddressResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryCounterpartyAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryCounterpartyAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CounterpartyAddress) > 0 { + i -= len(m.CounterpartyAddress) + copy(dAtA[i:], m.CounterpartyAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.CounterpartyAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -1625,6 +1842,36 @@ func (m *QueryTotalTimeoutFeesResponse) Size() (n int) { return n } +func (m *QueryCounterpartyAddressRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.RelayerAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryCounterpartyAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.CounterpartyAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2759,6 +3006,202 @@ func (m *QueryTotalTimeoutFeesResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryCounterpartyAddressRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryCounterpartyAddressRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryCounterpartyAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RelayerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RelayerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryCounterpartyAddressResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryCounterpartyAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryCounterpartyAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CounterpartyAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/29-fee/types/query.pb.gw.go b/modules/apps/29-fee/types/query.pb.gw.go index 8775f7404fd..0210f400710 100644 --- a/modules/apps/29-fee/types/query.pb.gw.go +++ b/modules/apps/29-fee/types/query.pb.gw.go @@ -625,6 +625,82 @@ func local_request_Query_TotalTimeoutFees_0(ctx context.Context, marshaler runti } +func request_Query_CounterpartyAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCounterpartyAddressRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["relayer_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + } + + protoReq.RelayerAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + } + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + msg, err := client.CounterpartyAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_CounterpartyAddress_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCounterpartyAddressRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["relayer_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + } + + protoReq.RelayerAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + } + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + msg, err := server.CounterpartyAddress(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -751,6 +827,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_CounterpartyAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_CounterpartyAddress_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_CounterpartyAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -912,6 +1008,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_CounterpartyAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_CounterpartyAddress_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_CounterpartyAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -927,6 +1043,8 @@ var ( pattern_Query_TotalAckFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_ack_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_TotalTimeoutFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_timeout_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_CounterpartyAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"ibc", "apps", "fee", "v1", "counterparty_address", "relayer_address", "channel", "channel_id"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -941,4 +1059,6 @@ var ( forward_Query_TotalAckFees_0 = runtime.ForwardResponseMessage forward_Query_TotalTimeoutFees_0 = runtime.ForwardResponseMessage + + forward_Query_CounterpartyAddress_0 = runtime.ForwardResponseMessage ) diff --git a/proto/ibc/applications/fee/v1/query.proto b/proto/ibc/applications/fee/v1/query.proto index 3e5d6b8740d..689617e6ff5 100644 --- a/proto/ibc/applications/fee/v1/query.proto +++ b/proto/ibc/applications/fee/v1/query.proto @@ -48,6 +48,11 @@ service Query { option (google.api.http).get = "/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/" "{packet_id.channel_id}/sequence/{packet_id.sequence}"; } + + // CounterpartyAddress returns the registered counterparty address for forward relaying + rpc CounterpartyAddress(QueryCounterpartyAddressRequest) returns (QueryCounterpartyAddressResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/counterparty_address/{relayer_address}/channel/{channel_id}"; + } } // QueryIncentivizedPacketsRequest defines the request type for the IncentivizedPackets rpc @@ -142,3 +147,17 @@ message QueryTotalTimeoutFeesResponse { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; } + +// QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc +message QueryCounterpartyAddressRequest { + // unique channel identifier + string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + // the relayer address to which the counterparty is registered + string relayer_address = 2 [(gogoproto.moretags) = "yaml:\"relayer_address\""]; +} + +// QueryCounterpartyAddressResponse defines the response type for the CounterpartyAddress rpc +message QueryCounterpartyAddressResponse { + // the counterparty address used to compensate forward relaying + string counterparty_address = 1 [(gogoproto.moretags) = "yaml:\"counterparty_address\""]; +} From 8451c6334518507748b8ef60c90db50a9e527e66 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 7 Apr 2022 17:44:05 +0200 Subject: [PATCH 062/275] chore: fix go ctx arg naming in ics29 grpc queries (#1226) --- modules/apps/29-fee/keeper/grpc_query.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/apps/29-fee/keeper/grpc_query.go b/modules/apps/29-fee/keeper/grpc_query.go index 6fbb598945f..ea893db61c3 100644 --- a/modules/apps/29-fee/keeper/grpc_query.go +++ b/modules/apps/29-fee/keeper/grpc_query.go @@ -15,13 +15,13 @@ import ( var _ types.QueryServer = Keeper{} -// IncentivizedPackets implements the IncentivizedPackets gRPC method -func (k Keeper) IncentivizedPackets(c context.Context, req *types.QueryIncentivizedPacketsRequest) (*types.QueryIncentivizedPacketsResponse, error) { +// IncentivizedPackets implements the Query/IncentivizedPackets gRPC method +func (k Keeper) IncentivizedPackets(goCtx context.Context, req *types.QueryIncentivizedPacketsRequest) (*types.QueryIncentivizedPacketsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } - ctx := sdk.UnwrapSDKContext(c).WithBlockHeight(int64(req.QueryHeight)) + ctx := sdk.UnwrapSDKContext(goCtx).WithBlockHeight(int64(req.QueryHeight)) var identifiedPackets []types.IdentifiedPacketFees store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.FeesInEscrowPrefix)) @@ -45,13 +45,13 @@ func (k Keeper) IncentivizedPackets(c context.Context, req *types.QueryIncentivi }, nil } -// IncentivizedPacket implements the IncentivizedPacket gRPC method -func (k Keeper) IncentivizedPacket(c context.Context, req *types.QueryIncentivizedPacketRequest) (*types.QueryIncentivizedPacketResponse, error) { +// IncentivizedPacket implements the Query/IncentivizedPacket gRPC method +func (k Keeper) IncentivizedPacket(goCtx context.Context, req *types.QueryIncentivizedPacketRequest) (*types.QueryIncentivizedPacketResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } - ctx := sdk.UnwrapSDKContext(c).WithBlockHeight(int64(req.QueryHeight)) + ctx := sdk.UnwrapSDKContext(goCtx).WithBlockHeight(int64(req.QueryHeight)) feesInEscrow, exists := k.GetFeesInEscrow(ctx, req.PacketId) if !exists { @@ -65,7 +65,7 @@ func (k Keeper) IncentivizedPacket(c context.Context, req *types.QueryIncentiviz }, nil } -// IncentivizedPacketsForChannel implements the IncentivizedPacketsForChannel gRPC method +// IncentivizedPacketsForChannel implements the Query/IncentivizedPacketsForChannel gRPC method func (k Keeper) IncentivizedPacketsForChannel(goCtx context.Context, req *types.QueryIncentivizedPacketsForChannelRequest) (*types.QueryIncentivizedPacketsForChannelResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") From 0be0d79781e8065a8b786a60184328d5ac23f199 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 7 Apr 2022 18:00:11 +0200 Subject: [PATCH 063/275] chore: ics29 module housekeeping cleanup (#1227) --- modules/apps/29-fee/module.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/modules/apps/29-fee/module.go b/modules/apps/29-fee/module.go index bb9b7081c7c..e493e047837 100644 --- a/modules/apps/29-fee/module.go +++ b/modules/apps/29-fee/module.go @@ -20,10 +20,6 @@ import ( "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/client/cli" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/keeper" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - - // "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/client/cli" - // "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/simulation" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" ) @@ -99,7 +95,6 @@ func NewAppModule(k keeper.Keeper) AppModule { // RegisterInvariants implements the AppModule interface func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - // TODO } // Route implements the AppModule interface @@ -154,7 +149,7 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V // AppModuleSimulation functions // GenerateGenesisState creates a randomized GenState of the 29-fee module. -func (AppModule) GenerateGenesisState(simState *module.SimulationState) { +func (AppModule) GenerateGenesisState(_ *module.SimulationState) { } // ProposalContents doesn't return any content functions for governance proposals. @@ -163,14 +158,12 @@ func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedP } // RandomizedParams creates randomized ibc-29-fee param changes for the simulator. -func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { - // return simulation.ParamChanges(r) +func (AppModule) RandomizedParams(_ *rand.Rand) []simtypes.ParamChange { return nil } // RegisterStoreDecoder registers a decoder for 29-fee module's types -func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - // sdr[types.StoreKey] = simulation.NewDecodeStore(am.keeper) +func (am AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) { } // WeightedOperations returns the all the 29-fee module operations with their respective weights. From f4675d3ff2a7a40878f8e1ddd13aa427708c591e Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 7 Apr 2022 18:11:37 +0200 Subject: [PATCH 064/275] feat: ics29 fee enabled channel queries (#1225) * adding protobuf codegen * adding grpc queries and tests * adding clis for queries * adding changelog * resolving nits from pr review * updating grpc gateway options --- CHANGELOG.md | 2 + docs/ibc/proto-docs.md | 68 ++ modules/apps/29-fee/client/cli/cli.go | 2 + modules/apps/29-fee/client/cli/query.go | 76 ++ modules/apps/29-fee/keeper/grpc_query.go | 51 + modules/apps/29-fee/keeper/grpc_query_test.go | 158 +++ modules/apps/29-fee/types/query.pb.go | 1078 +++++++++++++++-- modules/apps/29-fee/types/query.pb.gw.go | 200 +++ proto/ibc/applications/fee/v1/query.proto | 40 + 9 files changed, 1573 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7b86ca8d39..75ea3755d85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (apps/29-fee) [\#1224](https://github.com/cosmos/ibc-go/pull/1224) Adding Query/CounterpartyAddress and CLI to ICS29 fee middleware +* (apps/29-fee) [\#1225](https://github.com/cosmos/ibc-go/pull/1225) Adding Query/FeeEnabledChannel and Query/FeeEnabledChannels with CLIs to ICS29 fee middleware. + ### Bug Fixes * (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index ad54c1cf9d6..267feaeb581 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -46,6 +46,10 @@ - [ibc/applications/fee/v1/query.proto](#ibc/applications/fee/v1/query.proto) - [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) - [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) + - [QueryFeeEnabledChannelRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelRequest) + - [QueryFeeEnabledChannelResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelResponse) + - [QueryFeeEnabledChannelsRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest) + - [QueryFeeEnabledChannelsResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse) - [QueryIncentivizedPacketRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketRequest) - [QueryIncentivizedPacketResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketResponse) - [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) @@ -939,6 +943,68 @@ QueryCounterpartyAddressResponse defines the response type for the CounterpartyA + + +### QueryFeeEnabledChannelRequest +QueryFeeEnabledChannelRequest defines the request type for the FeeEnabledChannel rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | unique port identifier | +| `channel_id` | [string](#string) | | unique channel identifier | + + + + + + + + +### QueryFeeEnabledChannelResponse +QueryFeeEnabledChannelResponse defines the response type for the FeeEnabledChannel rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `fee_enabled` | [bool](#bool) | | boolean flag representing the fee enabled channel status | + + + + + + + + +### QueryFeeEnabledChannelsRequest +QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines an optional pagination for the request. | +| `query_height` | [uint64](#uint64) | | block height at which to query | + + + + + + + + +### QueryFeeEnabledChannelsResponse +QueryFeeEnabledChannelsResponse defines the response type for the FeeEnabledChannels rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `fee_enabled_channels` | [FeeEnabledChannel](#ibc.applications.fee.v1.FeeEnabledChannel) | repeated | list of fee enabled channels | + + + + + + ### QueryIncentivizedPacketRequest @@ -1145,6 +1211,8 @@ Query defines the ICS29 gRPC querier service. | `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| | `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| | `CounterpartyAddress` | [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) | [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) | CounterpartyAddress returns the registered counterparty address for forward relaying | GET|/ibc/apps/fee/v1/counterparty_address/{relayer_address}/channel/{channel_id}| +| `FeeEnabledChannels` | [QueryFeeEnabledChannelsRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest) | [QueryFeeEnabledChannelsResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse) | FeeEnabledChannels returns a list of all fee enabled channels | GET|/ibc/apps/fee/v1/fee_enabled| +| `FeeEnabledChannel` | [QueryFeeEnabledChannelRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelRequest) | [QueryFeeEnabledChannelResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelResponse) | FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel | GET|/ibc/apps/fee/v1/fee_enabled/port/{port_id}/channel/{channel_id}| diff --git a/modules/apps/29-fee/client/cli/cli.go b/modules/apps/29-fee/client/cli/cli.go index 2279e741556..c2afc6e25ed 100644 --- a/modules/apps/29-fee/client/cli/cli.go +++ b/modules/apps/29-fee/client/cli/cli.go @@ -21,6 +21,8 @@ func GetQueryCmd() *cobra.Command { GetCmdTotalAckFees(), GetCmdTotalTimeoutFees(), GetCmdCounterpartyAddress(), + GetCmdFeeEnabledChannel(), + GetCmdFeeEnabledChannels(), ) return queryCmd diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index 9c96afc9478..9eca35cae48 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -274,3 +274,79 @@ func GetCmdCounterpartyAddress() *cobra.Command { return cmd } + +// GetCmdFeeEnabledChannels returns the command handler for the Query/FeeEnabledChannels rpc. +func GetCmdFeeEnabledChannels() *cobra.Command { + cmd := &cobra.Command{ + Use: "channels", + Short: "Query the ibc-fee enabled channels", + Long: "Query the ibc-fee enabled channels", + Args: cobra.NoArgs, + Example: fmt.Sprintf("%s query ibc-fee channels", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryFeeEnabledChannelsRequest{ + Pagination: pageReq, + QueryHeight: uint64(clientCtx.Height), + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.FeeEnabledChannels(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "channels") + + return cmd +} + +// GetCmdFeeEnabledChannel returns the command handler for the Query/FeeEnabledChannel rpc. +func GetCmdFeeEnabledChannel() *cobra.Command { + cmd := &cobra.Command{ + Use: "channel [port-id] [channel-id]", + Short: "Query the ibc-fee enabled status of a channel", + Long: "Query the ibc-fee enabled status of a channel", + Args: cobra.ExactArgs(2), + Example: fmt.Sprintf("%s query ibc-fee channel transfer channel-6", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + req := &types.QueryFeeEnabledChannelRequest{ + PortId: args[0], + ChannelId: args[1], + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.FeeEnabledChannel(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/modules/apps/29-fee/keeper/grpc_query.go b/modules/apps/29-fee/keeper/grpc_query.go index ea893db61c3..10da5bc5595 100644 --- a/modules/apps/29-fee/keeper/grpc_query.go +++ b/modules/apps/29-fee/keeper/grpc_query.go @@ -191,3 +191,54 @@ func (k Keeper) CounterpartyAddress(goCtx context.Context, req *types.QueryCount CounterpartyAddress: counterpartyAddr, }, nil } + +// FeeEnabledChannels implements the Query/FeeEnabledChannels gRPC method and returns a list of fee enabled channels +func (k Keeper) FeeEnabledChannels(goCtx context.Context, req *types.QueryFeeEnabledChannelsRequest) (*types.QueryFeeEnabledChannelsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(goCtx).WithBlockHeight(int64(req.QueryHeight)) + + var feeEnabledChannels []types.FeeEnabledChannel + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.FeeEnabledKeyPrefix)) + _, err := query.Paginate(store, req.Pagination, func(key, value []byte) error { + portID, channelID, err := types.ParseKeyFeeEnabled(types.FeeEnabledKeyPrefix + string(key)) + if err != nil { + return err + } + + feeEnabledChannel := types.FeeEnabledChannel{ + PortId: portID, + ChannelId: channelID, + } + + feeEnabledChannels = append(feeEnabledChannels, feeEnabledChannel) + + return nil + }) + + if err != nil { + return nil, status.Error(codes.NotFound, err.Error()) + } + + return &types.QueryFeeEnabledChannelsResponse{ + FeeEnabledChannels: feeEnabledChannels, + }, nil +} + +// FeeEnabledChannel implements the Query/FeeEnabledChannel gRPC method and returns true if the provided +// port and channel identifiers belong to a fee enabled channel +func (k Keeper) FeeEnabledChannel(goCtx context.Context, req *types.QueryFeeEnabledChannelRequest) (*types.QueryFeeEnabledChannelResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + isFeeEnabled := k.IsFeeEnabled(ctx, req.PortId, req.ChannelId) + + return &types.QueryFeeEnabledChannelResponse{ + FeeEnabled: isFeeEnabled, + }, nil +} diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index 9802dd9216c..516a31e87b2 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -493,3 +493,161 @@ func (suite *KeeperTestSuite) TestQueryCounterpartyAddress() { }) } } + +func (suite *KeeperTestSuite) TestQueryFeeEnabledChannels() { + var ( + req *types.QueryFeeEnabledChannelsRequest + expFeeEnabledChannels []types.FeeEnabledChannel + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "success: empty pagination", + func() { + req = &types.QueryFeeEnabledChannelsRequest{} + }, + true, + }, + { + "success: with multiple fee enabled channels", + func() { + suite.coordinator.Setup(suite.pathAToC) + + expChannel := types.FeeEnabledChannel{ + PortId: suite.pathAToC.EndpointA.ChannelConfig.PortID, + ChannelId: suite.pathAToC.EndpointA.ChannelID, + } + + expFeeEnabledChannels = append(expFeeEnabledChannels, expChannel) + }, + true, + }, + { + "success: pagination with multiple fee enabled channels", + func() { + // start at index 1, as channel-0 is already added to expFeeEnabledChannels below + for i := 1; i < 10; i++ { + channelID := channeltypes.FormatChannelIdentifier(uint64(i)) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, channelID) + + expChannel := types.FeeEnabledChannel{ + PortId: ibctesting.MockFeePort, + ChannelId: channelID, + } + + if i < 5 { // add only the first 5 channels, as our default pagination limit is 5 + expFeeEnabledChannels = append(expFeeEnabledChannels, expChannel) + } + } + + suite.chainA.NextBlock() + }, + true, + }, + { + "empty response", + func() { + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + expFeeEnabledChannels = nil + + suite.chainA.NextBlock() + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + suite.coordinator.Setup(suite.path) + + expChannel := types.FeeEnabledChannel{ + PortId: suite.path.EndpointA.ChannelConfig.PortID, + ChannelId: suite.path.EndpointA.ChannelID, + } + + expFeeEnabledChannels = []types.FeeEnabledChannel{expChannel} + + req = &types.QueryFeeEnabledChannelsRequest{ + Pagination: &query.PageRequest{ + Limit: 5, + CountTotal: false, + }, + QueryHeight: 0, + } + + tc.malleate() + + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.queryClient.FeeEnabledChannels(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expFeeEnabledChannels, res.FeeEnabledChannels) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryFeeEnabledChannel() { + var ( + req *types.QueryFeeEnabledChannelRequest + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "fee not enabled on channel", + func() { + req.ChannelId = "invalid-channel-id" + req.PortId = "invalid-port-id" + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + suite.coordinator.Setup(suite.path) + + req = &types.QueryFeeEnabledChannelRequest{ + PortId: suite.path.EndpointA.ChannelConfig.PortID, + ChannelId: suite.path.EndpointA.ChannelID, + } + + tc.malleate() + + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.queryClient.FeeEnabledChannel(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().True(res.FeeEnabled) + } else { + suite.Require().False(res.FeeEnabled) + } + }) + } +} diff --git a/modules/apps/29-fee/types/query.pb.go b/modules/apps/29-fee/types/query.pb.go index 850bb1eb19a..2d2231f85be 100644 --- a/modules/apps/29-fee/types/query.pb.go +++ b/modules/apps/29-fee/types/query.pb.go @@ -738,6 +738,208 @@ func (m *QueryCounterpartyAddressResponse) GetCounterpartyAddress() string { return "" } +// QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc +type QueryFeeEnabledChannelsRequest struct { + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` + // block height at which to query + QueryHeight uint64 `protobuf:"varint,2,opt,name=query_height,json=queryHeight,proto3" json:"query_height,omitempty"` +} + +func (m *QueryFeeEnabledChannelsRequest) Reset() { *m = QueryFeeEnabledChannelsRequest{} } +func (m *QueryFeeEnabledChannelsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryFeeEnabledChannelsRequest) ProtoMessage() {} +func (*QueryFeeEnabledChannelsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{14} +} +func (m *QueryFeeEnabledChannelsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeeEnabledChannelsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeeEnabledChannelsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryFeeEnabledChannelsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeeEnabledChannelsRequest.Merge(m, src) +} +func (m *QueryFeeEnabledChannelsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryFeeEnabledChannelsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeeEnabledChannelsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeeEnabledChannelsRequest proto.InternalMessageInfo + +func (m *QueryFeeEnabledChannelsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +func (m *QueryFeeEnabledChannelsRequest) GetQueryHeight() uint64 { + if m != nil { + return m.QueryHeight + } + return 0 +} + +// QueryFeeEnabledChannelsResponse defines the response type for the FeeEnabledChannels rpc +type QueryFeeEnabledChannelsResponse struct { + // list of fee enabled channels + FeeEnabledChannels []FeeEnabledChannel `protobuf:"bytes,1,rep,name=fee_enabled_channels,json=feeEnabledChannels,proto3" json:"fee_enabled_channels" yaml:"fee_enabled_channels"` +} + +func (m *QueryFeeEnabledChannelsResponse) Reset() { *m = QueryFeeEnabledChannelsResponse{} } +func (m *QueryFeeEnabledChannelsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryFeeEnabledChannelsResponse) ProtoMessage() {} +func (*QueryFeeEnabledChannelsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{15} +} +func (m *QueryFeeEnabledChannelsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeeEnabledChannelsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeeEnabledChannelsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryFeeEnabledChannelsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeeEnabledChannelsResponse.Merge(m, src) +} +func (m *QueryFeeEnabledChannelsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryFeeEnabledChannelsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeeEnabledChannelsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeeEnabledChannelsResponse proto.InternalMessageInfo + +func (m *QueryFeeEnabledChannelsResponse) GetFeeEnabledChannels() []FeeEnabledChannel { + if m != nil { + return m.FeeEnabledChannels + } + return nil +} + +// QueryFeeEnabledChannelRequest defines the request type for the FeeEnabledChannel rpc +type QueryFeeEnabledChannelRequest struct { + // unique port identifier + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + // unique channel identifier + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` +} + +func (m *QueryFeeEnabledChannelRequest) Reset() { *m = QueryFeeEnabledChannelRequest{} } +func (m *QueryFeeEnabledChannelRequest) String() string { return proto.CompactTextString(m) } +func (*QueryFeeEnabledChannelRequest) ProtoMessage() {} +func (*QueryFeeEnabledChannelRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{16} +} +func (m *QueryFeeEnabledChannelRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeeEnabledChannelRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeeEnabledChannelRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryFeeEnabledChannelRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeeEnabledChannelRequest.Merge(m, src) +} +func (m *QueryFeeEnabledChannelRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryFeeEnabledChannelRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeeEnabledChannelRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeeEnabledChannelRequest proto.InternalMessageInfo + +func (m *QueryFeeEnabledChannelRequest) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func (m *QueryFeeEnabledChannelRequest) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +// QueryFeeEnabledChannelResponse defines the response type for the FeeEnabledChannel rpc +type QueryFeeEnabledChannelResponse struct { + // boolean flag representing the fee enabled channel status + FeeEnabled bool `protobuf:"varint,1,opt,name=fee_enabled,json=feeEnabled,proto3" json:"fee_enabled,omitempty" yaml:"fee_enabled"` +} + +func (m *QueryFeeEnabledChannelResponse) Reset() { *m = QueryFeeEnabledChannelResponse{} } +func (m *QueryFeeEnabledChannelResponse) String() string { return proto.CompactTextString(m) } +func (*QueryFeeEnabledChannelResponse) ProtoMessage() {} +func (*QueryFeeEnabledChannelResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{17} +} +func (m *QueryFeeEnabledChannelResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFeeEnabledChannelResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFeeEnabledChannelResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryFeeEnabledChannelResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFeeEnabledChannelResponse.Merge(m, src) +} +func (m *QueryFeeEnabledChannelResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryFeeEnabledChannelResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFeeEnabledChannelResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFeeEnabledChannelResponse proto.InternalMessageInfo + +func (m *QueryFeeEnabledChannelResponse) GetFeeEnabled() bool { + if m != nil { + return m.FeeEnabled + } + return false +} + func init() { proto.RegisterType((*QueryIncentivizedPacketsRequest)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketsRequest") proto.RegisterType((*QueryIncentivizedPacketsResponse)(nil), "ibc.applications.fee.v1.QueryIncentivizedPacketsResponse") @@ -753,6 +955,10 @@ func init() { proto.RegisterType((*QueryTotalTimeoutFeesResponse)(nil), "ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse") proto.RegisterType((*QueryCounterpartyAddressRequest)(nil), "ibc.applications.fee.v1.QueryCounterpartyAddressRequest") proto.RegisterType((*QueryCounterpartyAddressResponse)(nil), "ibc.applications.fee.v1.QueryCounterpartyAddressResponse") + proto.RegisterType((*QueryFeeEnabledChannelsRequest)(nil), "ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest") + proto.RegisterType((*QueryFeeEnabledChannelsResponse)(nil), "ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse") + proto.RegisterType((*QueryFeeEnabledChannelRequest)(nil), "ibc.applications.fee.v1.QueryFeeEnabledChannelRequest") + proto.RegisterType((*QueryFeeEnabledChannelResponse)(nil), "ibc.applications.fee.v1.QueryFeeEnabledChannelResponse") } func init() { @@ -760,76 +966,88 @@ func init() { } var fileDescriptor_0638a8a78ca2503c = []byte{ - // 1097 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1b, 0x45, - 0x1c, 0xcd, 0xa4, 0xa1, 0x8d, 0x27, 0x29, 0x2d, 0xe3, 0x40, 0x53, 0xd3, 0xd8, 0xe9, 0x22, 0x20, - 0x54, 0xf2, 0x8e, 0xe2, 0x50, 0x68, 0x11, 0x42, 0xd4, 0xae, 0x02, 0x91, 0x10, 0x94, 0x55, 0x4e, - 0x08, 0xe4, 0xae, 0x77, 0xc7, 0xce, 0x2a, 0xf6, 0xce, 0x76, 0x77, 0x6d, 0x70, 0xdd, 0x20, 0x51, - 0x29, 0x42, 0x42, 0x15, 0x42, 0x42, 0xe2, 0x80, 0x38, 0x70, 0x43, 0xe2, 0x1b, 0xf0, 0x0d, 0x7a, - 0x42, 0x95, 0xb8, 0x70, 0x32, 0x55, 0xc2, 0x99, 0x43, 0xc4, 0x81, 0x23, 0x9a, 0x3f, 0xbb, 0x5e, - 0x77, 0x77, 0x13, 0x3b, 0x75, 0x4e, 0xb1, 0xe7, 0xf7, 0xef, 0xbd, 0x37, 0xe3, 0x79, 0x13, 0xf8, - 0x92, 0x55, 0x33, 0xb0, 0xee, 0x38, 0x4d, 0xcb, 0xd0, 0x7d, 0x8b, 0xda, 0x1e, 0xae, 0x13, 0x82, - 0x3b, 0xab, 0xf8, 0x4e, 0x9b, 0xb8, 0x5d, 0xd5, 0x71, 0xa9, 0x4f, 0xd1, 0x05, 0xab, 0x66, 0xa8, - 0xd1, 0x24, 0xb5, 0x4e, 0x88, 0xda, 0x59, 0xcd, 0x2d, 0x34, 0x68, 0x83, 0xf2, 0x1c, 0xcc, 0x3e, - 0x89, 0xf4, 0xdc, 0xa5, 0x06, 0xa5, 0x8d, 0x26, 0xc1, 0xba, 0x63, 0x61, 0xdd, 0xb6, 0xa9, 0x2f, - 0x8b, 0x44, 0x34, 0x6f, 0x50, 0xaf, 0x45, 0x3d, 0x5c, 0xd3, 0x3d, 0x36, 0xa8, 0x46, 0x7c, 0x7d, - 0x15, 0x1b, 0xd4, 0xb2, 0x65, 0xfc, 0x4a, 0x34, 0xce, 0x51, 0x84, 0x59, 0x8e, 0xde, 0xb0, 0x6c, - 0xde, 0x4c, 0xe6, 0x5e, 0x4e, 0x43, 0xcf, 0xf0, 0x45, 0x52, 0x0c, 0xea, 0x12, 0x6c, 0x6c, 0xe9, - 0xb6, 0x4d, 0x9a, 0x2c, 0x2c, 0x3f, 0x8a, 0x14, 0xe5, 0x01, 0x80, 0x85, 0x8f, 0xd9, 0xa0, 0x0d, - 0xdb, 0x20, 0xb6, 0x6f, 0x75, 0xac, 0xbb, 0xc4, 0xbc, 0xa5, 0x1b, 0xdb, 0xc4, 0xf7, 0x34, 0x72, - 0xa7, 0x4d, 0x3c, 0x1f, 0xad, 0x43, 0x38, 0x98, 0xbe, 0x08, 0x96, 0xc1, 0xca, 0x5c, 0xe9, 0x15, - 0x55, 0x40, 0x55, 0x19, 0x54, 0x55, 0x08, 0x26, 0xa1, 0xaa, 0xb7, 0xf4, 0x06, 0x91, 0xb5, 0x5a, - 0xa4, 0x12, 0x5d, 0x86, 0xf3, 0x3c, 0xb1, 0xba, 0x45, 0xac, 0xc6, 0x96, 0xbf, 0x38, 0xbd, 0x0c, - 0x56, 0x66, 0xb4, 0x39, 0xbe, 0xf6, 0x3e, 0x5f, 0x52, 0xbe, 0x01, 0x70, 0x39, 0x1d, 0x8e, 0xe7, - 0x50, 0xdb, 0x23, 0xa8, 0x0e, 0x17, 0xac, 0x48, 0xb8, 0xea, 0x88, 0xf8, 0x22, 0x58, 0x3e, 0xb5, - 0x32, 0x57, 0x2a, 0xaa, 0x29, 0x3b, 0xa6, 0x6e, 0x98, 0xac, 0xa6, 0x6e, 0x05, 0x1d, 0xd7, 0x09, - 0xf1, 0xca, 0x33, 0x0f, 0xfb, 0x85, 0x29, 0x2d, 0x6b, 0xc5, 0xe7, 0x29, 0xbb, 0x00, 0xe6, 0x53, - 0xc0, 0x04, 0xd2, 0xbc, 0x0b, 0x33, 0x62, 0x7a, 0xd5, 0x32, 0xa5, 0x32, 0x4b, 0x7c, 0x3e, 0x53, - 0x5d, 0x0d, 0xa4, 0xee, 0x30, 0x4d, 0x58, 0xd6, 0x86, 0x29, 0xe7, 0xcd, 0x3a, 0xf2, 0xfb, 0x28, - 0xa2, 0x7c, 0x9d, 0xbe, 0x47, 0xa1, 0x26, 0x26, 0xcc, 0x26, 0x68, 0x22, 0x21, 0x1d, 0x4b, 0x12, - 0x14, 0x97, 0x44, 0xf9, 0x1d, 0xc0, 0xd7, 0xd2, 0xb6, 0x67, 0x9d, 0xba, 0x15, 0xc1, 0x77, 0xd2, - 0xe7, 0xe6, 0x02, 0x3c, 0xe3, 0x50, 0x97, 0x4b, 0xcc, 0xd4, 0xc9, 0x68, 0xa7, 0xd9, 0xd7, 0x0d, - 0x13, 0x2d, 0x41, 0x28, 0x25, 0x66, 0xb1, 0x53, 0x3c, 0x96, 0x91, 0x2b, 0x09, 0xd2, 0xce, 0xc4, - 0xa5, 0xfd, 0x16, 0xc0, 0x2b, 0xa3, 0x10, 0x92, 0x2a, 0xdf, 0x9e, 0xe0, 0xc9, 0x4b, 0x3e, 0x73, - 0x9f, 0xc1, 0x8b, 0x1c, 0xcf, 0x26, 0xf5, 0xf5, 0xa6, 0x46, 0x8c, 0x0e, 0x4f, 0x9d, 0xd4, 0x69, - 0x53, 0x7e, 0x04, 0x30, 0x97, 0xd4, 0x5f, 0xf2, 0xbb, 0x07, 0x33, 0x2e, 0x31, 0x3a, 0xd5, 0x3a, - 0x21, 0x01, 0xa9, 0x8b, 0x43, 0x1b, 0x16, 0x6c, 0x55, 0x85, 0x5a, 0x76, 0xf9, 0x26, 0x6b, 0x7e, - 0xd0, 0x2f, 0x9c, 0xef, 0xea, 0xad, 0xe6, 0x5b, 0x4a, 0x58, 0xa9, 0xfc, 0xfa, 0x57, 0x61, 0xa5, - 0x61, 0xf9, 0x5b, 0xed, 0x9a, 0x6a, 0xd0, 0x16, 0x96, 0x97, 0x9a, 0xf8, 0x53, 0xf4, 0xcc, 0x6d, - 0xec, 0x77, 0x1d, 0xe2, 0xf1, 0x26, 0x9e, 0x36, 0xeb, 0x4a, 0x14, 0xca, 0xa7, 0x70, 0x71, 0x80, - 0xed, 0x86, 0xb1, 0x3d, 0x59, 0xea, 0x3f, 0x80, 0xa8, 0xb4, 0x61, 0x7b, 0xc9, 0xbc, 0x0b, 0x67, - 0x75, 0x63, 0x7b, 0x44, 0xe2, 0x15, 0x49, 0xfc, 0x9c, 0x20, 0x1e, 0x14, 0x8e, 0xc7, 0xfb, 0x8c, - 0x2e, 0x20, 0x28, 0xb7, 0xe1, 0xa5, 0x01, 0xae, 0x4d, 0xab, 0x45, 0x68, 0xdb, 0x9f, 0x2c, 0xf5, - 0x5f, 0x00, 0x5c, 0x4a, 0x19, 0x21, 0xe9, 0xef, 0x02, 0x38, 0xef, 0x8b, 0xf5, 0x11, 0x35, 0x78, - 0x4f, 0x6a, 0x90, 0x15, 0x1a, 0x44, 0x8b, 0xc7, 0xd3, 0x61, 0xce, 0x1f, 0xe0, 0x51, 0x7e, 0x0a, - 0xae, 0xba, 0x0a, 0x6d, 0xdb, 0x3e, 0x71, 0x1d, 0xdd, 0xf5, 0xbb, 0x37, 0x4c, 0xd3, 0x25, 0x5e, - 0xa8, 0xc7, 0xeb, 0x43, 0xbf, 0x7a, 0x26, 0x48, 0xa6, 0xfc, 0xfc, 0x41, 0xbf, 0xf0, 0x9c, 0x40, - 0x32, 0x88, 0x29, 0xd1, 0xcb, 0xa0, 0x02, 0xcf, 0xb9, 0xa4, 0xa9, 0x77, 0x89, 0x5b, 0xd5, 0x45, - 0x3f, 0x71, 0x99, 0x94, 0x73, 0x07, 0xfd, 0xc2, 0x0b, 0xc1, 0x09, 0x1e, 0x4a, 0x50, 0xb4, 0x67, - 0xe5, 0x8a, 0x44, 0xa0, 0x74, 0xa4, 0x3b, 0x25, 0xa2, 0x93, 0x52, 0x6a, 0x70, 0xc1, 0x88, 0x84, - 0xc3, 0x69, 0x02, 0x68, 0xe1, 0xa0, 0x5f, 0x78, 0x51, 0x02, 0x4d, 0xc8, 0x52, 0xb4, 0xac, 0x11, - 0xef, 0x5d, 0xfa, 0xf9, 0x2c, 0x7c, 0x86, 0x0f, 0x46, 0xbf, 0x01, 0x98, 0x4d, 0xb8, 0xab, 0xd0, - 0xb5, 0xd4, 0xbb, 0xe7, 0x08, 0x77, 0xcf, 0x5d, 0x3f, 0x46, 0xa5, 0xa0, 0xaa, 0x14, 0xef, 0xff, - 0xf1, 0xf7, 0xf7, 0xd3, 0xaf, 0xa2, 0x97, 0xb1, 0x7c, 0x8b, 0x84, 0x6f, 0x90, 0xa4, 0x5b, 0x12, - 0x3d, 0x98, 0x86, 0x28, 0xde, 0x0e, 0xbd, 0x39, 0x2e, 0x80, 0x00, 0xf9, 0xb5, 0xf1, 0x0b, 0x25, - 0xf0, 0xfb, 0x80, 0x23, 0xbf, 0x87, 0xee, 0x8e, 0x82, 0x1c, 0x33, 0xbb, 0xc1, 0xbd, 0xf0, 0x47, - 0xa8, 0x4a, 0x37, 0xda, 0x09, 0x9f, 0x55, 0x91, 0xd8, 0xe0, 0xf8, 0xed, 0x60, 0x8f, 0x01, 0xb5, - 0x0d, 0x12, 0x8d, 0x07, 0x6b, 0x3b, 0xe8, 0x1f, 0x00, 0x97, 0x0e, 0xb5, 0x1d, 0x54, 0x1e, 0x7b, - 0x6b, 0x62, 0x26, 0x9c, 0xab, 0x3c, 0x55, 0x0f, 0xa9, 0xd7, 0x4d, 0x2e, 0xd7, 0x3b, 0xe8, 0xed, - 0x91, 0x36, 0x1a, 0xf7, 0x42, 0x81, 0x7a, 0x11, 0x39, 0xd0, 0x7f, 0x00, 0x9e, 0x1d, 0xf2, 0x1d, - 0x54, 0x3a, 0x1c, 0x5c, 0x92, 0x09, 0xe6, 0xd6, 0xc6, 0xaa, 0x91, 0x04, 0xbe, 0xe4, 0x04, 0xbe, - 0x40, 0x9d, 0x18, 0x01, 0x9f, 0xe5, 0x57, 0x43, 0xef, 0x3a, 0xa1, 0xbd, 0xfe, 0x17, 0xc0, 0xf9, - 0xa8, 0xef, 0xa0, 0xd5, 0x11, 0x58, 0x0c, 0x5b, 0x60, 0xae, 0x34, 0x4e, 0x89, 0xe4, 0xbd, 0xc3, - 0x79, 0x7f, 0x8e, 0xda, 0x29, 0xbc, 0x03, 0xeb, 0x3a, 0x21, 0xda, 0xbb, 0xd3, 0xf0, 0xfc, 0x93, - 0x9e, 0x83, 0xae, 0x8e, 0xc0, 0x23, 0x6e, 0x83, 0xb9, 0x37, 0xc6, 0x2d, 0x93, 0x12, 0x7c, 0x25, - 0x7e, 0xeb, 0x3d, 0xd4, 0x4d, 0xd1, 0x20, 0x6a, 0x5d, 0x27, 0xa4, 0xc3, 0x63, 0x00, 0xb3, 0x09, - 0x9e, 0x71, 0xd4, 0xad, 0x9d, 0x6e, 0x82, 0x47, 0xdd, 0xda, 0x87, 0x18, 0x94, 0xb2, 0xc9, 0xf5, - 0xf8, 0x10, 0x7d, 0x10, 0xd3, 0x23, 0xc9, 0x91, 0x70, 0xef, 0x09, 0x57, 0x8c, 0x48, 0x11, 0x11, - 0xa0, 0xfc, 0xd1, 0xc3, 0xbd, 0x3c, 0x78, 0xb4, 0x97, 0x07, 0x8f, 0xf7, 0xf2, 0xe0, 0xbb, 0xfd, - 0xfc, 0xd4, 0xa3, 0xfd, 0xfc, 0xd4, 0x9f, 0xfb, 0xf9, 0xa9, 0x4f, 0xae, 0xc6, 0x9f, 0x02, 0x56, - 0xcd, 0x28, 0x36, 0x28, 0xee, 0xac, 0xe1, 0x16, 0x35, 0xdb, 0x4d, 0xe2, 0x09, 0x18, 0xa5, 0xeb, - 0x45, 0x86, 0x84, 0xbf, 0x0e, 0x6a, 0xa7, 0xf9, 0x3f, 0xa8, 0x6b, 0xff, 0x07, 0x00, 0x00, 0xff, - 0xff, 0x32, 0xba, 0xf3, 0xf8, 0xa6, 0x0f, 0x00, 0x00, + // 1292 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xc1, 0x6f, 0x1b, 0xc5, + 0x17, 0xce, 0xa4, 0xf9, 0xb5, 0xc9, 0x24, 0xbf, 0x36, 0x1d, 0x87, 0x36, 0x35, 0x89, 0x9d, 0x4e, + 0x29, 0x84, 0xa0, 0xec, 0x2a, 0x0e, 0x6d, 0x5a, 0x84, 0x50, 0x6b, 0x97, 0xd0, 0x48, 0x08, 0xca, + 0x2a, 0x17, 0x10, 0xc8, 0x5d, 0xef, 0x8e, 0x9d, 0x55, 0x9c, 0x9d, 0xed, 0xee, 0xda, 0xe0, 0xa6, + 0x41, 0x6a, 0xa4, 0x08, 0x09, 0x2a, 0x84, 0x84, 0xc4, 0x01, 0x71, 0xe1, 0x80, 0x90, 0x90, 0xf8, + 0x03, 0xf8, 0x0f, 0x7a, 0xaa, 0x2a, 0x71, 0xe1, 0x64, 0xaa, 0x84, 0x33, 0x07, 0x8b, 0x03, 0x47, + 0xb4, 0x33, 0xb3, 0xeb, 0x75, 0x77, 0x37, 0xf1, 0x96, 0x44, 0x9c, 0x62, 0xcf, 0xbc, 0xf7, 0xe6, + 0xfb, 0xbe, 0xf7, 0x3c, 0xf3, 0x29, 0xf0, 0x82, 0x51, 0xd1, 0x64, 0xd5, 0xb2, 0xea, 0x86, 0xa6, + 0xba, 0x06, 0x35, 0x1d, 0xb9, 0x4a, 0x88, 0xdc, 0x5c, 0x90, 0xef, 0x34, 0x88, 0xdd, 0x92, 0x2c, + 0x9b, 0xba, 0x14, 0x9d, 0x35, 0x2a, 0x9a, 0x14, 0x0e, 0x92, 0xaa, 0x84, 0x48, 0xcd, 0x85, 0xec, + 0x44, 0x8d, 0xd6, 0x28, 0x8b, 0x91, 0xbd, 0x4f, 0x3c, 0x3c, 0x3b, 0x55, 0xa3, 0xb4, 0x56, 0x27, + 0xb2, 0x6a, 0x19, 0xb2, 0x6a, 0x9a, 0xd4, 0x15, 0x49, 0x7c, 0x37, 0xa7, 0x51, 0x67, 0x83, 0x3a, + 0x72, 0x45, 0x75, 0xbc, 0x83, 0x2a, 0xc4, 0x55, 0x17, 0x64, 0x8d, 0x1a, 0xa6, 0xd8, 0x9f, 0x0b, + 0xef, 0x33, 0x14, 0x41, 0x94, 0xa5, 0xd6, 0x0c, 0x93, 0x15, 0x13, 0xb1, 0xe7, 0x93, 0xd0, 0x7b, + 0xf8, 0x78, 0xc8, 0xc5, 0xa4, 0x90, 0x1a, 0x31, 0x89, 0x63, 0x38, 0xe1, 0x4a, 0x1a, 0xb5, 0x89, + 0xac, 0xad, 0xa9, 0xa6, 0x49, 0xea, 0x5e, 0x88, 0xf8, 0xc8, 0x43, 0xf0, 0x03, 0x00, 0xf3, 0xef, + 0x79, 0x78, 0x56, 0x4c, 0x8d, 0x98, 0xae, 0xd1, 0x34, 0xee, 0x12, 0xfd, 0x96, 0xaa, 0xad, 0x13, + 0xd7, 0x51, 0xc8, 0x9d, 0x06, 0x71, 0x5c, 0xb4, 0x0c, 0x61, 0x17, 0xe4, 0x24, 0x98, 0x01, 0xb3, + 0xa3, 0x85, 0x17, 0x25, 0xce, 0x48, 0xf2, 0x18, 0x49, 0x5c, 0x57, 0xc1, 0x48, 0xba, 0xa5, 0xd6, + 0x88, 0xc8, 0x55, 0x42, 0x99, 0xe8, 0x3c, 0x1c, 0x63, 0x81, 0xe5, 0x35, 0x62, 0xd4, 0xd6, 0xdc, + 0xc9, 0xc1, 0x19, 0x30, 0x3b, 0xa4, 0x8c, 0xb2, 0xb5, 0x9b, 0x6c, 0x09, 0x7f, 0x0e, 0xe0, 0x4c, + 0x32, 0x1c, 0xc7, 0xa2, 0xa6, 0x43, 0x50, 0x15, 0x4e, 0x18, 0xa1, 0xed, 0xb2, 0xc5, 0xf7, 0x27, + 0xc1, 0xcc, 0xb1, 0xd9, 0xd1, 0xc2, 0xbc, 0x94, 0xd0, 0x58, 0x69, 0x45, 0xf7, 0x72, 0xaa, 0x86, + 0x5f, 0x71, 0x99, 0x10, 0xa7, 0x38, 0xf4, 0xb0, 0x9d, 0x1f, 0x50, 0x32, 0x46, 0xf4, 0x3c, 0xbc, + 0x03, 0x60, 0x2e, 0x01, 0x8c, 0x2f, 0xcd, 0x35, 0x38, 0xc2, 0x4f, 0x2f, 0x1b, 0xba, 0x50, 0x66, + 0x9a, 0x9d, 0xef, 0xa9, 0x2e, 0xf9, 0x52, 0x37, 0x3d, 0x4d, 0xbc, 0xa8, 0x15, 0x5d, 0x9c, 0x37, + 0x6c, 0x89, 0xef, 0xfd, 0x88, 0xf2, 0x59, 0x72, 0x8f, 0x02, 0x4d, 0x74, 0x98, 0x89, 0xd1, 0x44, + 0x40, 0x7a, 0x26, 0x49, 0x50, 0x54, 0x12, 0xfc, 0x08, 0xc0, 0x97, 0x93, 0xda, 0xb3, 0x4c, 0xed, + 0x12, 0xe7, 0x7b, 0xd8, 0x73, 0x73, 0x16, 0x9e, 0xb0, 0xa8, 0xcd, 0x24, 0xf6, 0xd4, 0x19, 0x51, + 0x8e, 0x7b, 0x5f, 0x57, 0x74, 0x34, 0x0d, 0xa1, 0x90, 0xd8, 0xdb, 0x3b, 0xc6, 0xf6, 0x46, 0xc4, + 0x4a, 0x8c, 0xb4, 0x43, 0x51, 0x69, 0xbf, 0x04, 0x70, 0xae, 0x1f, 0x42, 0x42, 0xe5, 0xdb, 0x87, + 0x38, 0x79, 0xf1, 0x33, 0xf7, 0x11, 0x3c, 0xc7, 0xf0, 0xac, 0x52, 0x57, 0xad, 0x2b, 0x44, 0x6b, + 0xb2, 0xd0, 0xc3, 0x9a, 0x36, 0xfc, 0x2d, 0x80, 0xd9, 0xb8, 0xfa, 0x82, 0xdf, 0x3d, 0x38, 0x62, + 0x13, 0xad, 0x59, 0xae, 0x12, 0xe2, 0x93, 0x3a, 0xd7, 0xd3, 0x30, 0xbf, 0x55, 0x25, 0x6a, 0x98, + 0xc5, 0x1b, 0x5e, 0xf1, 0x4e, 0x3b, 0x3f, 0xde, 0x52, 0x37, 0xea, 0xaf, 0xe1, 0x20, 0x13, 0xff, + 0xf4, 0x7b, 0x7e, 0xb6, 0x66, 0xb8, 0x6b, 0x8d, 0x8a, 0xa4, 0xd1, 0x0d, 0x59, 0xdc, 0x7d, 0xfc, + 0xcf, 0xbc, 0xa3, 0xaf, 0xcb, 0x6e, 0xcb, 0x22, 0x0e, 0x2b, 0xe2, 0x28, 0xc3, 0xb6, 0x40, 0x81, + 0x3f, 0x84, 0x93, 0x5d, 0x6c, 0xd7, 0xb5, 0xf5, 0xc3, 0xa5, 0xfe, 0x0d, 0x08, 0x4b, 0x1b, 0x94, + 0x17, 0xcc, 0x5b, 0x70, 0x58, 0xd5, 0xd6, 0xfb, 0x24, 0x5e, 0x12, 0xc4, 0x4f, 0x71, 0xe2, 0x7e, + 0x62, 0x3a, 0xde, 0x27, 0x54, 0x0e, 0x01, 0xdf, 0x86, 0x53, 0x5d, 0x5c, 0xab, 0xc6, 0x06, 0xa1, + 0x0d, 0xf7, 0x70, 0xa9, 0xff, 0x08, 0xe0, 0x74, 0xc2, 0x11, 0x82, 0xfe, 0x0e, 0x80, 0x63, 0x2e, + 0x5f, 0xef, 0x53, 0x83, 0xb7, 0x84, 0x06, 0x19, 0xae, 0x41, 0x38, 0x39, 0x9d, 0x0e, 0xa3, 0x6e, + 0x17, 0x0f, 0xfe, 0xce, 0xbf, 0xea, 0x4a, 0xb4, 0x61, 0xba, 0xc4, 0xb6, 0x54, 0xdb, 0x6d, 0x5d, + 0xd7, 0x75, 0x9b, 0x38, 0x81, 0x1e, 0xaf, 0xf6, 0xfc, 0xea, 0x3d, 0x41, 0x46, 0x8a, 0xcf, 0x75, + 0xda, 0xf9, 0xd3, 0x1c, 0x49, 0x77, 0x0f, 0x87, 0x2f, 0x83, 0x12, 0x3c, 0x65, 0x93, 0xba, 0xda, + 0x22, 0x76, 0x59, 0xe5, 0xf5, 0xf8, 0x65, 0x52, 0xcc, 0x76, 0xda, 0xf9, 0x33, 0xfe, 0x04, 0xf7, + 0x04, 0x60, 0xe5, 0xa4, 0x58, 0x11, 0x08, 0x70, 0x53, 0xbc, 0x4e, 0xb1, 0xe8, 0x84, 0x94, 0x0a, + 0x9c, 0xd0, 0x42, 0xdb, 0xc1, 0x69, 0x1c, 0x68, 0xbe, 0xd3, 0xce, 0x3f, 0x2f, 0x80, 0xc6, 0x44, + 0x61, 0x25, 0xa3, 0x45, 0x6b, 0xe3, 0x2f, 0xfc, 0x97, 0x68, 0x99, 0x90, 0x37, 0x4d, 0xb5, 0x52, + 0x27, 0xba, 0xb8, 0x9a, 0xfe, 0x8b, 0x47, 0xfa, 0x07, 0xbf, 0x49, 0x71, 0x68, 0x84, 0x0a, 0xf7, + 0x01, 0x9c, 0xa8, 0x12, 0x52, 0x26, 0x7c, 0xbf, 0x2c, 0x1a, 0xe1, 0x0f, 0xd6, 0x5c, 0xe2, 0x55, + 0x19, 0xa9, 0x59, 0xbc, 0x20, 0x26, 0x4d, 0xc8, 0x16, 0x57, 0x15, 0x2b, 0xa8, 0x1a, 0xc1, 0x82, + 0xb7, 0xfd, 0xb1, 0x8f, 0xd4, 0xf4, 0x45, 0x7b, 0xa5, 0xfb, 0xb2, 0xf0, 0xf6, 0xa0, 0x4e, 0x3b, + 0x7f, 0x92, 0x9f, 0x23, 0x36, 0x70, 0xf0, 0xda, 0xf4, 0xce, 0xdd, 0x60, 0x7f, 0x73, 0x87, 0xdf, + 0x4f, 0xea, 0x5c, 0x20, 0xd5, 0x12, 0x1c, 0x0d, 0x71, 0x62, 0x40, 0x86, 0x8b, 0x67, 0x3a, 0xed, + 0x3c, 0x8a, 0x10, 0xc6, 0x0a, 0xec, 0xf2, 0x2c, 0x7c, 0x3f, 0x0e, 0xff, 0xc7, 0x6a, 0xa3, 0x5f, + 0x00, 0xcc, 0xc4, 0xbc, 0x60, 0xe8, 0x4a, 0xa2, 0xcc, 0x07, 0x78, 0xbe, 0xec, 0xd5, 0x67, 0xc8, + 0xe4, 0x7c, 0xf0, 0xfc, 0xf6, 0xaf, 0x7f, 0x7c, 0x3d, 0xf8, 0x12, 0xba, 0x28, 0x0b, 0x97, 0x1a, + 0xb8, 0xd3, 0xb8, 0xb7, 0x13, 0x3d, 0x18, 0x84, 0x28, 0x5a, 0x0e, 0x2d, 0xa5, 0x05, 0xe0, 0x23, + 0xbf, 0x92, 0x3e, 0x51, 0x00, 0xdf, 0x06, 0x0c, 0xf9, 0x3d, 0x74, 0xb7, 0x1f, 0xe4, 0xb2, 0x37, + 0x16, 0xf2, 0x66, 0x70, 0x35, 0x4b, 0x62, 0x60, 0xb6, 0x02, 0xb3, 0x1d, 0xda, 0xeb, 0x0e, 0xc7, + 0x96, 0xec, 0x78, 0x40, 0x4d, 0x8d, 0x84, 0xf7, 0xfd, 0xb5, 0x2d, 0xf4, 0x27, 0x80, 0xd3, 0xfb, + 0x9a, 0x11, 0x54, 0x4c, 0xdd, 0x9a, 0x88, 0x35, 0xcb, 0x96, 0xfe, 0x55, 0x0d, 0xa1, 0xd7, 0x0d, + 0x26, 0xd7, 0x1b, 0xe8, 0xf5, 0xbe, 0x1a, 0x2d, 0x6f, 0x06, 0x02, 0x6d, 0x86, 0xe4, 0x40, 0x7f, + 0x03, 0xf8, 0xff, 0x1e, 0x37, 0x82, 0x0a, 0xfb, 0x83, 0x8b, 0xb3, 0x46, 0xd9, 0xc5, 0x54, 0x39, + 0x82, 0xc0, 0xa7, 0x8c, 0xc0, 0x27, 0xa8, 0x19, 0x21, 0xe0, 0x7a, 0xf1, 0xe5, 0xc0, 0xd1, 0x1c, + 0x51, 0xaf, 0xff, 0x02, 0x70, 0x2c, 0xec, 0x46, 0xd0, 0x42, 0x1f, 0x2c, 0x7a, 0x8d, 0x51, 0xb6, + 0x90, 0x26, 0x45, 0xf0, 0xde, 0x62, 0xbc, 0x3f, 0x46, 0x8d, 0x04, 0xde, 0xbe, 0xa1, 0x39, 0x22, + 0xda, 0x3b, 0x83, 0x70, 0xfc, 0x69, 0x27, 0x82, 0x2e, 0xf5, 0xc1, 0x23, 0x6a, 0x8e, 0xb2, 0x97, + 0xd3, 0xa6, 0x09, 0x09, 0xee, 0xf3, 0xdf, 0xfa, 0x26, 0x6a, 0x25, 0x68, 0x10, 0x36, 0x34, 0x47, + 0xa4, 0xc3, 0x13, 0x00, 0x33, 0x31, 0x4e, 0xe2, 0xa0, 0x5b, 0x3b, 0xd9, 0x1a, 0x1d, 0x74, 0x6b, + 0xef, 0x63, 0x5b, 0xf0, 0x2a, 0xd3, 0xe3, 0x1d, 0xf4, 0x76, 0x44, 0x8f, 0x38, 0x9f, 0x22, 0x6f, + 0x3e, 0xe5, 0x95, 0x42, 0x52, 0x84, 0x7f, 0xdc, 0x3f, 0x03, 0x88, 0xa2, 0x2e, 0xe1, 0xa0, 0xcb, + 0x3d, 0xd1, 0xe5, 0x1c, 0x74, 0xb9, 0x27, 0x1b, 0x12, 0xfc, 0x02, 0xe3, 0x97, 0x43, 0x53, 0x11, + 0x7e, 0xa1, 0xf7, 0x15, 0x3d, 0x02, 0xf0, 0x74, 0xa4, 0x08, 0xba, 0x9c, 0xf2, 0x54, 0x1f, 0xed, + 0x52, 0xea, 0x3c, 0x01, 0xf6, 0x26, 0x03, 0x5b, 0x44, 0xd7, 0xf6, 0x03, 0xeb, 0x4f, 0x65, 0x64, + 0x16, 0x43, 0x0d, 0x28, 0xbe, 0xfb, 0x70, 0x37, 0x07, 0x1e, 0xef, 0xe6, 0xc0, 0x93, 0xdd, 0x1c, + 0xf8, 0x6a, 0x2f, 0x37, 0xf0, 0x78, 0x2f, 0x37, 0xf0, 0xdb, 0x5e, 0x6e, 0xe0, 0x83, 0x4b, 0x51, + 0x87, 0x6e, 0x54, 0xb4, 0xf9, 0x1a, 0x95, 0x9b, 0x8b, 0xf2, 0x06, 0xd5, 0x1b, 0x75, 0xe2, 0xf0, + 0xa3, 0x0b, 0x57, 0xe7, 0xbd, 0xd3, 0x99, 0x69, 0xaf, 0x1c, 0x67, 0xff, 0x37, 0x5a, 0xfc, 0x27, + 0x00, 0x00, 0xff, 0xff, 0xac, 0x50, 0xbb, 0x05, 0x64, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -858,6 +1076,10 @@ type QueryClient interface { TotalTimeoutFees(ctx context.Context, in *QueryTotalTimeoutFeesRequest, opts ...grpc.CallOption) (*QueryTotalTimeoutFeesResponse, error) // CounterpartyAddress returns the registered counterparty address for forward relaying CounterpartyAddress(ctx context.Context, in *QueryCounterpartyAddressRequest, opts ...grpc.CallOption) (*QueryCounterpartyAddressResponse, error) + // FeeEnabledChannels returns a list of all fee enabled channels + FeeEnabledChannels(ctx context.Context, in *QueryFeeEnabledChannelsRequest, opts ...grpc.CallOption) (*QueryFeeEnabledChannelsResponse, error) + // FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel + FeeEnabledChannel(ctx context.Context, in *QueryFeeEnabledChannelRequest, opts ...grpc.CallOption) (*QueryFeeEnabledChannelResponse, error) } type queryClient struct { @@ -931,6 +1153,24 @@ func (c *queryClient) CounterpartyAddress(ctx context.Context, in *QueryCounterp return out, nil } +func (c *queryClient) FeeEnabledChannels(ctx context.Context, in *QueryFeeEnabledChannelsRequest, opts ...grpc.CallOption) (*QueryFeeEnabledChannelsResponse, error) { + out := new(QueryFeeEnabledChannelsResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/FeeEnabledChannels", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) FeeEnabledChannel(ctx context.Context, in *QueryFeeEnabledChannelRequest, opts ...grpc.CallOption) (*QueryFeeEnabledChannelResponse, error) { + out := new(QueryFeeEnabledChannelResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/FeeEnabledChannel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // IncentivizedPackets returns all incentivized packets and their associated fees @@ -947,6 +1187,10 @@ type QueryServer interface { TotalTimeoutFees(context.Context, *QueryTotalTimeoutFeesRequest) (*QueryTotalTimeoutFeesResponse, error) // CounterpartyAddress returns the registered counterparty address for forward relaying CounterpartyAddress(context.Context, *QueryCounterpartyAddressRequest) (*QueryCounterpartyAddressResponse, error) + // FeeEnabledChannels returns a list of all fee enabled channels + FeeEnabledChannels(context.Context, *QueryFeeEnabledChannelsRequest) (*QueryFeeEnabledChannelsResponse, error) + // FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel + FeeEnabledChannel(context.Context, *QueryFeeEnabledChannelRequest) (*QueryFeeEnabledChannelResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -974,6 +1218,12 @@ func (*UnimplementedQueryServer) TotalTimeoutFees(ctx context.Context, req *Quer func (*UnimplementedQueryServer) CounterpartyAddress(ctx context.Context, req *QueryCounterpartyAddressRequest) (*QueryCounterpartyAddressResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CounterpartyAddress not implemented") } +func (*UnimplementedQueryServer) FeeEnabledChannels(ctx context.Context, req *QueryFeeEnabledChannelsRequest) (*QueryFeeEnabledChannelsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FeeEnabledChannels not implemented") +} +func (*UnimplementedQueryServer) FeeEnabledChannel(ctx context.Context, req *QueryFeeEnabledChannelRequest) (*QueryFeeEnabledChannelResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FeeEnabledChannel not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -1105,6 +1355,42 @@ func _Query_CounterpartyAddress_Handler(srv interface{}, ctx context.Context, de return interceptor(ctx, in, info, handler) } +func _Query_FeeEnabledChannels_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryFeeEnabledChannelsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).FeeEnabledChannels(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/FeeEnabledChannels", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).FeeEnabledChannels(ctx, req.(*QueryFeeEnabledChannelsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_FeeEnabledChannel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryFeeEnabledChannelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).FeeEnabledChannel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/FeeEnabledChannel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).FeeEnabledChannel(ctx, req.(*QueryFeeEnabledChannelRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "ibc.applications.fee.v1.Query", HandlerType: (*QueryServer)(nil), @@ -1137,6 +1423,14 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "CounterpartyAddress", Handler: _Query_CounterpartyAddress_Handler, }, + { + MethodName: "FeeEnabledChannels", + Handler: _Query_FeeEnabledChannels_Handler, + }, + { + MethodName: "FeeEnabledChannel", + Handler: _Query_FeeEnabledChannel_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "ibc/applications/fee/v1/query.proto", @@ -1658,54 +1952,201 @@ func (m *QueryCounterpartyAddressResponse) MarshalToSizedBuffer(dAtA []byte) (in return len(dAtA) - i, nil } -func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { - offset -= sovQuery(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *QueryFeeEnabledChannelsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *QueryIncentivizedPacketsRequest) Size() (n int) { - if m == nil { - return 0 - } + +func (m *QueryFeeEnabledChannelsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeeEnabledChannelsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) - } if m.QueryHeight != 0 { - n += 1 + sovQuery(uint64(m.QueryHeight)) + i = encodeVarintQuery(dAtA, i, uint64(m.QueryHeight)) + i-- + dAtA[i] = 0x10 } - return n + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } -func (m *QueryIncentivizedPacketsResponse) Size() (n int) { - if m == nil { - return 0 +func (m *QueryFeeEnabledChannelsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } + return dAtA[:n], nil +} + +func (m *QueryFeeEnabledChannelsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeeEnabledChannelsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if len(m.IncentivizedPackets) > 0 { - for _, e := range m.IncentivizedPackets { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) + if len(m.FeeEnabledChannels) > 0 { + for iNdEx := len(m.FeeEnabledChannels) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FeeEnabledChannels[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa } } - return n + return len(dAtA) - i, nil } -func (m *QueryIncentivizedPacketRequest) Size() (n int) { - if m == nil { - return 0 +func (m *QueryFeeEnabledChannelRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - var l int - _ = l + return dAtA[:n], nil +} + +func (m *QueryFeeEnabledChannelRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeeEnabledChannelRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryFeeEnabledChannelResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryFeeEnabledChannelResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFeeEnabledChannelResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.FeeEnabled { + i-- + if m.FeeEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryIncentivizedPacketsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + if m.QueryHeight != 0 { + n += 1 + sovQuery(uint64(m.QueryHeight)) + } + return n +} + +func (m *QueryIncentivizedPacketsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.IncentivizedPackets) > 0 { + for _, e := range m.IncentivizedPackets { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryIncentivizedPacketRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l l = m.PacketId.Size() n += 1 + l + sovQuery(uint64(l)) if m.QueryHeight != 0 { @@ -1872,6 +2313,66 @@ func (m *QueryCounterpartyAddressResponse) Size() (n int) { return n } +func (m *QueryFeeEnabledChannelsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + if m.QueryHeight != 0 { + n += 1 + sovQuery(uint64(m.QueryHeight)) + } + return n +} + +func (m *QueryFeeEnabledChannelsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.FeeEnabledChannels) > 0 { + for _, e := range m.FeeEnabledChannels { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryFeeEnabledChannelRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryFeeEnabledChannelResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.FeeEnabled { + n += 2 + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -3202,6 +3703,379 @@ func (m *QueryCounterpartyAddressResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryFeeEnabledChannelsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryFeeEnabledChannelsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeeEnabledChannelsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryHeight", wireType) + } + m.QueryHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.QueryHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryFeeEnabledChannelsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryFeeEnabledChannelsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeeEnabledChannelsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeeEnabledChannels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FeeEnabledChannels = append(m.FeeEnabledChannels, FeeEnabledChannel{}) + if err := m.FeeEnabledChannels[len(m.FeeEnabledChannels)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryFeeEnabledChannelRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryFeeEnabledChannelRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeeEnabledChannelRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryFeeEnabledChannelResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryFeeEnabledChannelResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFeeEnabledChannelResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FeeEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.FeeEnabled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/29-fee/types/query.pb.gw.go b/modules/apps/29-fee/types/query.pb.gw.go index 0210f400710..37c38769d20 100644 --- a/modules/apps/29-fee/types/query.pb.gw.go +++ b/modules/apps/29-fee/types/query.pb.gw.go @@ -701,6 +701,118 @@ func local_request_Query_CounterpartyAddress_0(ctx context.Context, marshaler ru } +var ( + filter_Query_FeeEnabledChannels_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_FeeEnabledChannels_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeeEnabledChannelsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_FeeEnabledChannels_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.FeeEnabledChannels(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_FeeEnabledChannels_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeeEnabledChannelsRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_FeeEnabledChannels_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.FeeEnabledChannels(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_FeeEnabledChannel_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeeEnabledChannelRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + msg, err := client.FeeEnabledChannel(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_FeeEnabledChannel_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryFeeEnabledChannelRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + msg, err := server.FeeEnabledChannel(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -847,6 +959,46 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_FeeEnabledChannels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_FeeEnabledChannels_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_FeeEnabledChannels_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_FeeEnabledChannel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_FeeEnabledChannel_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_FeeEnabledChannel_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1028,6 +1180,46 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_FeeEnabledChannels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_FeeEnabledChannels_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_FeeEnabledChannels_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_FeeEnabledChannel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_FeeEnabledChannel_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_FeeEnabledChannel_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -1045,6 +1237,10 @@ var ( pattern_Query_TotalTimeoutFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_timeout_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_CounterpartyAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"ibc", "apps", "fee", "v1", "counterparty_address", "relayer_address", "channel", "channel_id"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_FeeEnabledChannels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "apps", "fee", "v1", "fee_enabled"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_FeeEnabledChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8}, []string{"ibc", "apps", "fee", "v1", "fee_enabled", "port", "port_id", "channel", "channel_id"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -1061,4 +1257,8 @@ var ( forward_Query_TotalTimeoutFees_0 = runtime.ForwardResponseMessage forward_Query_CounterpartyAddress_0 = runtime.ForwardResponseMessage + + forward_Query_FeeEnabledChannels_0 = runtime.ForwardResponseMessage + + forward_Query_FeeEnabledChannel_0 = runtime.ForwardResponseMessage ) diff --git a/proto/ibc/applications/fee/v1/query.proto b/proto/ibc/applications/fee/v1/query.proto index 689617e6ff5..f36a1414203 100644 --- a/proto/ibc/applications/fee/v1/query.proto +++ b/proto/ibc/applications/fee/v1/query.proto @@ -9,6 +9,7 @@ import "google/api/annotations.proto"; import "cosmos/base/v1beta1/coin.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; import "ibc/applications/fee/v1/fee.proto"; +import "ibc/applications/fee/v1/genesis.proto"; import "ibc/core/channel/v1/channel.proto"; // Query defines the ICS29 gRPC querier service. @@ -53,6 +54,16 @@ service Query { rpc CounterpartyAddress(QueryCounterpartyAddressRequest) returns (QueryCounterpartyAddressResponse) { option (google.api.http).get = "/ibc/apps/fee/v1/counterparty_address/{relayer_address}/channel/{channel_id}"; } + + // FeeEnabledChannels returns a list of all fee enabled channels + rpc FeeEnabledChannels(QueryFeeEnabledChannelsRequest) returns (QueryFeeEnabledChannelsResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/fee_enabled"; + } + + // FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel + rpc FeeEnabledChannel(QueryFeeEnabledChannelRequest) returns (QueryFeeEnabledChannelResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/fee_enabled/port/{port_id}/channel/{channel_id}"; + } } // QueryIncentivizedPacketsRequest defines the request type for the IncentivizedPackets rpc @@ -161,3 +172,32 @@ message QueryCounterpartyAddressResponse { // the counterparty address used to compensate forward relaying string counterparty_address = 1 [(gogoproto.moretags) = "yaml:\"counterparty_address\""]; } + +// QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc +message QueryFeeEnabledChannelsRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; + // block height at which to query + uint64 query_height = 2; +} + +// QueryFeeEnabledChannelsResponse defines the response type for the FeeEnabledChannels rpc +message QueryFeeEnabledChannelsResponse { + // list of fee enabled channels + repeated ibc.applications.fee.v1.FeeEnabledChannel fee_enabled_channels = 1 + [(gogoproto.moretags) = "yaml:\"fee_enabled_channels\"", (gogoproto.nullable) = false]; +} + +// QueryFeeEnabledChannelRequest defines the request type for the FeeEnabledChannel rpc +message QueryFeeEnabledChannelRequest { + // unique port identifier + string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + // unique channel identifier + string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; +} + +// QueryFeeEnabledChannelResponse defines the response type for the FeeEnabledChannel rpc +message QueryFeeEnabledChannelResponse { + // boolean flag representing the fee enabled channel status + bool fee_enabled = 1 [(gogoproto.moretags) = "yaml:\"fee_enabled\""]; +} From 311379f7882409ece89cfbf6199c4b85ed69569b Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 7 Apr 2022 18:26:16 +0200 Subject: [PATCH 065/275] chore: cleanup OnAcknowledgement and OnTimeout code ics29 (#1228) --- modules/apps/29-fee/ibc_module.go | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/modules/apps/29-fee/ibc_module.go b/modules/apps/29-fee/ibc_module.go index 89d27b9f86f..e4dab034b04 100644 --- a/modules/apps/29-fee/ibc_module.go +++ b/modules/apps/29-fee/ibc_module.go @@ -233,15 +233,12 @@ func (im IBCModule) OnAcknowledgementPacket( packetID := channeltypes.NewPacketId(packet.SourceChannel, packet.SourcePort, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) - if !found { - // return underlying callback if no fee found for given packetID - return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer) - } - - im.keeper.DistributePacketFees(ctx, ack.ForwardRelayerAddress, relayer, feesInEscrow.PacketFees) + if found { + im.keeper.DistributePacketFees(ctx, ack.ForwardRelayerAddress, relayer, feesInEscrow.PacketFees) - // removes the fees from the store as fees are now paid - im.keeper.DeleteFeesInEscrow(ctx, packetID) + // removes the fees from the store as fees are now paid + im.keeper.DeleteFeesInEscrow(ctx, packetID) + } // call underlying callback return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer) @@ -260,15 +257,12 @@ func (im IBCModule) OnTimeoutPacket( packetID := channeltypes.NewPacketId(packet.SourceChannel, packet.SourcePort, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) - if !found { - // return underlying callback if fee not found for given packetID - return im.app.OnTimeoutPacket(ctx, packet, relayer) - } - - im.keeper.DistributePacketFeesOnTimeout(ctx, relayer, feesInEscrow.PacketFees) + if found { + im.keeper.DistributePacketFeesOnTimeout(ctx, relayer, feesInEscrow.PacketFees) - // removes the fee from the store as fee is now paid - im.keeper.DeleteFeesInEscrow(ctx, packetID) + // removes the fee from the store as fee is now paid + im.keeper.DeleteFeesInEscrow(ctx, packetID) + } // call underlying callback return im.app.OnTimeoutPacket(ctx, packet, relayer) From c5897ae7ae29197cf90c77d5377872a352fc5c8d Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 8 Apr 2022 11:18:45 +0200 Subject: [PATCH 066/275] add changelog entry for #276 (#1233) --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75ea3755d85..4f195384040 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,10 +47,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. ### Features -* (modules/apps/29-fee) [\#1229](https://github.com/cosmos/ibc-go/pull/1229) Adding CLI commands for getting all unrelayed incentivized packets and packet by packet-id. +* [\#276](https://github.com/cosmos/ibc-go/pull/276) Adding the Fee Middleware module v1 +* (apps/29-fee) [\#1229](https://github.com/cosmos/ibc-go/pull/1229) Adding CLI commands for getting all unrelayed incentivized packets and packet by packet-id. * (apps/29-fee) [\#1224](https://github.com/cosmos/ibc-go/pull/1224) Adding Query/CounterpartyAddress and CLI to ICS29 fee middleware - * (apps/29-fee) [\#1225](https://github.com/cosmos/ibc-go/pull/1225) Adding Query/FeeEnabledChannel and Query/FeeEnabledChannels with CLIs to ICS29 fee middleware. ### Bug Fixes From b71bbf22414f3ffbb29e792bbc5ded0b33bff7bb Mon Sep 17 00:00:00 2001 From: Sean King Date: Fri, 8 Apr 2022 12:03:10 +0200 Subject: [PATCH 067/275] feat: adding CLI for getting incentivized packets on a specific channel (#1230) * feat: adding CLI for getting incentivized packets on a specific channel * chore: changelog * refactor: usage --- CHANGELOG.md | 2 ++ modules/apps/29-fee/client/cli/cli.go | 1 + modules/apps/29-fee/client/cli/query.go | 43 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f195384040..8b1f9271632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. ### Features +* (modules/apps/29-fee) [\#1230](https://github.com/cosmos/ibc-go/pull/1230) Adding CLI command for getting incentivized packets for a specific channel-id. + * [\#276](https://github.com/cosmos/ibc-go/pull/276) Adding the Fee Middleware module v1 * (apps/29-fee) [\#1229](https://github.com/cosmos/ibc-go/pull/1229) Adding CLI commands for getting all unrelayed incentivized packets and packet by packet-id. diff --git a/modules/apps/29-fee/client/cli/cli.go b/modules/apps/29-fee/client/cli/cli.go index c2afc6e25ed..a0141c20f9a 100644 --- a/modules/apps/29-fee/client/cli/cli.go +++ b/modules/apps/29-fee/client/cli/cli.go @@ -20,6 +20,7 @@ func GetQueryCmd() *cobra.Command { GetCmdTotalRecvFees(), GetCmdTotalAckFees(), GetCmdTotalTimeoutFees(), + GetCmdIncentivizedPacketsForChannel(), GetCmdCounterpartyAddress(), GetCmdFeeEnabledChannel(), GetCmdFeeEnabledChannels(), diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index 9eca35cae48..22ad1378309 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -350,3 +350,46 @@ func GetCmdFeeEnabledChannel() *cobra.Command { return cmd } + +// GetCmdIncentivizedPacketsForChannel returns all of the unrelayed incentivized packets on a given channel +func GetCmdIncentivizedPacketsForChannel() *cobra.Command { + cmd := &cobra.Command{ + Use: "packets-for-channel [port-id] [channel-id]", + Short: "Query for all of the unrelayed incentivized packets on a given channel", + Long: "Query for all of the unrelayed incentivized packets on a given channel. These are packets that have not yet been relayed.", + Args: cobra.ExactArgs(2), + Example: fmt.Sprintf("%s query ibc-fee packets-for-channel", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryIncentivizedPacketsForChannelRequest{ + Pagination: pageReq, + PortId: args[0], + ChannelId: args[1], + QueryHeight: uint64(clientCtx.Height), + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.IncentivizedPacketsForChannel(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "packets-for-channel") + + return cmd +} From c7209a56cb653031c5e124431880f7212672f084 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 11 Apr 2022 10:39:52 +0200 Subject: [PATCH 068/275] chore: ics29 cleanup, addressing nits (#1236) --- modules/apps/29-fee/keeper/escrow.go | 15 +++++++++------ modules/apps/29-fee/types/codec.go | 8 +++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 525ce258d05..40aad06e3be 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -16,22 +16,25 @@ func (k Keeper) EscrowPacketFee(ctx sdk.Context, packetID channeltypes.PacketId, // users may not escrow fees on this channel. Must send packets without a fee message return sdkerrors.Wrap(types.ErrFeeNotEnabled, "cannot escrow fee for packet") } - // check if the refund account exists - refundAcc, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) + + // check if the refund address is valid + refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) if err != nil { return err } - hasRefundAcc := k.authKeeper.GetAccount(ctx, refundAcc) - if hasRefundAcc == nil { - return sdkerrors.Wrapf(types.ErrRefundAccNotFound, "account with address: %s not found", refundAcc) + refundAcc := k.authKeeper.GetAccount(ctx, refundAddr) + if refundAcc == nil { + return sdkerrors.Wrapf(types.ErrRefundAccNotFound, "account with address: %s not found", packetFee.RefundAddress) } coins := packetFee.Fee.Total() - if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, refundAcc, types.ModuleName, coins); err != nil { + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, refundAddr, types.ModuleName, coins); err != nil { return err } + // multiple fees may be escrowed for a single packet, firstly create a slice containing the new fee + // retrieve any previous fees stored in escrow for the packet and append them to the list fees := []types.PacketFee{packetFee} if feesInEscrow, found := k.GetFeesInEscrow(ctx, packetID); found { fees = append(fees, feesInEscrow.PacketFees...) diff --git a/modules/apps/29-fee/types/codec.go b/modules/apps/29-fee/types/codec.go index 846716d740f..871f148b043 100644 --- a/modules/apps/29-fee/types/codec.go +++ b/modules/apps/29-fee/types/codec.go @@ -18,7 +18,13 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { // RegisterInterfaces register the 29-fee module interfaces to protobuf // Any. func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations((*sdk.Msg)(nil), &MsgRegisterCounterpartyAddress{}, &MsgPayPacketFee{}, &MsgPayPacketFeeAsync{}) + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgRegisterCounterpartyAddress{}, + &MsgPayPacketFee{}, + &MsgPayPacketFeeAsync{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } From d43fd0ad3236928b782e143437e4f4f69c514b31 Mon Sep 17 00:00:00 2001 From: Sean King Date: Mon, 11 Apr 2022 14:46:28 +0200 Subject: [PATCH 069/275] refactor: moving fn definition to bottom of file and switching params (#1232) ## Description closes: #868 #997 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- CHANGELOG.md | 2 +- modules/apps/29-fee/client/cli/query.go | 6 ++--- modules/apps/29-fee/client/cli/tx.go | 2 +- modules/apps/29-fee/ibc_module.go | 6 ++--- modules/apps/29-fee/ibc_module_test.go | 22 ++++++++--------- modules/apps/29-fee/keeper/escrow_test.go | 12 +++++----- modules/apps/29-fee/keeper/genesis_test.go | 4 ++-- modules/apps/29-fee/keeper/grpc_query_test.go | 24 +++++++++---------- modules/apps/29-fee/keeper/keeper_test.go | 4 ++-- modules/apps/29-fee/keeper/msg_server.go | 2 +- modules/apps/29-fee/keeper/msg_server_test.go | 2 +- modules/apps/29-fee/keeper/relay.go | 2 +- modules/apps/29-fee/keeper/relay_test.go | 4 ++-- modules/apps/29-fee/types/genesis_test.go | 8 +++---- modules/apps/29-fee/types/keys.go | 4 ++-- modules/apps/29-fee/types/keys_test.go | 2 +- modules/apps/29-fee/types/msgs_test.go | 6 ++--- modules/core/04-channel/types/packet.go | 10 ++++---- 18 files changed, 61 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b1f9271632..88886e3254e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,8 +43,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking ### Improvements - * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. +* (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. ### Features * (modules/apps/29-fee) [\#1230](https://github.com/cosmos/ibc-go/pull/1230) Adding CLI command for getting incentivized packets for a specific channel-id. diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index 22ad1378309..a183c8f89d3 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -120,7 +120,7 @@ func GetCmdTotalRecvFees() *cobra.Command { return err } - packetID := channeltypes.NewPacketId(channelID, portID, seq) + packetID := channeltypes.NewPacketId(portID, channelID, seq) if err := packetID.Validate(); err != nil { return err @@ -166,7 +166,7 @@ func GetCmdTotalAckFees() *cobra.Command { return err } - packetID := channeltypes.NewPacketId(channelID, portID, seq) + packetID := channeltypes.NewPacketId(portID, channelID, seq) if err := packetID.Validate(); err != nil { return err @@ -212,7 +212,7 @@ func GetCmdTotalTimeoutFees() *cobra.Command { return err } - packetID := channeltypes.NewPacketId(channelID, portID, seq) + packetID := channeltypes.NewPacketId(portID, channelID, seq) if err := packetID.Validate(); err != nil { return err diff --git a/modules/apps/29-fee/client/cli/tx.go b/modules/apps/29-fee/client/cli/tx.go index 0a4436b0bc4..f1f858b60cd 100644 --- a/modules/apps/29-fee/client/cli/tx.go +++ b/modules/apps/29-fee/client/cli/tx.go @@ -45,7 +45,7 @@ func NewPayPacketFeeAsyncTxCmd() *cobra.Command { return err } - packetID := channeltypes.NewPacketId(args[1], args[0], seq) + packetID := channeltypes.NewPacketId(args[0], args[1], seq) recvFeeStr, err := cmd.Flags().GetString(flagRecvFee) if err != nil { diff --git a/modules/apps/29-fee/ibc_module.go b/modules/apps/29-fee/ibc_module.go index e4dab034b04..192193e07cc 100644 --- a/modules/apps/29-fee/ibc_module.go +++ b/modules/apps/29-fee/ibc_module.go @@ -204,7 +204,7 @@ func (im IBCModule) OnRecvPacket( // incase of async aknowledgement (ack == nil) store the relayer address for use later during async WriteAcknowledgement if ack == nil { - im.keeper.SetRelayerAddressForAsyncAck(ctx, channeltypes.NewPacketId(packet.GetDestChannel(), packet.GetDestPort(), packet.GetSequence()), relayer.String()) + im.keeper.SetRelayerAddressForAsyncAck(ctx, channeltypes.NewPacketId(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()), relayer.String()) return nil } @@ -231,7 +231,7 @@ func (im IBCModule) OnAcknowledgementPacket( return sdkerrors.Wrapf(err, "cannot unmarshal ICS-29 incentivized packet acknowledgement: %v", ack) } - packetID := channeltypes.NewPacketId(packet.SourceChannel, packet.SourcePort, packet.Sequence) + packetID := channeltypes.NewPacketId(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) if found { im.keeper.DistributePacketFees(ctx, ack.ForwardRelayerAddress, relayer, feesInEscrow.PacketFees) @@ -255,7 +255,7 @@ func (im IBCModule) OnTimeoutPacket( return im.app.OnTimeoutPacket(ctx, packet, relayer) } - packetID := channeltypes.NewPacketId(packet.SourceChannel, packet.SourcePort, packet.Sequence) + packetID := channeltypes.NewPacketId(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) if found { im.keeper.DistributePacketFeesOnTimeout(ctx, relayer, feesInEscrow.PacketFees) diff --git a/modules/apps/29-fee/ibc_module_test.go b/modules/apps/29-fee/ibc_module_test.go index fb2bd8ecf01..f2c56576a79 100644 --- a/modules/apps/29-fee/ibc_module_test.go +++ b/modules/apps/29-fee/ibc_module_test.go @@ -302,8 +302,8 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { "success", func(suite *FeeTestSuite) { packetID := channeltypes.NewPacketId( - suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, 1, ) refundAcc := suite.chainA.SenderAccount.GetAddress() @@ -316,11 +316,11 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { { "module account balance insufficient", func(suite *FeeTestSuite) { - packetID := channeltypes.PacketId{ - PortId: suite.path.EndpointA.ChannelConfig.PortID, - ChannelId: suite.path.EndpointA.ChannelID, - Sequence: 1, - } + packetID := channeltypes.NewPacketId( + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + 1, + ) refundAcc := suite.chainA.SenderAccount.GetAddress() packetFee := types.NewPacketFee(types.Fee{validCoins, validCoins2, validCoins3}, refundAcc.String(), []string{}) err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) @@ -537,7 +537,7 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { case tc.forwardRelayer && result == nil: suite.Require().Equal(nil, result) - packetID := channeltypes.NewPacketId(packet.GetDestChannel(), packet.GetDestPort(), packet.GetSequence()) + packetID := channeltypes.NewPacketId(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) // retrieve the forward relayer that was stored in `onRecvPacket` relayer, _ := suite.chainB.GetSimApp().IBCFeeKeeper.GetRelayerAddressForAsyncAck(suite.chainB.GetContext(), packetID) @@ -580,7 +580,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { { "no op success without a packet fee", func() { - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, suite.chainA.SenderAccount.GetSequence()) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetSequence()) suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeesInEscrow(suite.chainA.GetContext(), packetID) ack = types.IncentivizedAcknowledgement{ @@ -645,7 +645,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { suite.Require().True(ok) // escrow the packet fee - packetID := channeltypes.NewPacketId(packet.GetSourceChannel(), packet.GetSourcePort(), packet.GetSequence()) + packetID := channeltypes.NewPacketId(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) packetFee = types.NewPacketFee( types.Fee{ RecvFee: validCoins, @@ -728,7 +728,7 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { "no op if identified packet fee doesn't exist", func() { // delete packet fee - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, suite.chainA.SenderAccount.GetSequence()) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetSequence()) suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeesInEscrow(suite.chainA.GetContext(), packetID) expectedBalance = originalBalance @@ -762,7 +762,7 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - packetID := channeltypes.NewPacketId(packet.GetSourceChannel(), packet.GetSourcePort(), packet.GetSequence()) + packetID := channeltypes.NewPacketId(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) // must be explicitly changed relayerAddr = suite.chainB.SenderAccount.GetAddress() diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 2f6b2fe62b1..0b9e3045542 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -82,7 +82,7 @@ func (suite *KeeperTestSuite) TestEscrowPacketFee() { receiveFee = defaultReceiveFee ackFee = defaultAckFee timeoutFee = defaultTimeoutFee - packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, uint64(1)) + packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) tc.malleate() fee := types.Fee{ @@ -161,7 +161,7 @@ func (suite *KeeperTestSuite) TestDistributeFee() { reverseRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) forwardRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, validSeq) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, validSeq) fee := types.Fee{ RecvFee: defaultReceiveFee, AckFee: defaultAckFee, @@ -221,8 +221,8 @@ func (suite *KeeperTestSuite) TestDistributeTimeoutFee() { timeoutRelayer := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) packetID := channeltypes.NewPacketId( - suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, 1, ) @@ -271,7 +271,7 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannel() { prevBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) for i := 0; i < 5; i++ { - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, uint64(i)) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(i)) fee := types.Fee{ RecvFee: defaultReceiveFee, AckFee: defaultAckFee, @@ -285,7 +285,7 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannel() { } // send a packet over a different channel to ensure this fee is not refunded - packetID := channeltypes.NewPacketId("channel-1", ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, "channel-1", 1) fee := types.Fee{ RecvFee: defaultReceiveFee, AckFee: defaultAckFee, @@ -306,7 +306,7 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannel() { suite.Require().Equal(prevBal, afterBal.Add(fee.RecvFee...).Add(fee.AckFee...).Add(fee.TimeoutFee...), "refund account not back to original balance after refunding all tokens") // create escrow and then change module account balance to cause error on refund - packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, uint64(6)) + packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(6)) packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) diff --git a/modules/apps/29-fee/keeper/genesis_test.go b/modules/apps/29-fee/keeper/genesis_test.go index f2824120a82..ec9602d3a4f 100644 --- a/modules/apps/29-fee/keeper/genesis_test.go +++ b/modules/apps/29-fee/keeper/genesis_test.go @@ -9,7 +9,7 @@ import ( func (suite *KeeperTestSuite) TestInitGenesis() { // build PacketId & Fee refundAcc := suite.chainA.SenderAccount.GetAddress() - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.Fee{ RecvFee: defaultReceiveFee, AckFee: defaultAckFee, @@ -71,7 +71,7 @@ func (suite *KeeperTestSuite) TestExportGenesis() { // setup & escrow the packet fee refundAcc := suite.chainA.SenderAccount.GetAddress() - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.Fee{ RecvFee: defaultReceiveFee, AckFee: defaultAckFee, diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index 516a31e87b2..446616ab176 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -33,7 +33,7 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPackets() { for i := 0; i < 3; i++ { // escrow packet fees for three different packets - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, uint64(i+1)) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, uint64(i+1)) suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) expectedPackets = append(expectedPackets, types.NewIdentifiedPacketFees(packetID, []types.PacketFee{packetFee})) @@ -98,7 +98,7 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPacket() { "fees not found for packet id", func() { req = &types.QueryIncentivizedPacketRequest{ - PacketId: channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 100), + PacketId: channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 100), QueryHeight: 0, } }, @@ -112,7 +112,7 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPacket() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) @@ -210,9 +210,9 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPacketsForChannel() { packetFee := types.NewPacketFee(fee, refundAcc.String(), nil) packetFees := types.NewPacketFees([]types.PacketFee{packetFee, packetFee, packetFee}) - identifiedFees1 := types.NewIdentifiedPacketFees(channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1), packetFees.PacketFees) - identifiedFees2 := types.NewIdentifiedPacketFees(channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 2), packetFees.PacketFees) - identifiedFees3 := types.NewIdentifiedPacketFees(channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 3), packetFees.PacketFees) + identifiedFees1 := types.NewIdentifiedPacketFees(channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1), packetFees.PacketFees) + identifiedFees2 := types.NewIdentifiedPacketFees(channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 2), packetFees.PacketFees) + identifiedFees3 := types.NewIdentifiedPacketFees(channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 3), packetFees.PacketFees) expIdentifiedPacketFees = append(expIdentifiedPacketFees, &identifiedFees1, &identifiedFees2, &identifiedFees3) @@ -255,7 +255,7 @@ func (suite *KeeperTestSuite) TestQueryTotalRecvFees() { { "packet not found", func() { - req.PacketId = channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 100) + req.PacketId = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 100) }, false, }, @@ -267,7 +267,7 @@ func (suite *KeeperTestSuite) TestQueryTotalRecvFees() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) @@ -319,7 +319,7 @@ func (suite *KeeperTestSuite) TestQueryTotalAckFees() { { "packet not found", func() { - req.PacketId = channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 100) + req.PacketId = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 100) }, false, }, @@ -331,7 +331,7 @@ func (suite *KeeperTestSuite) TestQueryTotalAckFees() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) @@ -383,7 +383,7 @@ func (suite *KeeperTestSuite) TestQueryTotalTimeoutFees() { { "packet not found", func() { - req.PacketId = channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 100) + req.PacketId = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 100) }, false, }, @@ -395,7 +395,7 @@ func (suite *KeeperTestSuite) TestQueryTotalTimeoutFees() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index 1f29a8872d5..29cb19fb8f5 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -92,7 +92,7 @@ func (suite *KeeperTestSuite) TestFeesInEscrow() { suite.coordinator.Setup(suite.path) // escrow five fees for packet sequence 1 - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, 1) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) for i := 1; i < 6; i++ { @@ -131,7 +131,7 @@ func (suite *KeeperTestSuite) TestGetAllIdentifiedPacketFees() { // escrow a fee refundAcc := suite.chainA.SenderAccount.GetAddress() - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, 1) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) fee := types.Fee{ AckFee: defaultAckFee, RecvFee: defaultReceiveFee, diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index fdac1d27874..c9100f9c73e 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -38,8 +38,8 @@ func (k Keeper) PayPacketFee(goCtx context.Context, msg *types.MsgPayPacketFee) } packetID := channeltypes.NewPacketId( - msg.SourceChannelId, msg.SourcePortId, + msg.SourceChannelId, sequence, ) diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 26ce387b60e..7a06af6e30b 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -119,7 +119,7 @@ func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { seq, _ := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceSend(ctxA, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) // build fee - packetID := channeltypes.NewPacketId(channelID, suite.path.EndpointA.ChannelConfig.PortID, seq) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, channelID, seq) packetFee := types.NewPacketFee(fee, refundAcc.String(), nil) tc.malleate() diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index a2ef8a7ca11..34c473e2e83 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -23,7 +23,7 @@ func (k Keeper) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.C return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, acknowledgement) } - packetID := channeltypes.NewPacketId(packet.GetDestChannel(), packet.GetDestPort(), packet.GetSequence()) + packetID := channeltypes.NewPacketId(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) // retrieve the forward relayer that was stored in `onRecvPacket` relayer, found := k.GetRelayerAddressForAsyncAck(ctx, packetID) diff --git a/modules/apps/29-fee/keeper/relay_test.go b/modules/apps/29-fee/keeper/relay_test.go index 3cfd627b520..c853babd527 100644 --- a/modules/apps/29-fee/keeper/relay_test.go +++ b/modules/apps/29-fee/keeper/relay_test.go @@ -15,7 +15,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgementAsync() { { "success", func() { - suite.chainB.GetSimApp().IBCFeeKeeper.SetRelayerAddressForAsyncAck(suite.chainB.GetContext(), channeltypes.NewPacketId(suite.path.EndpointB.ChannelID, suite.path.EndpointB.ChannelConfig.PortID, 1), suite.chainA.SenderAccount.GetAddress().String()) + suite.chainB.GetSimApp().IBCFeeKeeper.SetRelayerAddressForAsyncAck(suite.chainB.GetContext(), channeltypes.NewPacketId(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, 1), suite.chainA.SenderAccount.GetAddress().String()) suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) }, true, @@ -61,7 +61,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgementAsync() { if tc.expPass { suite.Require().NoError(err) - _, found := suite.chainB.GetSimApp().IBCFeeKeeper.GetRelayerAddressForAsyncAck(suite.chainB.GetContext(), channeltypes.NewPacketId(suite.path.EndpointA.ChannelID, suite.path.EndpointA.ChannelConfig.PortID, 1)) + _, found := suite.chainB.GetSimApp().IBCFeeKeeper.GetRelayerAddressForAsyncAck(suite.chainB.GetContext(), channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1)) suite.Require().False(found) expectedAck := types.NewIncentivizedAcknowledgement(suite.chainB.SenderAccount.GetAddress().String(), ack.Acknowledgement(), ack.Success()) diff --git a/modules/apps/29-fee/types/genesis_test.go b/modules/apps/29-fee/types/genesis_test.go index edcd91c6f9d..d574257e706 100644 --- a/modules/apps/29-fee/types/genesis_test.go +++ b/modules/apps/29-fee/types/genesis_test.go @@ -49,8 +49,8 @@ func TestValidateGenesis(t *testing.T) { "invalid packetID: invalid channel", func() { packetID = channeltypes.NewPacketId( - "", portID, + "", seq, ) }, @@ -60,8 +60,8 @@ func TestValidateGenesis(t *testing.T) { "invalid packetID: invalid port", func() { packetID = channeltypes.NewPacketId( - channelID, "", + channelID, seq, ) }, @@ -71,8 +71,8 @@ func TestValidateGenesis(t *testing.T) { "invalid packetID: invalid sequence", func() { packetID = channeltypes.NewPacketId( - channelID, portID, + channelID, 0, ) }, @@ -195,7 +195,7 @@ func TestValidateGenesis(t *testing.T) { ForwardRelayers: []types.ForwardRelayerAddress{ { Address: forwardAddr, - PacketId: channeltypes.NewPacketId(packetChannelID, portID, 1), + PacketId: channeltypes.NewPacketId(portID, packetChannelID, 1), }, }, } diff --git a/modules/apps/29-fee/types/keys.go b/modules/apps/29-fee/types/keys.go index f2dd3458e20..d98dbcdf5a1 100644 --- a/modules/apps/29-fee/types/keys.go +++ b/modules/apps/29-fee/types/keys.go @@ -100,7 +100,7 @@ func ParseKeyForwardRelayerAddress(key string) (channeltypes.PacketId, error) { return channeltypes.PacketId{}, err } - packetID := channeltypes.NewPacketId(keySplit[2], keySplit[1], seq) + packetID := channeltypes.NewPacketId(keySplit[1], keySplit[2], seq) return packetID, nil } @@ -123,7 +123,7 @@ func ParseKeyFeesInEscrow(key string) (channeltypes.PacketId, error) { return channeltypes.PacketId{}, err } - packetID := channeltypes.NewPacketId(keySplit[2], keySplit[1], seq) + packetID := channeltypes.NewPacketId(keySplit[1], keySplit[2], seq) return packetID, nil } diff --git a/modules/apps/29-fee/types/keys_test.go b/modules/apps/29-fee/types/keys_test.go index 518b2d65604..22dc91b6a57 100644 --- a/modules/apps/29-fee/types/keys_test.go +++ b/modules/apps/29-fee/types/keys_test.go @@ -12,7 +12,7 @@ import ( ) var ( - validPacketID = channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + validPacketID = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) ) func TestKeyCounterpartyRelayer(t *testing.T) { diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go index 8a7ec915a31..d314a4f4193 100644 --- a/modules/apps/29-fee/types/msgs_test.go +++ b/modules/apps/29-fee/types/msgs_test.go @@ -267,7 +267,7 @@ func TestMsgPayPacketFeeAsyncValidation(t *testing.T) { } for _, tc := range testCases { - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, defaultAccAddress, nil) @@ -287,7 +287,7 @@ func TestMsgPayPacketFeeAsyncValidation(t *testing.T) { func TestPayPacketFeeAsyncGetSigners(t *testing.T) { refundAddr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, refundAddr.String(), nil) @@ -307,7 +307,7 @@ func TestMsgPayPacketFeeAsyncType(t *testing.T) { } func TestMsgPayPacketFeeAsyncGetSignBytes(t *testing.T) { - packetID := channeltypes.NewPacketId(ibctesting.FirstChannelID, ibctesting.MockFeePort, 1) + packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, defaultAccAddress, nil) diff --git a/modules/core/04-channel/types/packet.go b/modules/core/04-channel/types/packet.go index 1b69dafa758..dd59c8bfde9 100644 --- a/modules/core/04-channel/types/packet.go +++ b/modules/core/04-channel/types/packet.go @@ -12,11 +12,6 @@ import ( "github.com/cosmos/ibc-go/v3/modules/core/exported" ) -// NewPacketId returns a new instance of PacketId -func NewPacketId(channelId, portId string, seq uint64) PacketId { - return PacketId{ChannelId: channelId, PortId: portId, Sequence: seq} -} - // CommitPacket returns the packet commitment bytes. The commitment consists of: // sha256_hash(timeout_timestamp + timeout_height.RevisionNumber + timeout_height.RevisionHeight + sha256_hash(data)) // from a given packet. This results in a fixed length preimage. @@ -133,3 +128,8 @@ func (p PacketId) Validate() error { return nil } + +// NewPacketId returns a new instance of PacketId +func NewPacketId(portId, channelId string, seq uint64) PacketId { + return PacketId{PortId: portId, ChannelId: channelId, Sequence: seq} +} From a6342fdc2aa5a59a739461097ca9b823f84293d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 11 Apr 2022 16:07:36 +0200 Subject: [PATCH 070/275] feat: allow ability to lock fee module in presence of severe bug (#1239) * apply code changes from pr #1031 * update comments * chore: update fee module is locked error string * update godoc to reference ADR 004 * add more references to ADR 004 --- modules/apps/29-fee/fee_test.go | 10 ++- modules/apps/29-fee/ibc_module.go | 19 ++++- modules/apps/29-fee/ibc_module_test.go | 18 +++++ modules/apps/29-fee/keeper/escrow_test.go | 79 +++++++++++-------- modules/apps/29-fee/keeper/keeper.go | 15 ++++ modules/apps/29-fee/keeper/keeper_test.go | 18 ++++- modules/apps/29-fee/keeper/msg_server.go | 8 ++ modules/apps/29-fee/keeper/msg_server_test.go | 21 ++++- modules/apps/29-fee/types/errors.go | 1 + modules/apps/29-fee/types/keys.go | 6 ++ 10 files changed, 156 insertions(+), 39 deletions(-) diff --git a/modules/apps/29-fee/fee_test.go b/modules/apps/29-fee/fee_test.go index 9369fc16743..d2445adef22 100644 --- a/modules/apps/29-fee/fee_test.go +++ b/modules/apps/29-fee/fee_test.go @@ -21,7 +21,7 @@ type FeeTestSuite struct { chainB *ibctesting.TestChain chainC *ibctesting.TestChain - path *ibctesting.Path + path *ibctesting.Path pathAToC *ibctesting.Path } @@ -63,3 +63,11 @@ func (suite *FeeTestSuite) CreateMockPacket() channeltypes.Packet { 0, ) } + +// helper function +func lockFeeModule(chain *ibctesting.TestChain) { + ctx := chain.GetContext() + storeKey := chain.GetSimApp().GetKey(types.ModuleName) + store := ctx.KVStore(storeKey) + store.Set(types.KeyLocked(), []byte{1}) +} diff --git a/modules/apps/29-fee/ibc_module.go b/modules/apps/29-fee/ibc_module.go index 192193e07cc..9d026a9f032 100644 --- a/modules/apps/29-fee/ibc_module.go +++ b/modules/apps/29-fee/ibc_module.go @@ -231,6 +231,18 @@ func (im IBCModule) OnAcknowledgementPacket( return sdkerrors.Wrapf(err, "cannot unmarshal ICS-29 incentivized packet acknowledgement: %v", ack) } + if im.keeper.IsLocked(ctx) { + // if the fee keeper is locked then fee logic should be skipped + // this may occur in the presence of a severe bug which leads to invalid state + // the fee keeper will be unlocked after manual intervention + // the acknowledgement has been unmarshalled into an ics29 acknowledgement + // since the counterparty is still sending incentivized acknowledgements + // for fee enabled channels + // + // Please see ADR 004 for more information. + return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer) + } + packetID := channeltypes.NewPacketId(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) if found { @@ -251,7 +263,12 @@ func (im IBCModule) OnTimeoutPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - if !im.keeper.IsFeeEnabled(ctx, packet.SourcePort, packet.SourceChannel) { + // if the fee keeper is locked then fee logic should be skipped + // this may occur in the presence of a severe bug which leads to invalid state + // the fee keeper will be unlocked after manual intervention + // + // Please see ADR 004 for more information. + if !im.keeper.IsFeeEnabled(ctx, packet.SourcePort, packet.SourceChannel) || im.keeper.IsLocked(ctx) { return im.app.OnTimeoutPacket(ctx, packet, relayer) } diff --git a/modules/apps/29-fee/ibc_module_test.go b/modules/apps/29-fee/ibc_module_test.go index f2c56576a79..2a54fc03ec3 100644 --- a/modules/apps/29-fee/ibc_module_test.go +++ b/modules/apps/29-fee/ibc_module_test.go @@ -611,6 +611,15 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { }, true, }, + { + "success: fee module is disabled, skip fee logic", + func() { + lockFeeModule(suite.chainA) + + expectedBalance = originalBalance + }, + true, + }, { "fail on distribute receive fee (blocked address)", func() { @@ -724,6 +733,15 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { }, false, }, + { + "fee module is disabled, skip fee logic", + func() { + lockFeeModule(suite.chainA) + + expectedBalance = originalBalance + }, + false, + }, { "no op if identified packet fee doesn't exist", func() { diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 0b9e3045542..b03da9f12ca 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -125,27 +125,62 @@ func (suite *KeeperTestSuite) TestDistributeFee() { reverseRelayer sdk.AccAddress forwardRelayer string refundAcc sdk.AccAddress + refundAccBal sdk.Coin + fee types.Fee + packetID channeltypes.PacketId ) validSeq := uint64(1) testCases := []struct { - name string - malleate func() - expPass bool + name string + malleate func() + expResult func() }{ { - "success", func() {}, true, + "success", func() {}, func() { + // check if the reverse relayer is paid + hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), reverseRelayer, fee.AckFee[0].Add(fee.AckFee[0])) + suite.Require().True(hasBalance) + + // check if the forward relayer is paid + forward, err := sdk.AccAddressFromBech32(forwardRelayer) + suite.Require().NoError(err) + hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), forward, fee.RecvFee[0].Add(fee.RecvFee[0])) + suite.Require().True(hasBalance) + + // check if the refund acc has been refunded the timeoutFee + expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0].Add(fee.TimeoutFee[0])) + hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) + suite.Require().True(hasBalance) + + // check the module acc wallet is now empty + hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(0)}) + suite.Require().True(hasBalance) + }, }, { "invalid forward address", func() { forwardRelayer = "invalid address" - }, false, + }, + func() { + // check if the refund acc has been refunded the timeoutFee & onRecvFee + expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]).Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]) + hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) + suite.Require().True(hasBalance) + + }, }, { "invalid forward address: blocked address", func() { forwardRelayer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() - }, false, + }, + func() { + // check if the refund acc has been refunded the timeoutFee & onRecvFee + expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]).Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]) + hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) + suite.Require().True(hasBalance) + }, }, } @@ -161,8 +196,8 @@ func (suite *KeeperTestSuite) TestDistributeFee() { reverseRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) forwardRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, validSeq) - fee := types.Fee{ + packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, validSeq) + fee = types.Fee{ RecvFee: defaultReceiveFee, AckFee: defaultAckFee, TimeoutFee: defaultTimeoutFee, @@ -180,35 +215,11 @@ func (suite *KeeperTestSuite) TestDistributeFee() { tc.malleate() // refundAcc balance after escrow - refundAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + refundAccBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFees(suite.chainA.GetContext(), forwardRelayer, reverseRelayer, []types.PacketFee{packetFee, packetFee}) - if tc.expPass { - // check if the reverse relayer is paid - hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), reverseRelayer, fee.AckFee[0].Add(fee.AckFee[0])) - suite.Require().True(hasBalance) - - // check if the forward relayer is paid - forward, err := sdk.AccAddressFromBech32(forwardRelayer) - suite.Require().NoError(err) - hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), forward, fee.RecvFee[0].Add(fee.RecvFee[0])) - suite.Require().True(hasBalance) - - // check if the refund acc has been refunded the timeoutFee - expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0].Add(fee.TimeoutFee[0])) - hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) - suite.Require().True(hasBalance) - - // check the module acc wallet is now empty - hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(0)}) - suite.Require().True(hasBalance) - } else { - // check if the refund acc has been refunded the timeoutFee & onRecvFee - expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]).Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]) - hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) - suite.Require().True(hasBalance) - } + tc.expResult() }) } } diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index c0c43dbecc6..2ebec6aaf42 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -85,6 +85,21 @@ func (k Keeper) EscrowAccountHasBalance(ctx sdk.Context, coins sdk.Coins) bool { return true } +// lockFeeModule sets a flag to determine if fee handling logic should run for the given channel +// identified by channel and port identifiers. +// Please see ADR 004 for more information. +func (k Keeper) lockFeeModule(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyLocked(), []byte{1}) +} + +// IsLocked indicates if the fee module is locked +// Please see ADR 004 for more information. +func (k Keeper) IsLocked(ctx sdk.Context) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(types.KeyLocked()) +} + // SetFeeEnabled sets a flag to determine if fee handling logic should run for the given channel // identified by channel and port identifiers. func (k Keeper) SetFeeEnabled(ctx sdk.Context, portID, channelID string) { diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index 29cb19fb8f5..5c44e45c332 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -67,6 +67,14 @@ func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } +// helper function +func lockFeeModule(chain *ibctesting.TestChain) { + ctx := chain.GetContext() + storeKey := chain.GetSimApp().GetKey(types.ModuleName) + store := ctx.KVStore(storeKey) + store.Set(types.KeyLocked(), []byte{1}) +} + func (suite *KeeperTestSuite) TestEscrowAccountHasBalance() { fee := types.Fee{ AckFee: defaultAckFee, @@ -85,7 +93,6 @@ func (suite *KeeperTestSuite) TestEscrowAccountHasBalance() { // increase ack fee fee.AckFee = fee.AckFee.Add(defaultAckFee...) suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.EscrowAccountHasBalance(suite.chainA.GetContext(), fee.Total())) - } func (suite *KeeperTestSuite) TestFeesInEscrow() { @@ -111,6 +118,15 @@ func (suite *KeeperTestSuite) TestFeesInEscrow() { suite.Require().False(hasFeesInEscrow) } +func (suite *KeeperTestSuite) TestIsLocked() { + ctx := suite.chainA.GetContext() + suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(ctx)) + + lockFeeModule(suite.chainA) + + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(ctx)) +} + func (suite *KeeperTestSuite) TestDisableAllChannels() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "port1", "channel1") suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "port2", "channel2") diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index c9100f9c73e..40a7fb4df9c 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -31,6 +31,10 @@ func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.Ms func (k Keeper) PayPacketFee(goCtx context.Context, msg *types.MsgPayPacketFee) (*types.MsgPayPacketFeeResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + if k.IsLocked(ctx) { + return nil, types.ErrFeeModuleLocked + } + // get the next sequence sequence, found := k.GetNextSequenceSend(ctx, msg.SourcePortId, msg.SourceChannelId) if !found { @@ -57,6 +61,10 @@ func (k Keeper) PayPacketFee(goCtx context.Context, msg *types.MsgPayPacketFee) func (k Keeper) PayPacketFeeAsync(goCtx context.Context, msg *types.MsgPayPacketFeeAsync) (*types.MsgPayPacketFeeAsyncResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + if k.IsLocked(ctx) { + return nil, types.ErrFeeModuleLocked + } + if err := k.EscrowPacketFee(ctx, msg.PacketId, msg.PacketFee); err != nil { return nil, err } diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 7a06af6e30b..74c5342d674 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -1,6 +1,8 @@ package keeper_test import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" @@ -62,6 +64,13 @@ func (suite *KeeperTestSuite) TestPayPacketFee() { true, func() {}, }, + { + "fee module is locked", + false, + func() { + lockFeeModule(suite.chainA) + }, + }, } for _, tc := range testCases { @@ -78,7 +87,8 @@ func (suite *KeeperTestSuite) TestPayPacketFee() { msg := types.NewMsgPayPacketFee(fee, suite.path.EndpointA.ChannelConfig.PortID, channelID, refundAcc.String(), []string{}) tc.malleate() - _, err := suite.chainA.SendMsgs(msg) + + _, err := suite.chainA.GetSimApp().IBCFeeKeeper.PayPacketFee(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) if tc.expPass { suite.Require().NoError(err) // message committed @@ -99,6 +109,13 @@ func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { true, func() {}, }, + { + "fee module is locked", + false, + func() { + lockFeeModule(suite.chainA) + }, + }, } for _, tc := range testCases { @@ -125,7 +142,7 @@ func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { tc.malleate() msg := types.NewMsgPayPacketFeeAsync(packetID, packetFee) - _, err := suite.chainA.SendMsgs(msg) + _, err := suite.chainA.GetSimApp().IBCFeeKeeper.PayPacketFeeAsync(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) if tc.expPass { suite.Require().NoError(err) // message committed diff --git a/modules/apps/29-fee/types/errors.go b/modules/apps/29-fee/types/errors.go index 75fdd436c91..812db0a43a4 100644 --- a/modules/apps/29-fee/types/errors.go +++ b/modules/apps/29-fee/types/errors.go @@ -15,4 +15,5 @@ var ( ErrForwardRelayerAddressNotFound = sdkerrors.Register(ModuleName, 8, "forward relayer address not found") ErrFeeNotEnabled = sdkerrors.Register(ModuleName, 9, "fee module is not enabled for this channel. If this error occurs after channel setup, fee module may not be enabled") ErrRelayerNotFoundForAsyncAck = sdkerrors.Register(ModuleName, 10, "relayer address must be stored for async WriteAcknowledgement") + ErrFeeModuleLocked = sdkerrors.Register(ModuleName, 11, "the fee module is currently locked, a severe bug has been detected") ) diff --git a/modules/apps/29-fee/types/keys.go b/modules/apps/29-fee/types/keys.go index d98dbcdf5a1..188a75e7ac3 100644 --- a/modules/apps/29-fee/types/keys.go +++ b/modules/apps/29-fee/types/keys.go @@ -38,6 +38,12 @@ const ( ForwardRelayerPrefix = "forwardRelayer" ) +// KeyLocked returns the key used to lock and unlock the fee module. This key is used +// in the presence of a severe bug. +func KeyLocked() []byte { + return []byte("locked") +} + // KeyFeeEnabled returns the key that stores a flag to determine if fee logic should // be enabled for the given port and channel identifiers. func KeyFeeEnabled(portID, channelID string) []byte { From aee7763f3f0b32bff1f95130b00c0e8ddf2b9eae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Apr 2022 10:27:48 +0000 Subject: [PATCH 071/275] build(deps): bump actions/download-artifact from 2 to 3 (#1241) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 2 to 3.
    Release notes

    Sourced from actions/download-artifact's releases.

    v3.0.0

    What's Changed

    Breaking Changes

    With the update to Node 16, all scripts will now be run with Node 16 rather than Node 12.

    v2.1.0 Download Artifact

    • Improved output & logging
    • Fixed issue where downloading all artifacts could cause display percentages to be over 100%
    • Various small bug fixes & improvements

    v2.0.10

    • Retry on HTTP 500 responses from the service

    v2.0.9

    • Fixes to proxy related issues

    v2.0.8

    • Improvements to retryability if an error is encountered during artifact download

    v2.0.7 download-artifact

    • Improved download retry-ability if a partial download is encountered

    v2.0.6

    Update actions/core NPM package that is used internally

    v2.0.5

    • Add Third Party License Information

    v2.0.4

    • Use the latest version of the @actions/artifact NPM package

    v2.0.3

    • Misc improvements

    v2.0.2

    • Support for tilde expansion

    v2.0.1

    • Download path output
    • Improved logging
    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=2&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    --- .github/workflows/test.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 901d728b4cc..b2987814bba 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -95,7 +95,7 @@ jobs: **/**.go go.mod go.sum - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: "${{ github.sha }}-${{ matrix.part }}" if: env.GIT_DIFF @@ -119,19 +119,19 @@ jobs: **/**.go go.mod go.sum - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: "${{ github.sha }}-00-coverage" if: env.GIT_DIFF - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: "${{ github.sha }}-01-coverage" if: env.GIT_DIFF - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: "${{ github.sha }}-02-coverage" if: env.GIT_DIFF - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: "${{ github.sha }}-03-coverage" if: env.GIT_DIFF From 8c264a80642f9e9c3779a37c336255644f188d49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Apr 2022 10:30:21 +0000 Subject: [PATCH 072/275] build(deps): bump actions/upload-artifact from 2 to 3 (#1240) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 3.
    Release notes

    Sourced from actions/upload-artifact's releases.

    v3.0.0

    What's Changed

    • Update default runtime to node16 (#293)
    • Update package-lock.json file version to 2 (#302)

    Breaking Changes

    With the update to Node 16, all scripts will now be run with Node 16 rather than Node 12.

    v2.3.1

    Fix for empty fails on Windows failing on upload #281

    v2.3.0 Upload Artifact

    • Optimizations for faster uploads of larger files that are already compressed
    • Significantly improved logging when there are chunked uploads
    • Clarifications in logs around the upload size and prohibited characters that aren't allowed in the artifact name or any uploaded files
    • Various other small bugfixes & optimizations

    v2.2.4

    • Retry on HTTP 500 responses from the service

    v2.2.3

    • Fixes for proxy related issues

    v2.2.2

    • Improved retryability and error handling

    v2.2.1

    • Update used actions/core package to the latest version

    v2.2.0

    • Support for artifact retention

    v2.1.4

    • Add Third Party License Information

    v2.1.3

    • Use updated version of the @action/artifact NPM package

    v2.1.2

    • Increase upload chunk size from 4MB to 8MB
    • Detect case insensitive file uploads

    v2.1.1

    • Fix for certain symlinks not correctly being identified as directories before starting uploads

    v2.1.0

    • Support for uploading artifacts with multiple paths
    • Support for using exclude paths
    • Updates to dependencies

    ... (truncated)

    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=2&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    --- .github/workflows/test.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b2987814bba..498c1bb467e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -60,19 +60,19 @@ jobs: - name: Split pkgs into 4 files run: split -d -n l/4 pkgs.txt pkgs.txt.part. # cache multiple - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: "${{ github.sha }}-00" path: ./pkgs.txt.part.00 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: "${{ github.sha }}-01" path: ./pkgs.txt.part.01 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: "${{ github.sha }}-02" path: ./pkgs.txt.part.02 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: "${{ github.sha }}-03" path: ./pkgs.txt.part.03 @@ -103,7 +103,7 @@ jobs: run: | cat pkgs.txt.part.${{ matrix.part }} | xargs go test -race -mod=readonly -timeout 30m -coverprofile=${{ matrix.part }}profile.out -covermode=atomic -tags='ledger test_ledger_mock' if: env.GIT_DIFF - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: "${{ github.sha }}-${{ matrix.part }}-coverage" path: ./${{ matrix.part }}profile.out From caeb1223748fde48acb21556cbe61a9cc9131e26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Apr 2022 10:34:42 +0000 Subject: [PATCH 073/275] build(deps): bump actions/setup-go from 2 to 3 (#1242) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 3.
    Release notes

    Sourced from actions/setup-go's releases.

    v3.0.0

    What's Changed

    Breaking Changes

    With the update to Node 16, all scripts will now be run with Node 16 rather than Node 12.

    This new major release removes the stable input, so there is no need to specify additional input to use pre-release versions. This release also corrects the pre-release versions syntax to satisfy the SemVer notation (1.18.0-beta1 -> 1.18.0-beta.1, 1.18.0-rc1 -> 1.18.0-rc.1).

    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-go@v3
        with:
          go-version: '1.18.0-rc.1'
      - run: go version
    

    Add check-latest input

    In scope of this release we add the check-latest input. If check-latest is set to true, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, a Go version will then be downloaded from go-versions repository. By default check-latest is set to false. Example of usage:

    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-go@v2
        with:
          go-version: '1.16'
          check-latest: true
      - run: go version
    

    Moreover, we updated @actions/core from 1.2.6 to 1.6.0

    v2.1.5

    In scope of this release we updated matchers.json to improve the problem matcher pattern. For more information please refer to this pull request

    v2.1.4

    What's Changed

    New Contributors

    Full Changelog: https://github.com/actions/setup-go/compare/v2.1.3...v2.1.4

    v2.1.3

    • Updated communication with runner to use environment files rather then workflow commands

    v2.1.2

    This release includes vendored licenses for this action's npm dependencies.

    ... (truncated)

    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-go&package-manager=github_actions&previous-version=2&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index db50dc06ba7..06b91b20c75 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: go-version: '1.17' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 498c1bb467e..31ef80c80f2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: install-tparse: runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v2.1.5 + - uses: actions/setup-go@v3 with: go-version: 1.17 - name: Display go version @@ -38,7 +38,7 @@ jobs: go-arch: ["amd64", "arm", "arm64"] steps: - uses: actions/checkout@v3 - - uses: actions/setup-go@v2.1.5 + - uses: actions/setup-go@v3 with: go-version: 1.17 - uses: technote-space/get-diff-action@v6.0.1 @@ -86,7 +86,7 @@ jobs: part: ["00", "01", "02", "03"] steps: - uses: actions/checkout@v3 - - uses: actions/setup-go@v2.1.5 + - uses: actions/setup-go@v3 with: go-version: 1.17 - uses: technote-space/get-diff-action@v6.0.1 From 1d3c1467f6502a9667eff8d48599e7232593a7eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Apr 2022 14:10:36 +0200 Subject: [PATCH 074/275] build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.1 to 0.45.3 (#1247) Bumps [github.com/cosmos/cosmos-sdk](https://github.com/cosmos/cosmos-sdk) from 0.45.1 to 0.45.3. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.45.3/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/v0.45.1...v0.45.3) --- updated-dependencies: - dependency-name: github.com/cosmos/cosmos-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 43 ++++---- go.sum | 302 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 286 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index d13f9bc4ef7..ab0e814bead 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alp require ( github.com/armon/go-metrics v0.3.10 github.com/confio/ics23/go v0.7.0 - github.com/cosmos/cosmos-sdk v0.45.1 + github.com/cosmos/cosmos-sdk v0.45.3 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 @@ -18,9 +18,9 @@ require ( github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.10.1 github.com/stretchr/testify v1.7.1 - github.com/tendermint/tendermint v0.34.14 - github.com/tendermint/tm-db v0.6.4 - google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa + github.com/tendermint/tendermint v0.34.19 + github.com/tendermint/tm-db v0.6.6 + google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb google.golang.org/grpc v1.45.0 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 @@ -31,7 +31,7 @@ require ( github.com/99designs/keyring v1.1.6 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/DataDog/zstd v1.4.5 // indirect - github.com/Workiva/go-datastructures v1.0.52 // indirect + github.com/Workiva/go-datastructures v1.0.53 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect @@ -54,15 +54,16 @@ require ( github.com/felixge/httpsnoop v1.0.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/gin-gonic/gin v1.7.0 // indirect - github.com/go-kit/kit v0.10.0 // indirect - github.com/go-logfmt/logfmt v0.5.0 // indirect + github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/log v0.2.0 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/gateway v1.1.0 // indirect - github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 // indirect + github.com/golang/snappy v0.0.3 // indirect github.com/google/btree v1.0.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/gorilla/handlers v1.5.1 // indirect - github.com/gorilla/websocket v1.4.2 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect @@ -75,29 +76,27 @@ require ( github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect - github.com/klauspost/compress v1.11.7 // indirect - github.com/lib/pq v1.10.2 // indirect + github.com/klauspost/compress v1.13.6 // indirect + github.com/lib/pq v1.10.4 // indirect github.com/libp2p/go-buffer-pool v0.0.2 // indirect github.com/magiconair/properties v1.8.5 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect - github.com/minio/highwayhash v1.0.1 // indirect + github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/opencontainers/image-spec v1.0.2 // indirect - github.com/opencontainers/runc v1.0.3 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.11.0 // indirect + github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.29.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect - github.com/rs/cors v1.7.0 // indirect + github.com/rs/cors v1.8.2 // indirect github.com/rs/zerolog v1.23.0 // indirect github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect github.com/spf13/afero v1.6.0 // indirect @@ -110,10 +109,10 @@ require ( github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/zondax/hid v0.9.0 // indirect - go.etcd.io/bbolt v1.3.5 // indirect - golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect - golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f // indirect - golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect + go.etcd.io/bbolt v1.3.6 // indirect + golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 // indirect + golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b // indirect + golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect golang.org/x/text v0.3.7 // indirect gopkg.in/ini.v1 v1.66.2 // indirect diff --git a/go.sum b/go.sum index a3904fbbaa6..63461520875 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -18,6 +19,14 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -27,6 +36,7 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -43,6 +53,9 @@ github.com/99designs/keyring v1.1.6 h1:kVDC2uCgVwecxCk+9zoCt2uEL6dt+dfVzMvGgnVcI github.com/99designs/keyring v1.1.6/go.mod h1:16e0ds7LGQQcT59QqkTg72Hh5ShM51Byv5PEmW6uoRU= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= @@ -58,17 +71,22 @@ github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= @@ -79,13 +97,16 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9abU0yMQt0NI= github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= +github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM= -github.com/adlio/schema v1.1.13 h1:LeNMVg5Z1FX+Qgz8tJUijBLRdcpbFUElz+d1489On98= github.com/adlio/schema v1.1.13/go.mod h1:L5Z7tw+7lRK1Fnpi/LT/ooCP1elkXn0krMWBQHUhEDE= +github.com/adlio/schema v1.3.0 h1:eSVYLxYWbm/6ReZBCkLw4Fz7uqC+ZNoPvA39bOwi52A= +github.com/adlio/schema v1.3.0/go.mod h1:51QzxkpeFs6lRY11kPye26IaFPOV+HqEj01t5aXXKfs= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -103,11 +124,17 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4 github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -116,7 +143,6 @@ github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= @@ -139,9 +165,12 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -155,6 +184,7 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= @@ -165,7 +195,9 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg= @@ -174,8 +206,9 @@ github.com/confio/ics23/go v0.6.6/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4ur github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8= github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 h1:NmTXa/uVnDyp0TY5MKi197+3HWcnYWfnHGyaFthlnGw= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.2.1 h1:/EeEo2EtN3umhbbgCveyjifoMYg0pS+nMMEemaYw634= +github.com/containerd/continuity v0.2.1/go.mod h1:wCYX+dRqZdImhGucXOqTQn05AhX6EUDaGEMUzTFFpLg= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -189,8 +222,8 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= -github.com/cosmos/cosmos-sdk v0.45.1 h1:PY79YxPea5qlRLExRnzg8/rT1Scc8GGgRs22p7DX99Q= -github.com/cosmos/cosmos-sdk v0.45.1/go.mod h1:XXS/asyCqWNWkx2rW6pSuen+EVcpAFxq6khrhnZgHaQ= +github.com/cosmos/cosmos-sdk v0.45.3 h1:PiVSU3IkNEDPhoxOZHk2lPnhwBBJgEYAtAR0jGXRN4g= +github.com/cosmos/cosmos-sdk v0.45.3/go.mod h1:qYm5JEr0ZlbnmoP/Q3b+dYMOliHf4ddHirpILiwZzqg= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -215,6 +248,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= @@ -228,6 +262,7 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= @@ -254,7 +289,9 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -264,13 +301,18 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQD github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -289,13 +331,17 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= @@ -307,9 +353,10 @@ github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7a github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= @@ -322,12 +369,17 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -359,8 +411,9 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg= github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -376,6 +429,7 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= @@ -383,6 +437,7 @@ github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -396,12 +451,17 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -412,10 +472,12 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -438,18 +500,27 @@ github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uM github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -465,15 +536,23 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87/go.mod h1:XGsKKeXxeRr95aEOgipvluMPlgjr7dGlk9ZTWOjcUcg= github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/improbable-eng/grpc-web v0.14.1 h1:NrN4PY71A6tAz2sKDvC5JCauENWp0ykG8Oq1H3cpFvw= @@ -482,6 +561,7 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -489,6 +569,8 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jhump/protoreflect v1.9.0 h1:npqHz788dryJiR/l6K/RUQAyh2SwV91+d1dnh4RjO9w= github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -501,12 +583,14 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= @@ -514,8 +598,10 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -531,13 +617,14 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= +github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -545,26 +632,39 @@ github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaW github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -574,7 +674,7 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= @@ -584,6 +684,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= @@ -595,10 +697,16 @@ github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= +github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= @@ -627,8 +735,9 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -642,10 +751,12 @@ github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= @@ -661,15 +772,17 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -679,6 +792,7 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= @@ -687,8 +801,9 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -706,8 +821,9 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8 github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.29.0 h1:3jqPBvKT4OHAbje2Ql7KeaaSicDBCxMYwEJU1zRJceE= -github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -716,8 +832,9 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= @@ -734,8 +851,9 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.23.0 h1:UskrK+saS9P9Y789yNNulYKdARjPZuS35B8gJF2x60g= @@ -744,6 +862,7 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= @@ -768,16 +887,16 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -788,9 +907,9 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= @@ -798,7 +917,9 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8 github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -824,19 +945,25 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RM github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/tendermint v0.34.14 h1:GCXmlS8Bqd2Ix3TQCpwYLUNHe+Y+QyJsm5YE+S/FkPo= github.com/tendermint/tendermint v0.34.14/go.mod h1:FrwVm3TvsVicI9Z7FlucHV6Znfd5KBc/Lpp69cCwtk0= -github.com/tendermint/tm-db v0.6.4 h1:3N2jlnYQkXNQclQwd/eKV/NzlqPlfK21cpRRIx80XXQ= +github.com/tendermint/tendermint v0.34.19 h1:y0P1qI5wSa9IRuhKnTDA6IUcOrLi1hXJuALR+R7HFEk= +github.com/tendermint/tendermint v0.34.19/go.mod h1:R5+wgIwSxMdKQcmOaeudL0Cjkr3HDkhpcdum6VeU3R4= github.com/tendermint/tm-db v0.6.4/go.mod h1:dptYhIpJ2M5kUuenLr+Yyf3zQOv1SgBZcl8/BmWlMBw= +github.com/tendermint/tm-db v0.6.6 h1:EzhaOfR0bdKyATqcd5PNeyeq8r+V4bRPHBfyFdD9kGM= +github.com/tendermint/tm-db v0.6.6/go.mod h1:wP8d49A85B7/erz/r4YbKssKw6ylsO/hKtFk7E1aWZI= github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg= +github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -861,12 +988,17 @@ github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -881,13 +1013,17 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -899,17 +1035,26 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 h1:3erb+vDS8lU1sxfDHF4/hhWyaXnhIaO+7RgL4fDZORA= +golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= @@ -921,6 +1066,7 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -948,6 +1094,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -964,6 +1111,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -998,10 +1146,17 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b h1:MWaHNqZy3KTpuTMAGvv+Kw+ylsEpmyJZizz1dqxnu28= +golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1013,8 +1168,12 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1037,6 +1196,7 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1050,19 +1210,23 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1082,6 +1246,7 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1091,6 +1256,7 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1099,13 +1265,25 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1123,9 +1301,13 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1138,6 +1320,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1174,6 +1357,7 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1183,12 +1367,18 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1211,7 +1401,17 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1266,10 +1466,30 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb h1:ZrsicilzPCS/Xr8qtBZZLpy4P9TYXAfl49ctG1/5tgw= +google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1297,11 +1517,17 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1322,6 +1548,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -1329,7 +1556,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= @@ -1364,7 +1590,9 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= From 960a49effeb2b34d464d3f82cd50f23a3b374ece Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 12 Apr 2022 17:22:11 +0200 Subject: [PATCH 075/275] chore(ics29): refund fees on distribution failure (#1245) * attempt to refund fees if distribution fails * adapting logic and updating testcases * updating inline comments * updating refund address testcase --- modules/apps/29-fee/ibc_module_test.go | 7 +- modules/apps/29-fee/keeper/escrow.go | 38 +++++--- modules/apps/29-fee/keeper/escrow_test.go | 110 ++++++++++++++-------- 3 files changed, 98 insertions(+), 57 deletions(-) diff --git a/modules/apps/29-fee/ibc_module_test.go b/modules/apps/29-fee/ibc_module_test.go index 2a54fc03ec3..4ca50d2c612 100644 --- a/modules/apps/29-fee/ibc_module_test.go +++ b/modules/apps/29-fee/ibc_module_test.go @@ -631,7 +631,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { }.Acknowledgement() expectedRelayerBalance = packetFee.Fee.AckFee - expectedBalance = expectedBalance.Add(packetFee.Fee.RecvFee[0]) + expectedBalance = expectedBalance.Add(packetFee.Fee.RecvFee...) }, true, }, @@ -759,8 +759,9 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { relayerAddr = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() expectedBalance = originalBalance. - Add(packetFee.Fee.RecvFee[0]). - Add(packetFee.Fee.AckFee[0]) + Add(packetFee.Fee.RecvFee...). + Add(packetFee.Fee.AckFee...). + Add(packetFee.Fee.TimeoutFee...) }, false, }, diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 40aad06e3be..f0c18e379ba 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -1,6 +1,7 @@ package keeper import ( + "bytes" "fmt" sdk "github.com/cosmos/cosmos-sdk/types" @@ -61,17 +62,17 @@ func (k Keeper) DistributePacketFees(ctx sdk.Context, forwardRelayer string, rev // distribute fee to valid forward relayer address otherwise refund the fee if !forwardAddr.Empty() && !k.bankKeeper.BlockedAddr(forwardAddr) { // distribute fee for forward relaying - k.distributeFee(ctx, forwardAddr, packetFee.Fee.RecvFee) + k.distributeFee(ctx, forwardAddr, refundAddr, packetFee.Fee.RecvFee) } else { // refund onRecv fee as forward relayer is not valid address - k.distributeFee(ctx, refundAddr, packetFee.Fee.RecvFee) + k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.RecvFee) } // distribute fee for reverse relaying - k.distributeFee(ctx, reverseRelayer, packetFee.Fee.AckFee) + k.distributeFee(ctx, reverseRelayer, refundAddr, packetFee.Fee.AckFee) // refund timeout fee for unused timeout - k.distributeFee(ctx, refundAddr, packetFee.Fee.TimeoutFee) + k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.TimeoutFee) } } @@ -85,31 +86,42 @@ func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sd } // refund receive fee for unused forward relaying - k.distributeFee(ctx, refundAddr, feeInEscrow.Fee.RecvFee) + k.distributeFee(ctx, refundAddr, refundAddr, feeInEscrow.Fee.RecvFee) // refund ack fee for unused reverse relaying - k.distributeFee(ctx, refundAddr, feeInEscrow.Fee.AckFee) + k.distributeFee(ctx, refundAddr, refundAddr, feeInEscrow.Fee.AckFee) // distribute fee for timeout relaying - k.distributeFee(ctx, timeoutRelayer, feeInEscrow.Fee.TimeoutFee) + k.distributeFee(ctx, timeoutRelayer, refundAddr, feeInEscrow.Fee.TimeoutFee) } } // distributeFee will attempt to distribute the escrowed fee to the receiver address. // If the distribution fails for any reason (such as the receiving address being blocked), // the state changes will be discarded. -func (k Keeper) distributeFee(ctx sdk.Context, receiver sdk.AccAddress, fee sdk.Coins) { +func (k Keeper) distributeFee(ctx sdk.Context, receiver, refundAccAddress sdk.AccAddress, fee sdk.Coins) { // cache context before trying to distribute fees cacheCtx, writeFn := ctx.CacheContext() err := k.bankKeeper.SendCoinsFromModuleToAccount(cacheCtx, types.ModuleName, receiver, fee) - if err == nil { - // write the cache - writeFn() + if err != nil { + if bytes.Equal(receiver, refundAccAddress) { + return // if sending to the refund address already failed, then return (no-op) + } - // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. - ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + // if an error is returned from x/bank and the receiver is not the refundAccAddress + // then attempt to refund the fee to the original sender + err := k.bankKeeper.SendCoinsFromModuleToAccount(cacheCtx, types.ModuleName, refundAccAddress, fee) + if err != nil { + return // if sending to the refund address fails, no-op + } } + + // write the cache + writeFn() + + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) } func (k Keeper) RefundFeesOnChannel(ctx sdk.Context, portID, channelID string) error { diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index b03da9f12ca..052a8cdc9c1 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -122,64 +122,93 @@ func (suite *KeeperTestSuite) TestEscrowPacketFee() { func (suite *KeeperTestSuite) TestDistributeFee() { var ( - reverseRelayer sdk.AccAddress - forwardRelayer string - refundAcc sdk.AccAddress - refundAccBal sdk.Coin - fee types.Fee - packetID channeltypes.PacketId + forwardRelayer string + forwardRelayerBal sdk.Coin + reverseRelayer sdk.AccAddress + reverseRelayerBal sdk.Coin + refundAcc sdk.AccAddress + refundAccBal sdk.Coin + packetFee types.PacketFee ) - validSeq := uint64(1) - testCases := []struct { name string malleate func() expResult func() }{ { - "success", func() {}, func() { + "success", + func() {}, + func() { // check if the reverse relayer is paid - hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), reverseRelayer, fee.AckFee[0].Add(fee.AckFee[0])) - suite.Require().True(hasBalance) + expectedReverseAccBal := reverseRelayerBal.Add(defaultAckFee[0]).Add(defaultAckFee[0]) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), reverseRelayer, sdk.DefaultBondDenom) + suite.Require().Equal(expectedReverseAccBal, balance) // check if the forward relayer is paid forward, err := sdk.AccAddressFromBech32(forwardRelayer) suite.Require().NoError(err) - hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), forward, fee.RecvFee[0].Add(fee.RecvFee[0])) - suite.Require().True(hasBalance) + + expectedForwardAccBal := forwardRelayerBal.Add(defaultReceiveFee[0]).Add(defaultReceiveFee[0]) + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), forward, sdk.DefaultBondDenom) + suite.Require().Equal(expectedForwardAccBal, balance) // check if the refund acc has been refunded the timeoutFee - expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0].Add(fee.TimeoutFee[0])) - hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) - suite.Require().True(hasBalance) + expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0].Add(defaultTimeoutFee[0])) + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(expectedRefundAccBal, balance) // check the module acc wallet is now empty - hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(0)}) - suite.Require().True(hasBalance) + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(0)), balance) }, }, { - "invalid forward address", func() { + "invalid forward address", + func() { forwardRelayer = "invalid address" }, func() { - // check if the refund acc has been refunded the timeoutFee & onRecvFee - expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]).Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]) - hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) - suite.Require().True(hasBalance) - + // check if the refund acc has been refunded the timeoutFee & recvFee + expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultReceiveFee[0]).Add(defaultTimeoutFee[0]).Add(defaultReceiveFee[0]) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(expectedRefundAccBal, balance) }, }, { - "invalid forward address: blocked address", func() { + "invalid forward address: blocked address", + func() { forwardRelayer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() }, func() { - // check if the refund acc has been refunded the timeoutFee & onRecvFee - expectedRefundAccBal := refundAccBal.Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]).Add(fee.TimeoutFee[0]).Add(fee.RecvFee[0]) - hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) - suite.Require().True(hasBalance) + // check if the refund acc has been refunded the timeoutFee & recvFee + expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultReceiveFee[0]).Add(defaultTimeoutFee[0]).Add(defaultReceiveFee[0]) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(expectedRefundAccBal, balance) + }, + }, + { + "invalid receiver address: ack fee returned to sender", + func() { + reverseRelayer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() + }, + func() { + // check if the refund acc has been refunded the timeoutFee & ackFee + expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultAckFee[0]).Add(defaultTimeoutFee[0]).Add(defaultAckFee[0]) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(expectedRefundAccBal, balance) + }, + }, + { + "invalid refund address: no-op, timeout fee remains in escrow", + func() { + packetFee.RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() + }, + func() { + // check if the module acc contains the timeoutFee + expectedModuleAccBal := sdk.NewCoin(sdk.DefaultBondDenom, defaultTimeoutFee.Add(defaultTimeoutFee...).AmountOf(sdk.DefaultBondDenom)) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(expectedModuleAccBal, balance) }, }, } @@ -191,30 +220,29 @@ func (suite *KeeperTestSuite) TestDistributeFee() { suite.SetupTest() // reset suite.coordinator.Setup(suite.path) // setup channel - // setup - refundAcc = suite.chainA.SenderAccount.GetAddress() - reverseRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + // setup accounts forwardRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + reverseRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + refundAcc = suite.chainA.SenderAccount.GetAddress() - packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, validSeq) - fee = types.Fee{ - RecvFee: defaultReceiveFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, - } + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) // escrow the packet fee & store the fee in state - packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) - + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) suite.Require().NoError(err) + // escrow a second packet fee to test with multiple fees distributed err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) suite.Require().NoError(err) tc.malleate() - // refundAcc balance after escrow + // fetch the account balances before fee distribution (forward, reverse, refund) + forwardAccAddress, _ := sdk.AccAddressFromBech32(forwardRelayer) + forwardRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), forwardAccAddress, sdk.DefaultBondDenom) + reverseRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), reverseRelayer, sdk.DefaultBondDenom) refundAccBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFees(suite.chainA.GetContext(), forwardRelayer, reverseRelayer, []types.PacketFee{packetFee, packetFee}) From e59a6d2b88fbd543016b0a148b19fac368696ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Apr 2022 11:49:23 +0200 Subject: [PATCH 076/275] refactor: Fix RefundFeesOnChannel (#1244) ## Description read #1060 closes: #860 closes: #780 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [x] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [x] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [x] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [x] Review `Codecov Report` in the comment section below once CI passes --- modules/apps/29-fee/ibc_module.go | 37 +--- modules/apps/29-fee/ibc_module_test.go | 191 +++++++++--------- modules/apps/29-fee/keeper/escrow.go | 64 ++++--- modules/apps/29-fee/keeper/escrow_test.go | 223 +++++++++++++++++----- modules/apps/29-fee/keeper/keeper.go | 37 ++-- modules/apps/29-fee/keeper/keeper_test.go | 83 ++++++-- modules/apps/29-fee/transfer_test.go | 6 +- 7 files changed, 402 insertions(+), 239 deletions(-) diff --git a/modules/apps/29-fee/ibc_module.go b/modules/apps/29-fee/ibc_module.go index 9d026a9f032..c542c5999e6 100644 --- a/modules/apps/29-fee/ibc_module.go +++ b/modules/apps/29-fee/ibc_module.go @@ -148,19 +148,8 @@ func (im IBCModule) OnChanCloseInit( return err } - // delete fee enabled on channel - // and refund any remaining fees escrowed on channel - im.keeper.DeleteFeeEnabled(ctx, portID, channelID) - err := im.keeper.RefundFeesOnChannel(ctx, portID, channelID) - // error should only be non-nil if there is a bug in the code - // that causes module account to have insufficient funds to refund - // all escrowed fees on the channel. - // Disable all channels to allow for coordinated fix to the issue - // and mitigate/reverse damage. - // NOTE: Underlying application's packets will still go through, but - // fee module will be disabled for all channels - if err != nil { - im.keeper.DisableAllChannels(ctx) + if err := im.keeper.RefundFeesOnChannelClosure(ctx, portID, channelID); err != nil { + return err } return nil @@ -172,21 +161,15 @@ func (im IBCModule) OnChanCloseConfirm( portID, channelID string, ) error { - // delete fee enabled on channel - // and refund any remaining fees escrowed on channel - im.keeper.DeleteFeeEnabled(ctx, portID, channelID) - err := im.keeper.RefundFeesOnChannel(ctx, portID, channelID) - // error should only be non-nil if there is a bug in the code - // that causes module account to have insufficient funds to refund - // all escrowed fees on the channel. - // Disable all channels to allow for coordinated fix to the issue - // and mitigate/reverse damage. - // NOTE: Underlying application's packets will still go through, but - // fee module will be disabled for all channels - if err != nil { - im.keeper.DisableAllChannels(ctx) + if err := im.app.OnChanCloseConfirm(ctx, portID, channelID); err != nil { + return err } - return im.app.OnChanCloseConfirm(ctx, portID, channelID) + + if err := im.keeper.RefundFeesOnChannelClosure(ctx, portID, channelID); err != nil { + return err + } + + return nil } // OnRecvPacket implements the IBCModule interface. diff --git a/modules/apps/29-fee/ibc_module_test.go b/modules/apps/29-fee/ibc_module_test.go index 4ca50d2c612..1e5743f7490 100644 --- a/modules/apps/29-fee/ibc_module_test.go +++ b/modules/apps/29-fee/ibc_module_test.go @@ -16,9 +16,9 @@ import ( ) var ( - validCoins = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}} - validCoins2 = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}} - validCoins3 = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(300)}} + defaultRecvFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}} + defaultAckFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}} + defaultTimeoutFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(300)}} ) // Tests OnChanOpenInit on ChainA @@ -291,47 +291,39 @@ func (suite *FeeTestSuite) TestOnChanOpenAck() { } } -// Tests OnChanCloseInit on chainA func (suite *FeeTestSuite) TestOnChanCloseInit() { + var ( + refundAcc sdk.AccAddress + fee types.Fee + ) + testCases := []struct { name string - setup func(suite *FeeTestSuite) - disabled bool + malleate func() + expPass bool }{ { - "success", - func(suite *FeeTestSuite) { - packetID := channeltypes.NewPacketId( - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - 1, - ) - refundAcc := suite.chainA.SenderAccount.GetAddress() - packetFee := types.NewPacketFee(types.Fee{validCoins, validCoins2, validCoins3}, refundAcc.String(), []string{}) - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - }, - false, + "success", func() {}, true, }, { - "module account balance insufficient", - func(suite *FeeTestSuite) { - packetID := channeltypes.NewPacketId( - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - 1, - ) - refundAcc := suite.chainA.SenderAccount.GetAddress() - packetFee := types.NewPacketFee(types.Fee{validCoins, validCoins2, validCoins3}, refundAcc.String(), []string{}) - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, refundAcc, validCoins3) + "application callback fails", func() { + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanCloseInit = func( + ctx sdk.Context, portID, channelID string, + ) error { + return fmt.Errorf("application callback fails") + } + }, false, + }, + { + "RefundFeesOnChannelClosure fails - invalid refund address", func() { + // store the fee in state & update escrow account balance + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) + packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) - // set fee enabled on different channel - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "portID7", "channel-7") + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) }, - true, + false, }, } @@ -341,9 +333,19 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { suite.SetupTest() suite.coordinator.Setup(suite.path) // setup channel - origBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress()) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + fee = types.Fee{ + RecvFee: defaultRecvFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } - tc.setup(suite) + refundAcc = suite.chainA.SenderAccount.GetAddress() + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + tc.malleate() module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) suite.Require().NoError(err) @@ -351,19 +353,12 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - if tc.disabled { - suite.Require().True( - suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID), - "fee is not disabled on original channel: %s", suite.path.EndpointA.ChannelID, - ) - suite.Require().True( - suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "portID7", "channel-7"), - "fee is not disabled on other channel: %s", "channel-7", - ) + err = cbs.OnChanCloseInit(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + + if tc.expPass { + suite.Require().NoError(err) } else { - cbs.OnChanCloseInit(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) - afterBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress()) - suite.Require().Equal(origBal, afterBal, "balances of refund account not equal after all fees refunded") + suite.Require().Error(err) } }) } @@ -371,57 +366,61 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { // Tests OnChanCloseConfirm on chainA func (suite *FeeTestSuite) TestOnChanCloseConfirm() { + var ( + refundAcc sdk.AccAddress + fee types.Fee + ) + testCases := []struct { name string - setup func(suite *FeeTestSuite) - disabled bool + malleate func() + expPass bool }{ { - "success", - func(suite *FeeTestSuite) { - packetID := channeltypes.PacketId{ - PortId: suite.path.EndpointA.ChannelConfig.PortID, - ChannelId: suite.path.EndpointA.ChannelID, - Sequence: 1, - } - refundAcc := suite.chainA.SenderAccount.GetAddress() - packetFee := types.NewPacketFee(types.Fee{validCoins, validCoins2, validCoins3}, refundAcc.String(), []string{}) - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - }, - false, + "success", func() {}, true, }, { - "module account balance insufficient", - func(suite *FeeTestSuite) { - packetID := channeltypes.PacketId{ - PortId: suite.path.EndpointA.ChannelConfig.PortID, - ChannelId: suite.path.EndpointA.ChannelID, - Sequence: 1, + "application callback fails", func() { + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanCloseConfirm = func( + ctx sdk.Context, portID, channelID string, + ) error { + return fmt.Errorf("application callback fails") } - refundAcc := suite.chainA.SenderAccount.GetAddress() - packetFee := types.NewPacketFee(types.Fee{validCoins, validCoins2, validCoins3}, refundAcc.String(), []string{}) - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, refundAcc, validCoins3) + }, false, + }, + { + "RefundChannelFeesOnClosure fails - refund address is invalid", func() { + // store the fee in state & update escrow account balance + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) + packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) - // set fee enabled on different channel - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "portID7", "channel-7") + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) }, - true, + false, }, } for _, tc := range testCases { tc := tc + suite.Run(tc.name, func() { suite.SetupTest() suite.coordinator.Setup(suite.path) // setup channel - origBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress()) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + fee = types.Fee{ + RecvFee: defaultRecvFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } - tc.setup(suite) + refundAcc = suite.chainA.SenderAccount.GetAddress() + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) + + tc.malleate() module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) suite.Require().NoError(err) @@ -429,20 +428,14 @@ func (suite *FeeTestSuite) TestOnChanCloseConfirm() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - if tc.disabled { - suite.Require().True( - suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID), - "fee is not disabled on original channel: %s", suite.path.EndpointA.ChannelID, - ) - suite.Require().True( - suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "portID7", "channel-7"), - "fee is not disabled on other channel: %s", "channel-7", - ) + err = cbs.OnChanCloseConfirm(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + + if tc.expPass { + suite.Require().NoError(err) } else { - cbs.OnChanCloseConfirm(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) - afterBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress()) - suite.Require().Equal(origBal, afterBal, "balances of refund account not equal after all fees refunded") + suite.Require().Error(err) } + }) } } @@ -657,9 +650,9 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { packetID := channeltypes.NewPacketId(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) packetFee = types.NewPacketFee( types.Fee{ - RecvFee: validCoins, - AckFee: validCoins2, - TimeoutFee: validCoins3, + RecvFee: defaultRecvFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, }, suite.chainA.SenderAccount.GetAddress().String(), []string{}, @@ -788,9 +781,9 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { packetFee = types.NewPacketFee( types.Fee{ - RecvFee: validCoins, - AckFee: validCoins2, - TimeoutFee: validCoins3, + RecvFee: defaultRecvFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, }, suite.chainA.SenderAccount.GetAddress().String(), []string{}, diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index f0c18e379ba..8f201293860 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -124,37 +124,57 @@ func (k Keeper) distributeFee(ctx sdk.Context, receiver, refundAccAddress sdk.Ac ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) } -func (k Keeper) RefundFeesOnChannel(ctx sdk.Context, portID, channelID string) error { +// RefundFeesOnChannelClosure will refund all fees associated with the given port and channel identifiers. +// If the escrow account runs out of balance then fee module will become locked as this implies the presence +// of a severe bug. When the fee module is locked, no fee distributions will be performed. +// Please see ADR 004 for more information. +func (k Keeper) RefundFeesOnChannelClosure(ctx sdk.Context, portID, channelID string) error { + identifiedPacketFees := k.GetIdentifiedPacketFeesForChannel(ctx, portID, channelID) - var refundErr error + // cache context before trying to distribute fees + // if the escrow account has insufficient balance then we want to avoid partially distributing fees + cacheCtx, writeFn := ctx.CacheContext() + + for _, identifiedPacketFee := range identifiedPacketFees { + for _, packetFee := range identifiedPacketFee.PacketFees { + + if !k.EscrowAccountHasBalance(cacheCtx, packetFee.Fee.Total()) { + // if the escrow account does not have sufficient funds then there must exist a severe bug + // the fee module should be locked until manual intervention fixes the issue + // a locked fee module will simply skip fee logic, all channels will temporarily function as + // fee disabled channels + // NOTE: we use the uncached context to lock the fee module so that the state changes from + // locking the fee module are persisted + k.lockFeeModule(ctx) - k.IteratePacketFeesInEscrow(ctx, portID, channelID, func(packetFees types.PacketFees) (stop bool) { - for _, identifiedFee := range packetFees.PacketFees { - refundAccAddr, err := sdk.AccAddressFromBech32(identifiedFee.RefundAddress) + // return a nil error so state changes are committed but distribution stops + return nil + } + + refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) if err != nil { - refundErr = err - return true + return err + } + + // if the refund address is blocked, skip and continue distribution + if k.bankKeeper.BlockedAddr(refundAddr) { + continue } // refund all fees to refund address // Use SendCoins rather than the module account send functions since refund address may be a user account or module address. - // if any `SendCoins` call returns an error, we return error and stop iteration - if err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, refundAccAddr, identifiedFee.Fee.RecvFee); err != nil { - refundErr = err - return true - } - if err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, refundAccAddr, identifiedFee.Fee.AckFee); err != nil { - refundErr = err - return true - } - if err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, refundAccAddr, identifiedFee.Fee.TimeoutFee); err != nil { - refundErr = err - return true + moduleAcc := k.GetFeeModuleAddress() + if err = k.bankKeeper.SendCoins(cacheCtx, moduleAcc, refundAddr, packetFee.Fee.Total()); err != nil { + return err } + } - return false - }) + k.DeleteFeesInEscrow(cacheCtx, identifiedPacketFee.PacketId) + } + + // write the cache + writeFn() - return refundErr + return nil } diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 052a8cdc9c1..85747ae7acf 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" ) func (suite *KeeperTestSuite) TestEscrowPacketFee() { @@ -300,59 +299,193 @@ func (suite *KeeperTestSuite) TestDistributeTimeoutFee() { suite.Require().True(hasBalance) } -func (suite *KeeperTestSuite) TestRefundFeesOnChannel() { - suite.coordinator.Setup(suite.path) +func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { + var ( + expIdentifiedPacketFees []types.IdentifiedPacketFees + expEscrowBal sdk.Coins + expRefundBal sdk.Coins + refundAcc sdk.AccAddress + fee types.Fee + locked bool + ) - // setup - refundAcc := suite.chainA.SenderAccount.GetAddress() + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", func() { + for i := 1; i < 6; i++ { + // store the fee in state & update escrow account balance + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(i)) + packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) + identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) - // refundAcc balance before escrow - prevBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) - - for i := 0; i < 5; i++ { - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(i)) - fee := types.Fee{ - RecvFee: defaultReceiveFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, - } - - packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - } + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - // send a packet over a different channel to ensure this fee is not refunded - packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, "channel-1", 1) - fee := types.Fee{ - RecvFee: defaultReceiveFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + + expIdentifiedPacketFees = append(expIdentifiedPacketFees, identifiedPacketFees) + } + }, true, + }, + { + "success with undistributed packet fees on a different channel", func() { + for i := 1; i < 6; i++ { + // store the fee in state & update escrow account balance + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(i)) + packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) + identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) + + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + + expIdentifiedPacketFees = append(expIdentifiedPacketFees, identifiedPacketFees) + } + + // set packet fee for a different channel + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, "channel-1", uint64(1)) + packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, "channel-1") + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + + expEscrowBal = fee.Total() + expRefundBal = expRefundBal.Sub(fee.Total()) + }, true, + }, + { + "escrow account empty, module should become locked", func() { + locked = true + + // store the fee in state without updating escrow account balance + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) + packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) + identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) + + expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} + }, + true, + }, + { + "escrow account goes negative on second packet, module should become locked", func() { + locked = true + + // store 2 fees in state + packetID1 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) + packetID2 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(2)) + packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, refundAcc.String(), nil)}) + identifiedPacketFee1 := types.NewIdentifiedPacketFees(packetID1, packetFees.PacketFees) + identifiedPacketFee2 := types.NewIdentifiedPacketFees(packetID2, packetFees.PacketFees) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID1, packetFees) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID2, packetFees) + + // update escrow account balance for 1 fee + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + + expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFee1, identifiedPacketFee2} + }, true, + }, + { + "invalid refund acc address", func() { + // store the fee in state & update escrow account balance + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) + packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) + identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) + + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + + expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} + }, false, + }, + { + "distributing to blocked address is skipped", func() { + blockedAddr := suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() + + // store the fee in state & update escrow account balance + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) + packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, blockedAddr, nil)}) + identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) + + suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + + expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} + + expEscrowBal = fee.Total() + expRefundBal = expRefundBal.Sub(fee.Total()) + }, true, + }, } - packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, "channel-1") - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) + for _, tc := range testCases { + tc := tc - // check that refunding all fees on channel-0 refunds all fees except for fee on channel-1 - err = suite.chainA.GetSimApp().IBCFeeKeeper.RefundFeesOnChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) - suite.Require().NoError(err, "refund fees returned unexpected error") + suite.Run(tc.name, func() { + suite.SetupTest() // reset + suite.coordinator.Setup(suite.path) // setup channel + expIdentifiedPacketFees = []types.IdentifiedPacketFees{} + expEscrowBal = sdk.Coins{} + locked = false - // add fee sent to channel-1 to after balance to recover original balance - afterBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) - suite.Require().Equal(prevBal, afterBal.Add(fee.RecvFee...).Add(fee.AckFee...).Add(fee.TimeoutFee...), "refund account not back to original balance after refunding all tokens") + // setup + refundAcc = suite.chainA.SenderAccount.GetAddress() + moduleAcc := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress() - // create escrow and then change module account balance to cause error on refund - packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(6)) + // expected refund balance if the refunds are successful + // NOTE: tc.malleate() should transfer from refund balance to correctly set the escrow balance + expRefundBal = suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) - packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) - err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) + fee = types.Fee{ + RecvFee: defaultReceiveFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, + } + + tc.malleate() + + // refundAcc balance before distribution + originalRefundBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) + originalEscrowBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), moduleAcc) - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, refundAcc, fee.TimeoutFee) + err := suite.chainA.GetSimApp().IBCFeeKeeper.RefundFeesOnChannelClosure(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) - err = suite.chainA.GetSimApp().IBCFeeKeeper.RefundFeesOnChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) - suite.Require().Error(err, "refund fees returned no error with insufficient balance on module account") + // refundAcc balance after RefundFeesOnChannelClosure + refundBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) + escrowBal := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), moduleAcc) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + suite.Require().Equal(locked, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + + if locked || !tc.expPass { + // refund account and escrow account balances should remain unchanged + suite.Require().Equal(originalRefundBal, refundBal) + suite.Require().Equal(originalEscrowBal, escrowBal) + + // ensure none of the fees were deleted + suite.Require().Equal(expIdentifiedPacketFees, suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + } else { + suite.Require().Equal(expEscrowBal, escrowBal) // escrow balance should be empty + suite.Require().Equal(expRefundBal, refundBal) // all packets should have been refunded + + // all fees in escrow should be deleted for this channel + suite.Require().Empty(suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + } + + }) + } } diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index 2ebec6aaf42..e0317d3660a 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -69,7 +69,7 @@ func (k Keeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) ( return k.channelKeeper.GetNextSequenceSend(ctx, portID, channelID) } -// GetFeeAccount returns the ICS29 Fee ModuleAccount address +// GetFeeModuleAddress returns the ICS29 Fee ModuleAccount address func (k Keeper) GetFeeModuleAddress() sdk.AccAddress { return k.authKeeper.GetModuleAddress(types.ModuleName) } @@ -143,21 +143,6 @@ func (k Keeper) GetAllFeeEnabledChannels(ctx sdk.Context) []types.FeeEnabledChan return enabledChArr } -// DisableAllChannels will disable the fee module for all channels. -// Only called if the module enters into an invalid state -// e.g. ModuleAccount has insufficient balance to refund users. -// In this case, chain developers should investigate the issue, fix it, -// and then re-enable the fee module in a coordinated upgrade. -func (k Keeper) DisableAllChannels(ctx sdk.Context) { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte(types.FeeEnabledKeyPrefix)) - - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - store.Delete(iterator.Key()) - } -} - // SetCounterpartyAddress maps the destination chain relayer address to the source relayer address // The receiving chain must store the mapping from: address -> counterpartyAddress for the given channel func (k Keeper) SetCounterpartyAddress(ctx sdk.Context, address, counterpartyAddress, channelID string) { @@ -286,19 +271,27 @@ func (k Keeper) DeleteFeesInEscrow(ctx sdk.Context, packetID channeltypes.Packet store.Delete(key) } -// IteratePacketFeesInEscrow iterates over all the fees on the given channel currently escrowed and calls the provided callback -// if the callback returns true, then iteration is stopped. -func (k Keeper) IteratePacketFeesInEscrow(ctx sdk.Context, portID, channelID string, cb func(packetFees types.PacketFees) (stop bool)) { +// GetIdentifiedPacketFeesForChannel returns all the currently escrowed fees on a given channel. +func (k Keeper) GetIdentifiedPacketFeesForChannel(ctx sdk.Context, portID, channelID string) []types.IdentifiedPacketFees { + var identifiedPacketFees []types.IdentifiedPacketFees + store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, types.KeyFeesInEscrowChannelPrefix(portID, channelID)) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - packetFees := k.MustUnmarshalFees(iterator.Value()) - if cb(packetFees) { - break + packetID, err := types.ParseKeyFeesInEscrow(string(iterator.Key())) + if err != nil { + panic(err) } + + packetFees := k.MustUnmarshalFees(iterator.Value()) + + identifiedFee := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) + identifiedPacketFees = append(identifiedPacketFees, identifiedFee) } + + return identifiedPacketFees } // GetAllIdentifiedPacketFees returns a list of all IdentifiedPacketFees that are stored in state diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index 5c44e45c332..cf0d17ae494 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -76,11 +76,7 @@ func lockFeeModule(chain *ibctesting.TestChain) { } func (suite *KeeperTestSuite) TestEscrowAccountHasBalance() { - fee := types.Fee{ - AckFee: defaultAckFee, - RecvFee: defaultReceiveFee, - TimeoutFee: defaultTimeoutFee, - } + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.EscrowAccountHasBalance(suite.chainA.GetContext(), fee.Total())) @@ -127,19 +123,68 @@ func (suite *KeeperTestSuite) TestIsLocked() { suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(ctx)) } -func (suite *KeeperTestSuite) TestDisableAllChannels() { - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "port1", "channel1") - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "port2", "channel2") - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), "port3", "channel3") +func (suite *KeeperTestSuite) TestGetIdentifiedPacketFeesForChannel() { + suite.coordinator.Setup(suite.path) + + // escrow a fee + refundAcc := suite.chainA.SenderAccount.GetAddress() + packetID1 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + packetID2 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 2) + packetID5 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 51) + + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + + // escrow the packet fee + packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID1, types.NewPacketFees([]types.PacketFee{packetFee})) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID2, types.NewPacketFees([]types.PacketFee{packetFee})) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID5, types.NewPacketFees([]types.PacketFee{packetFee})) + + // set fees in escrow for packetIDs on different channel + diffChannel := "channel-1" + diffPacketID1 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, diffChannel, 1) + diffPacketID2 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, diffChannel, 2) + diffPacketID5 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, diffChannel, 5) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), diffPacketID1, types.NewPacketFees([]types.PacketFee{packetFee})) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), diffPacketID2, types.NewPacketFees([]types.PacketFee{packetFee})) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), diffPacketID5, types.NewPacketFees([]types.PacketFee{packetFee})) - suite.chainA.GetSimApp().IBCFeeKeeper.DisableAllChannels(suite.chainA.GetContext()) + expectedFees := []types.IdentifiedPacketFees{ + { + PacketId: packetID1, + PacketFees: []types.PacketFee{ + { + Fee: fee, + RefundAddress: refundAcc.String(), + Relayers: nil, + }, + }, + }, + { + PacketId: packetID2, + PacketFees: []types.PacketFee{ + { + Fee: fee, + RefundAddress: refundAcc.String(), + Relayers: nil, + }, + }, + }, + { + PacketId: packetID5, + PacketFees: []types.PacketFee{ + { + Fee: fee, + RefundAddress: refundAcc.String(), + Relayers: nil, + }, + }, + }, + } - suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "port1", "channel1"), - "fee is still enabled on channel-1 after DisableAllChannels call") - suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "port2", "channel2"), - "fee is still enabled on channel-2 after DisableAllChannels call") - suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), "port3", "channel3"), - "fee is still enabled on channel-3 after DisableAllChannels call") + identifiedFees := suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + suite.Require().Len(identifiedFees, len(expectedFees)) + suite.Require().Equal(identifiedFees, expectedFees) } func (suite *KeeperTestSuite) TestGetAllIdentifiedPacketFees() { @@ -148,11 +193,7 @@ func (suite *KeeperTestSuite) TestGetAllIdentifiedPacketFees() { // escrow a fee refundAcc := suite.chainA.SenderAccount.GetAddress() packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) - fee := types.Fee{ - AckFee: defaultAckFee, - RecvFee: defaultReceiveFee, - TimeoutFee: defaultTimeoutFee, - } + fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) // escrow the packet fee packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index a07d841d07c..9d7557fd6c4 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -23,9 +23,9 @@ func (suite *FeeTestSuite) TestFeeTransfer() { // set up coin & ics20 packet coin := ibctesting.TestCoin fee := types.Fee{ - RecvFee: validCoins, - AckFee: validCoins2, - TimeoutFee: validCoins3, + RecvFee: defaultRecvFee, + AckFee: defaultAckFee, + TimeoutFee: defaultTimeoutFee, } msgs := []sdk.Msg{ From f636ee3972f43a28d116f1df3e46f9db2550e15c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 13 Apr 2022 21:35:38 +0200 Subject: [PATCH 077/275] deprecate GetTransferAccount (#1250) * deprecate GetTransferAccount * add changelog entry * remove unused imports --- CHANGELOG.md | 6 ++++-- modules/apps/transfer/keeper/genesis.go | 6 ------ modules/apps/transfer/keeper/keeper.go | 6 ------ modules/apps/transfer/keeper/keeper_test.go | 12 ------------ 4 files changed, 4 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88886e3254e..4d718ea85ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,20 +40,22 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. + ### State Machine Breaking ### Improvements + * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. * (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. ### Features -* (modules/apps/29-fee) [\#1230](https://github.com/cosmos/ibc-go/pull/1230) Adding CLI command for getting incentivized packets for a specific channel-id. - * [\#276](https://github.com/cosmos/ibc-go/pull/276) Adding the Fee Middleware module v1 * (apps/29-fee) [\#1229](https://github.com/cosmos/ibc-go/pull/1229) Adding CLI commands for getting all unrelayed incentivized packets and packet by packet-id. * (apps/29-fee) [\#1224](https://github.com/cosmos/ibc-go/pull/1224) Adding Query/CounterpartyAddress and CLI to ICS29 fee middleware * (apps/29-fee) [\#1225](https://github.com/cosmos/ibc-go/pull/1225) Adding Query/FeeEnabledChannel and Query/FeeEnabledChannels with CLIs to ICS29 fee middleware. +* (modules/apps/29-fee) [\#1230](https://github.com/cosmos/ibc-go/pull/1230) Adding CLI command for getting incentivized packets for a specific channel-id. ### Bug Fixes diff --git a/modules/apps/transfer/keeper/genesis.go b/modules/apps/transfer/keeper/genesis.go index 35bbd231a59..d4020508cc9 100644 --- a/modules/apps/transfer/keeper/genesis.go +++ b/modules/apps/transfer/keeper/genesis.go @@ -28,12 +28,6 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { } k.SetParams(ctx, state.Params) - - // check if the module account exists - moduleAcc := k.GetTransferAccount(ctx) - if moduleAcc == nil { - panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) - } } // ExportGenesis exports ibc-transfer module's portID and denom trace info into its genesis state. diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 46e3c51aa2a..d3f32d95df7 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -4,7 +4,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" 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" @@ -64,11 +63,6 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+host.ModuleName+"-"+types.ModuleName) } -// GetTransferAccount returns the ICS20 - transfers ModuleAccount -func (k Keeper) GetTransferAccount(ctx sdk.Context) authtypes.ModuleAccountI { - return k.authKeeper.GetModuleAccount(ctx, types.ModuleName) -} - // IsBound checks if the transfer module is already bound to the desired port func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) diff --git a/modules/apps/transfer/keeper/keeper_test.go b/modules/apps/transfer/keeper/keeper_test.go index 1e29626c987..40ceb6d782f 100644 --- a/modules/apps/transfer/keeper/keeper_test.go +++ b/modules/apps/transfer/keeper/keeper_test.go @@ -4,9 +4,7 @@ import ( "testing" "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - "github.com/tendermint/tendermint/crypto" "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" @@ -46,16 +44,6 @@ func NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { return path } -func (suite *KeeperTestSuite) TestGetTransferAccount() { - expectedMaccAddr := sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName))) - - macc := suite.chainA.GetSimApp().TransferKeeper.GetTransferAccount(suite.chainA.GetContext()) - - suite.Require().NotNil(macc) - suite.Require().Equal(types.ModuleName, macc.GetName()) - suite.Require().Equal(expectedMaccAddr, macc.GetAddress()) -} - func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } From 31d577648124e4b9242b202f6c4521231cbb7b7c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 14 Apr 2022 09:44:43 +0200 Subject: [PATCH 078/275] docs: replace links in apps with correct ones (#1255) ## Description I noticed that 2 links at the bottom of the applications docs page were not correct. closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- docs/ibc/apps.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ibc/apps.md b/docs/ibc/apps.md index bb2716fa0b1..f729d7dfd71 100644 --- a/docs/ibc/apps.md +++ b/docs/ibc/apps.md @@ -464,13 +464,13 @@ which implements everything discussed above. Here are the useful parts of the module to look at: [Binding to transfer -port](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/types/genesis.go) +port](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/genesis.go) [Sending transfer packets](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/relay.go) [Implementing IBC -callbacks](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/module.go) +callbacks](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/ibc_module.go) ## Next {hide} From 4872c4b4a4fba3336664ea5f1206b9857f5ffd4f Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 14 Apr 2022 09:53:10 +0200 Subject: [PATCH 079/275] update godoc of `RegisterInterchainAccount` (#1256) ## Description The godoc of `RegisterInterchainAccount` was still saying that the port identifier was constructed using as well the connection identifiers. I corrected that. closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- .../27-interchain-accounts/controller/keeper/account.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account.go b/modules/apps/27-interchain-accounts/controller/keeper/account.go index dd87348876e..03eeef69f1f 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account.go @@ -10,11 +10,10 @@ import ( ) // RegisterInterchainAccount is the entry point to registering an interchain account. -// It generates a new port identifier using the owner address, connection identifier, -// and counterparty connection identifier. It will bind to the port identifier and -// call 04-channel 'ChanOpenInit'. An error is returned if the port identifier is -// already in use. Gaining access to interchain accounts whose channels have closed -// cannot be done with this function. A regular MsgChanOpenInit must be used. +// It generates a new port identifier using the owner address. It will bind to the +// port identifier and call 04-channel 'ChanOpenInit'. An error is returned if the port +// identifier is already in use. Gaining access to interchain accounts whose channels +// have closed cannot be done with this function. A regular MsgChanOpenInit must be used. func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner string) error { portID, err := icatypes.NewControllerPortID(owner) if err != nil { From eaff98bbb6c007a8670f7e276d73118563fe3c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 14 Apr 2022 12:14:29 +0200 Subject: [PATCH 080/275] isolate packet fee distribution for on acknowledgement and on timeout into separate functions (#1253) ## Description Reduces the complexity contained in `DistributePacketFees` and `DistributePacketFeesOnAcknowledgement` in anticipation of #1251 closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- modules/apps/29-fee/keeper/escrow.go | 56 +++++++++++++++++----------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 8f201293860..053bb9d668e 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -49,7 +49,7 @@ func (k Keeper) EscrowPacketFee(ctx sdk.Context, packetID channeltypes.PacketId, return nil } -// DistributePacketFees pays the acknowledgement fee & receive fee for a given packetID while refunding the timeout fee to the refund account associated with the Fee. +// DistributePacketFees pays all the acknowledgement & receive fees for a given packetID while refunding the timeout fees to the refund account. func (k Keeper) DistributePacketFees(ctx sdk.Context, forwardRelayer string, reverseRelayer sdk.AccAddress, feesInEscrow []types.PacketFee) { forwardAddr, _ := sdk.AccAddressFromBech32(forwardRelayer) @@ -59,24 +59,31 @@ func (k Keeper) DistributePacketFees(ctx sdk.Context, forwardRelayer string, rev panic(fmt.Sprintf("could not parse refundAcc %s to sdk.AccAddress", packetFee.RefundAddress)) } - // distribute fee to valid forward relayer address otherwise refund the fee - if !forwardAddr.Empty() && !k.bankKeeper.BlockedAddr(forwardAddr) { - // distribute fee for forward relaying - k.distributeFee(ctx, forwardAddr, refundAddr, packetFee.Fee.RecvFee) - } else { - // refund onRecv fee as forward relayer is not valid address - k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.RecvFee) - } - - // distribute fee for reverse relaying - k.distributeFee(ctx, reverseRelayer, refundAddr, packetFee.Fee.AckFee) + k.distributePacketFeeOnAcknowledgement(ctx, refundAddr, forwardAddr, reverseRelayer, packetFee) + } +} - // refund timeout fee for unused timeout - k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.TimeoutFee) +// distributePacketFeeOnAcknowledgement pays the receive fee for a given packetID while refunding the timeout fee to the refund account associated with the Fee. +// If there was no forward relayer or the associated forward relayer address is blocked, the receive fee is refunded. +func (k Keeper) distributePacketFeeOnAcknowledgement(ctx sdk.Context, refundAddr, forwardRelayer, reverseRelayer sdk.AccAddress, packetFee types.PacketFee) { + // distribute fee to valid forward relayer address otherwise refund the fee + if !forwardRelayer.Empty() && !k.bankKeeper.BlockedAddr(forwardRelayer) { + // distribute fee for forward relaying + k.distributeFee(ctx, forwardRelayer, refundAddr, packetFee.Fee.RecvFee) + } else { + // refund onRecv fee as forward relayer is not valid address + k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.RecvFee) } + + // distribute fee for reverse relaying + k.distributeFee(ctx, reverseRelayer, refundAddr, packetFee.Fee.AckFee) + + // refund timeout fee for unused timeout + k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.TimeoutFee) + } -// DistributePacketsFeesTimeout pays the timeout fee for a given packetID while refunding the acknowledgement fee & receive fee to the refund account associated with the Fee +// DistributePacketsFeesOnTimeout pays all the timeout fees for a given packetID while refunding the acknowledgement & receive fees to the refund account. func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sdk.AccAddress, feesInEscrow []types.PacketFee) { for _, feeInEscrow := range feesInEscrow { // check if refundAcc address works @@ -85,15 +92,20 @@ func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sd panic(fmt.Sprintf("could not parse refundAcc %s to sdk.AccAddress", feeInEscrow.RefundAddress)) } - // refund receive fee for unused forward relaying - k.distributeFee(ctx, refundAddr, refundAddr, feeInEscrow.Fee.RecvFee) + k.distributePacketFeeOnTimeout(ctx, refundAddr, timeoutRelayer, feeInEscrow) + } +} - // refund ack fee for unused reverse relaying - k.distributeFee(ctx, refundAddr, refundAddr, feeInEscrow.Fee.AckFee) +// distributePacketFeeOnTimeout pays the timeout fee to the timeout relayer and refunds the acknowledgement & receive fee. +func (k Keeper) distributePacketFeeOnTimeout(ctx sdk.Context, refundAddr, timeoutRelayer sdk.AccAddress, packetFee types.PacketFee) { + // refund receive fee for unused forward relaying + k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.RecvFee) - // distribute fee for timeout relaying - k.distributeFee(ctx, timeoutRelayer, refundAddr, feeInEscrow.Fee.TimeoutFee) - } + // refund ack fee for unused reverse relaying + k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.AckFee) + + // distribute fee for timeout relaying + k.distributeFee(ctx, timeoutRelayer, refundAddr, packetFee.Fee.TimeoutFee) } // distributeFee will attempt to distribute the escrowed fee to the receiver address. From 2120d2e961c1f84a4cffafd8aef51d6c416ac2bd Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 14 Apr 2022 13:43:40 +0200 Subject: [PATCH 081/275] Update supported release lines (#1263) ## Description closes: #1152 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- RELEASES.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 839e8e06612..c92cc13aed0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -65,9 +65,11 @@ Only the following major release series have a stable release status: |Release|End of Life Date| |-------|-------| -|`v1.1.x`|July 01, 2022| -|`v1.2.x`|July 01, 2022| -|`v2.0.x`|February 01, 2023| +|`v1.3.x`|July 01, 2022| +|`v1.4.x`|July 01, 2022| +|`v2.1.x`|February 01, 2023| +|`v2.2.x`|February 01, 2023| +|`v3.0.x`|March 15, 2023| **Note**: The v1 major release series will reach end of life 6 months after merging this policy. v2 will reach end of life one year after merging this policy. From 63c5341410389faa6767d7645941d7cbccef605b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 14 Apr 2022 14:21:25 +0200 Subject: [PATCH 082/275] ics29: gracefully handle escrow out of balance edge case during fee distribution (#1251) ## Description closes: #821 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [x] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [x] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [x] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [x] Review `Codecov Report` in the comment section below once CI passes --- modules/apps/29-fee/ibc_module.go | 2 +- modules/apps/29-fee/keeper/escrow.go | 63 ++++++- modules/apps/29-fee/keeper/escrow_test.go | 169 +++++++++++++----- modules/apps/29-fee/keeper/genesis_test.go | 4 +- modules/apps/29-fee/keeper/grpc_query_test.go | 12 +- modules/apps/29-fee/keeper/keeper_test.go | 10 +- modules/apps/29-fee/keeper/msg_server_test.go | 4 +- 7 files changed, 195 insertions(+), 69 deletions(-) diff --git a/modules/apps/29-fee/ibc_module.go b/modules/apps/29-fee/ibc_module.go index c542c5999e6..e89b95cb4de 100644 --- a/modules/apps/29-fee/ibc_module.go +++ b/modules/apps/29-fee/ibc_module.go @@ -229,7 +229,7 @@ func (im IBCModule) OnAcknowledgementPacket( packetID := channeltypes.NewPacketId(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) if found { - im.keeper.DistributePacketFees(ctx, ack.ForwardRelayerAddress, relayer, feesInEscrow.PacketFees) + im.keeper.DistributePacketFeesOnAcknowledgement(ctx, ack.ForwardRelayerAddress, relayer, feesInEscrow.PacketFees) // removes the fees from the store as fees are now paid im.keeper.DeleteFeesInEscrow(ctx, packetID) diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 053bb9d668e..e2b29a439cc 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -49,18 +49,41 @@ func (k Keeper) EscrowPacketFee(ctx sdk.Context, packetID channeltypes.PacketId, return nil } -// DistributePacketFees pays all the acknowledgement & receive fees for a given packetID while refunding the timeout fees to the refund account. -func (k Keeper) DistributePacketFees(ctx sdk.Context, forwardRelayer string, reverseRelayer sdk.AccAddress, feesInEscrow []types.PacketFee) { +// DistributePacketFeesOnAcknowledgement pays all the acknowledgement & receive fees for a given packetID while refunding the timeout fees to the refund account. +func (k Keeper) DistributePacketFeesOnAcknowledgement(ctx sdk.Context, forwardRelayer string, reverseRelayer sdk.AccAddress, packetFees []types.PacketFee) { + // cache context before trying to distribute fees + // if the escrow account has insufficient balance then we want to avoid partially distributing fees + cacheCtx, writeFn := ctx.CacheContext() + forwardAddr, _ := sdk.AccAddressFromBech32(forwardRelayer) - for _, packetFee := range feesInEscrow { + for _, packetFee := range packetFees { + if !k.EscrowAccountHasBalance(cacheCtx, packetFee.Fee.Total()) { + // if the escrow account does not have sufficient funds then there must exist a severe bug + // the fee module should be locked until manual intervention fixes the issue + // a locked fee module will simply skip fee logic, all channels will temporarily function as + // fee disabled channels + // NOTE: we use the uncached context to lock the fee module so that the state changes from + // locking the fee module are persisted + k.lockFeeModule(ctx) + + return + } + + // check if refundAcc address works refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) if err != nil { panic(fmt.Sprintf("could not parse refundAcc %s to sdk.AccAddress", packetFee.RefundAddress)) } - k.distributePacketFeeOnAcknowledgement(ctx, refundAddr, forwardAddr, reverseRelayer, packetFee) + k.distributePacketFeeOnAcknowledgement(cacheCtx, refundAddr, forwardAddr, reverseRelayer, packetFee) } + + // write the cache + writeFn() + + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) } // distributePacketFeeOnAcknowledgement pays the receive fee for a given packetID while refunding the timeout fee to the refund account associated with the Fee. @@ -84,16 +107,38 @@ func (k Keeper) distributePacketFeeOnAcknowledgement(ctx sdk.Context, refundAddr } // DistributePacketsFeesOnTimeout pays all the timeout fees for a given packetID while refunding the acknowledgement & receive fees to the refund account. -func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sdk.AccAddress, feesInEscrow []types.PacketFee) { - for _, feeInEscrow := range feesInEscrow { +func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sdk.AccAddress, packetFees []types.PacketFee) { + // cache context before trying to distribute fees + // if the escrow account has insufficient balance then we want to avoid partially distributing fees + cacheCtx, writeFn := ctx.CacheContext() + + for _, packetFee := range packetFees { + if !k.EscrowAccountHasBalance(cacheCtx, packetFee.Fee.Total()) { + // if the escrow account does not have sufficient funds then there must exist a severe bug + // the fee module should be locked until manual intervention fixes the issue + // a locked fee module will simply skip fee logic, all channels will temporarily function as + // fee disabled channels + // NOTE: we use the uncached context to lock the fee module so that the state changes from + // locking the fee module are persisted + k.lockFeeModule(ctx) + + return + } + // check if refundAcc address works - refundAddr, err := sdk.AccAddressFromBech32(feeInEscrow.RefundAddress) + refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) if err != nil { - panic(fmt.Sprintf("could not parse refundAcc %s to sdk.AccAddress", feeInEscrow.RefundAddress)) + panic(fmt.Sprintf("could not parse refundAcc %s to sdk.AccAddress", packetFee.RefundAddress)) } - k.distributePacketFeeOnTimeout(ctx, refundAddr, timeoutRelayer, feeInEscrow) + k.distributePacketFeeOnTimeout(cacheCtx, refundAddr, timeoutRelayer, packetFee) } + + // write the cache + writeFn() + + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) } // distributePacketFeeOnTimeout pays the timeout fee to the timeout relayer and refunds the acknowledgement & receive fee. diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 85747ae7acf..ea915beedf6 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -78,7 +78,7 @@ func (suite *KeeperTestSuite) TestEscrowPacketFee() { // setup refundAcc = suite.chainA.SenderAccount.GetAddress() - receiveFee = defaultReceiveFee + receiveFee = defaultRecvFee ackFee = defaultAckFee timeoutFee = defaultTimeoutFee packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) @@ -119,7 +119,7 @@ func (suite *KeeperTestSuite) TestEscrowPacketFee() { } } -func (suite *KeeperTestSuite) TestDistributeFee() { +func (suite *KeeperTestSuite) TestDistributePacketFeesOnAcknowledgement() { var ( forwardRelayer string forwardRelayerBal sdk.Coin @@ -128,6 +128,7 @@ func (suite *KeeperTestSuite) TestDistributeFee() { refundAcc sdk.AccAddress refundAccBal sdk.Coin packetFee types.PacketFee + packetFees []types.PacketFee ) testCases := []struct { @@ -148,7 +149,7 @@ func (suite *KeeperTestSuite) TestDistributeFee() { forward, err := sdk.AccAddressFromBech32(forwardRelayer) suite.Require().NoError(err) - expectedForwardAccBal := forwardRelayerBal.Add(defaultReceiveFee[0]).Add(defaultReceiveFee[0]) + expectedForwardAccBal := forwardRelayerBal.Add(defaultRecvFee[0]).Add(defaultRecvFee[0]) balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), forward, sdk.DefaultBondDenom) suite.Require().Equal(expectedForwardAccBal, balance) @@ -162,6 +163,20 @@ func (suite *KeeperTestSuite) TestDistributeFee() { suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(0)), balance) }, }, + { + "escrow account out of balance, fee module becomes locked - no distribution", func() { + // pass in an extra packet fee + packetFees = append(packetFees, packetFee) + }, + func() { + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + + // check if the module acc contains all the fees + expectedModuleAccBal := packetFee.Fee.Total().Add(packetFee.Fee.Total()...) + balance := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress()) + suite.Require().Equal(expectedModuleAccBal, balance) + }, + }, { "invalid forward address", func() { @@ -169,7 +184,7 @@ func (suite *KeeperTestSuite) TestDistributeFee() { }, func() { // check if the refund acc has been refunded the timeoutFee & recvFee - expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultReceiveFee[0]).Add(defaultTimeoutFee[0]).Add(defaultReceiveFee[0]) + expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0]).Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0]) balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.Require().Equal(expectedRefundAccBal, balance) }, @@ -181,7 +196,7 @@ func (suite *KeeperTestSuite) TestDistributeFee() { }, func() { // check if the refund acc has been refunded the timeoutFee & recvFee - expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultReceiveFee[0]).Add(defaultTimeoutFee[0]).Add(defaultReceiveFee[0]) + expectedRefundAccBal := refundAccBal.Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0]).Add(defaultTimeoutFee[0]).Add(defaultRecvFee[0]) balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) suite.Require().Equal(expectedRefundAccBal, balance) }, @@ -201,7 +216,8 @@ func (suite *KeeperTestSuite) TestDistributeFee() { { "invalid refund address: no-op, timeout fee remains in escrow", func() { - packetFee.RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() + packetFees[0].RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() + packetFees[1].RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() }, func() { // check if the module acc contains the timeoutFee @@ -225,10 +241,11 @@ func (suite *KeeperTestSuite) TestDistributeFee() { refundAcc = suite.chainA.SenderAccount.GetAddress() packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) // escrow the packet fee & store the fee in state packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) suite.Require().NoError(err) @@ -244,59 +261,123 @@ func (suite *KeeperTestSuite) TestDistributeFee() { reverseRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), reverseRelayer, sdk.DefaultBondDenom) refundAccBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) - suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFees(suite.chainA.GetContext(), forwardRelayer, reverseRelayer, []types.PacketFee{packetFee, packetFee}) + suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnAcknowledgement(suite.chainA.GetContext(), forwardRelayer, reverseRelayer, packetFees) tc.expResult() }) } } -func (suite *KeeperTestSuite) TestDistributeTimeoutFee() { - suite.coordinator.Setup(suite.path) // setup channel +func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { + var ( + timeoutRelayer sdk.AccAddress + timeoutRelayerBal sdk.Coin + refundAcc sdk.AccAddress + refundAccBal sdk.Coin + packetFee types.PacketFee + packetFees []types.PacketFee + ) - // setup - refundAcc := suite.chainA.SenderAccount.GetAddress() - timeoutRelayer := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + testCases := []struct { + name string + malleate func() + expResult func() + }{ + { + "success", + func() {}, + func() { + // check if the timeout relayer is paid + expectedTimeoutAccBal := timeoutRelayerBal.Add(defaultTimeoutFee[0]).Add(defaultTimeoutFee[0]) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), timeoutRelayer, sdk.DefaultBondDenom) + suite.Require().Equal(expectedTimeoutAccBal, balance) - packetID := channeltypes.NewPacketId( - suite.path.EndpointA.ChannelConfig.PortID, - suite.path.EndpointA.ChannelID, - 1, - ) + // check if the refund acc has been refunded the recv/ack fees + expectedRefundAccBal := refundAccBal.Add(defaultAckFee[0]).Add(defaultAckFee[0]).Add(defaultRecvFee[0]).Add(defaultRecvFee[0]) + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(expectedRefundAccBal, balance) - fee := types.Fee{ - RecvFee: defaultReceiveFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, + // check the module acc wallet is now empty + balance = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(0)), balance) + }, + }, + { + "escrow account out of balance, fee module becomes locked - no distribution", func() { + // pass in an extra packet fee + packetFees = append(packetFees, packetFee) + }, + func() { + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + + // check if the module acc contains all the fees + expectedModuleAccBal := packetFee.Fee.Total().Add(packetFee.Fee.Total()...) + balance := suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress()) + suite.Require().Equal(expectedModuleAccBal, balance) + }, + }, + { + "invalid timeout relayer address: timeout fee returned to sender", + func() { + timeoutRelayer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() + }, + func() { + // check if the refund acc has been refunded the all the fees + expectedRefundAccBal := sdk.Coins{refundAccBal}.Add(packetFee.Fee.Total()...).Add(packetFee.Fee.Total()...)[0] + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(expectedRefundAccBal, balance) + }, + }, + { + "invalid refund address: no-op, recv and ack fees remain in escrow", + func() { + packetFees[0].RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() + packetFees[1].RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() + }, + func() { + // check if the module acc contains the timeoutFee + expectedModuleAccBal := sdk.NewCoin(sdk.DefaultBondDenom, defaultRecvFee.Add(defaultRecvFee[0]).Add(defaultAckFee[0]).Add(defaultAckFee[0]).AmountOf(sdk.DefaultBondDenom)) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(expectedModuleAccBal, balance) + }, + }, } - // escrow the packet fee & store the fee in state - packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.SetupTest() // reset + suite.coordinator.Setup(suite.path) // setup channel + + // setup accounts + timeoutRelayer = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + refundAcc = suite.chainA.SenderAccount.GetAddress() - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - // escrow a second packet fee to test with multiple fees distributed - err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - // refundAcc balance after escrow - refundAccBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + // escrow the packet fee & store the fee in state + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) - suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnTimeout(suite.chainA.GetContext(), timeoutRelayer, []types.PacketFee{packetFee, packetFee}) + // escrow a second packet fee to test with multiple fees distributed + err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.Require().NoError(err) - // check if the timeoutRelayer has been paid - hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), timeoutRelayer, fee.TimeoutFee[0]) - suite.Require().True(hasBalance) + tc.malleate() - // check if the refund acc has been refunded the recv & ack fees - expectedRefundAccBal := refundAccBal.Add(fee.AckFee[0]).Add(fee.AckFee[0]) - expectedRefundAccBal = refundAccBal.Add(fee.RecvFee[0]).Add(fee.RecvFee[0]) - hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, expectedRefundAccBal) - suite.Require().True(hasBalance) + // fetch the account balances before fee distribution (forward, reverse, refund) + timeoutRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), timeoutRelayer, sdk.DefaultBondDenom) + refundAccBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) - // check the module acc wallet is now empty - hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(0)}) - suite.Require().True(hasBalance) + suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnTimeout(suite.chainA.GetContext(), timeoutRelayer, packetFees) + + tc.expResult() + }) + } } func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { @@ -446,7 +527,7 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { expRefundBal = suite.chainA.GetSimApp().BankKeeper.GetAllBalances(suite.chainA.GetContext(), refundAcc) fee = types.Fee{ - RecvFee: defaultReceiveFee, + RecvFee: defaultRecvFee, AckFee: defaultAckFee, TimeoutFee: defaultTimeoutFee, } diff --git a/modules/apps/29-fee/keeper/genesis_test.go b/modules/apps/29-fee/keeper/genesis_test.go index ec9602d3a4f..8aa30385e58 100644 --- a/modules/apps/29-fee/keeper/genesis_test.go +++ b/modules/apps/29-fee/keeper/genesis_test.go @@ -11,7 +11,7 @@ func (suite *KeeperTestSuite) TestInitGenesis() { refundAcc := suite.chainA.SenderAccount.GetAddress() packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.Fee{ - RecvFee: defaultReceiveFee, + RecvFee: defaultRecvFee, AckFee: defaultAckFee, TimeoutFee: defaultTimeoutFee, } @@ -73,7 +73,7 @@ func (suite *KeeperTestSuite) TestExportGenesis() { refundAcc := suite.chainA.SenderAccount.GetAddress() packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) fee := types.Fee{ - RecvFee: defaultReceiveFee, + RecvFee: defaultRecvFee, AckFee: defaultAckFee, TimeoutFee: defaultTimeoutFee, } diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index 446616ab176..43935490f2a 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -28,7 +28,7 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPackets() { func() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) for i := 0; i < 3; i++ { @@ -113,7 +113,7 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPacket() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) for i := 0; i < 3; i++ { @@ -269,7 +269,7 @@ func (suite *KeeperTestSuite) TestQueryTotalRecvFees() { packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) for i := 0; i < 3; i++ { @@ -292,7 +292,7 @@ func (suite *KeeperTestSuite) TestQueryTotalRecvFees() { suite.Require().NotNil(res) // expected total is three times the default recv fee - expectedFees := defaultReceiveFee.Add(defaultReceiveFee...).Add(defaultReceiveFee...) + expectedFees := defaultRecvFee.Add(defaultRecvFee...).Add(defaultRecvFee...) suite.Require().Equal(expectedFees, res.RecvFees) } else { suite.Require().Error(err) @@ -333,7 +333,7 @@ func (suite *KeeperTestSuite) TestQueryTotalAckFees() { packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) for i := 0; i < 3; i++ { @@ -397,7 +397,7 @@ func (suite *KeeperTestSuite) TestQueryTotalTimeoutFees() { packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) for i := 0; i < 3; i++ { diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index cf0d17ae494..c4be4553c5a 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -15,7 +15,7 @@ import ( ) var ( - defaultReceiveFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}} + defaultRecvFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}} defaultAckFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}} defaultTimeoutFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(300)}} invalidCoins = sdk.Coins{sdk.Coin{Denom: "invalidDenom", Amount: sdk.NewInt(100)}} @@ -76,7 +76,7 @@ func lockFeeModule(chain *ibctesting.TestChain) { } func (suite *KeeperTestSuite) TestEscrowAccountHasBalance() { - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.EscrowAccountHasBalance(suite.chainA.GetContext(), fee.Total())) @@ -96,7 +96,7 @@ func (suite *KeeperTestSuite) TestFeesInEscrow() { // escrow five fees for packet sequence 1 packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) for i := 1; i < 6; i++ { packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), nil) @@ -132,7 +132,7 @@ func (suite *KeeperTestSuite) TestGetIdentifiedPacketFeesForChannel() { packetID2 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 2) packetID5 := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 51) - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) // escrow the packet fee packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) @@ -193,7 +193,7 @@ func (suite *KeeperTestSuite) TestGetAllIdentifiedPacketFees() { // escrow a fee refundAcc := suite.chainA.SenderAccount.GetAddress() packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) - fee := types.NewFee(defaultReceiveFee, defaultAckFee, defaultTimeoutFee) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) // escrow the packet fee packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 74c5342d674..2954ebcebaf 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -80,7 +80,7 @@ func (suite *KeeperTestSuite) TestPayPacketFee() { refundAcc := suite.chainA.SenderAccount.GetAddress() channelID := suite.path.EndpointA.ChannelID fee := types.Fee{ - RecvFee: defaultReceiveFee, + RecvFee: defaultRecvFee, AckFee: defaultAckFee, TimeoutFee: defaultTimeoutFee, } @@ -129,7 +129,7 @@ func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { // build packetID channelID := suite.path.EndpointA.ChannelID fee := types.Fee{ - RecvFee: defaultReceiveFee, + RecvFee: defaultRecvFee, AckFee: defaultAckFee, TimeoutFee: defaultTimeoutFee, } From 2ab4359a469918e81760421c12f516c3c642290f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Apr 2022 13:19:25 +0000 Subject: [PATCH 083/275] build(deps): bump github.com/spf13/viper from 1.10.1 to 1.11.0 (#1264) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.10.1 to 1.11.0. - [Release notes](https://github.com/spf13/viper/releases) - [Commits](https://github.com/spf13/viper/compare/v1.10.1...v1.11.0) --- updated-dependencies: - dependency-name: github.com/spf13/viper dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 19 ++++++------- go.sum | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 84 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index ab0e814bead..4f56c03dd9e 100644 --- a/go.mod +++ b/go.mod @@ -16,11 +16,11 @@ require ( github.com/regen-network/cosmos-proto v0.3.1 github.com/spf13/cast v1.4.1 github.com/spf13/cobra v1.4.0 - github.com/spf13/viper v1.10.1 + github.com/spf13/viper v1.11.0 github.com/stretchr/testify v1.7.1 github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 - google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb + google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac google.golang.org/grpc v1.45.0 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 @@ -79,7 +79,7 @@ require ( github.com/klauspost/compress v1.13.6 // indirect github.com/lib/pq v1.10.4 // indirect github.com/libp2p/go-buffer-pool v0.0.2 // indirect - github.com/magiconair/properties v1.8.5 // indirect + github.com/magiconair/properties v1.8.6 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect @@ -88,6 +88,7 @@ require ( github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -99,7 +100,7 @@ require ( github.com/rs/cors v1.8.2 // indirect github.com/rs/zerolog v1.23.0 // indirect github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect - github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/afero v1.8.2 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.2.0 // indirect @@ -110,12 +111,12 @@ require ( github.com/tendermint/go-amino v0.16.0 // indirect github.com/zondax/hid v0.9.0 // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 // indirect - golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b // indirect - golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect - gopkg.in/ini.v1 v1.66.2 // indirect + gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/go.sum b/go.sum index 63461520875..a8f6d150085 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -16,6 +17,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= @@ -27,12 +29,16 @@ cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+Y cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= @@ -46,6 +52,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-beta.2 h1:/BZRNzm8N4K4eWfK28dL4yescorxtO7YG1yun8fy+pI= filippo.io/edwards25519 v1.0.0-beta.2/go.mod h1:X+pm78QAUPtFLi1z9PYIlS/bdDnvbCOGKtZ+ACWEf7o= @@ -428,8 +435,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= @@ -449,6 +457,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -462,6 +471,9 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -512,6 +524,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/S github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -544,6 +557,7 @@ github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87/go.mod h1:XGsKKeXxeRr95aEOgipvluMPlgjr7dGlk9ZTWOjcUcg= github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= @@ -628,8 +642,9 @@ github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc8 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -774,6 +789,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.0-beta.8 h1:dy81yyLYJDwMTifq24Oi/IslOslRrDSb3jwDggjz3Z0= +github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= @@ -789,6 +806,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -863,6 +881,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= +github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= @@ -888,8 +907,9 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -910,8 +930,9 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/spf13/viper v1.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44= +github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= @@ -994,10 +1015,13 @@ go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.etcd.io/etcd/client/v2 v2.305.2/go.mod h1:2D7ZejHVMIfog1221iLSYlQRzrtECw3kz4I4VAQm3qI= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1047,10 +1071,13 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 h1:3erb+vDS8lU1sxfDHF4/hhWyaXnhIaO+7RgL4fDZORA= golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1155,8 +1182,13 @@ golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b h1:MWaHNqZy3KTpuTMAGvv+Kw+ylsEpmyJZizz1dqxnu28= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1174,6 +1206,9 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1256,6 +1291,7 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1263,6 +1299,7 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1282,11 +1319,18 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1364,6 +1408,7 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -1373,8 +1418,9 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1412,6 +1458,10 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1460,8 +1510,10 @@ google.golang.org/genproto v0.0.0-20201119123407-9b1e624d6bc4/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1488,8 +1540,17 @@ google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb h1:ZrsicilzPCS/Xr8qtBZZLpy4P9TYXAfl49ctG1/5tgw= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac h1:qSNTkEN+L2mvWcLgJOR+8bdHX9rN/IdU3A1Ghpfb1Rg= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1525,6 +1586,7 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -1556,8 +1618,9 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= +gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= From acb0e9f51bf359203bd49cca7c043010ad9a2728 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 14 Apr 2022 16:46:12 +0200 Subject: [PATCH 084/275] chore(ics29): make EscrowPacketFee private (#1252) * making EsrowPacketFee private, adapting test cases to conform * refactor msg server tests to accomoodate escrowPacketFee * adding assertions on escrow account balance * adding error checks on bank sends in tests, omitting loop as per review * adding escrow balance checks to TestPayPacketFee * adding assertions on expected fees in state --- modules/apps/29-fee/ibc_module_test.go | 21 +- modules/apps/29-fee/keeper/escrow.go | 9 +- modules/apps/29-fee/keeper/escrow_test.go | 146 ++-------- modules/apps/29-fee/keeper/grpc_query_test.go | 30 +-- modules/apps/29-fee/keeper/keeper_test.go | 8 +- modules/apps/29-fee/keeper/msg_server.go | 22 +- modules/apps/29-fee/keeper/msg_server_test.go | 251 ++++++++++++++---- 7 files changed, 267 insertions(+), 220 deletions(-) diff --git a/modules/apps/29-fee/ibc_module_test.go b/modules/apps/29-fee/ibc_module_test.go index 1e5743f7490..cb6a89d13b7 100644 --- a/modules/apps/29-fee/ibc_module_test.go +++ b/modules/apps/29-fee/ibc_module_test.go @@ -321,7 +321,8 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + suite.Require().NoError(err) }, false, }, @@ -342,7 +343,9 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { refundAcc = suite.chainA.SenderAccount.GetAddress() packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) suite.Require().NoError(err) tc.malleate() @@ -395,7 +398,8 @@ func (suite *FeeTestSuite) TestOnChanCloseConfirm() { packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + suite.Require().NoError(err) }, false, }, @@ -417,7 +421,9 @@ func (suite *FeeTestSuite) TestOnChanCloseConfirm() { refundAcc = suite.chainA.SenderAccount.GetAddress() packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) suite.Require().NoError(err) tc.malleate() @@ -657,7 +663,9 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { suite.chainA.SenderAccount.GetAddress().String(), []string{}, ) - err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) + err = suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, packetFee.Fee.Total()) suite.Require().NoError(err) relayerAddr := suite.chainB.SenderAccount.GetAddress() @@ -789,7 +797,8 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { []string{}, ) - err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) + err = suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, packetFee.Fee.Total()) suite.Require().NoError(err) // log original sender balance diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index e2b29a439cc..0ca84684440 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -11,13 +11,8 @@ import ( channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ) -// EscrowPacketFee sends the packet fee to the 29-fee module account to hold in escrow -func (k Keeper) EscrowPacketFee(ctx sdk.Context, packetID channeltypes.PacketId, packetFee types.PacketFee) error { - if !k.IsFeeEnabled(ctx, packetID.PortId, packetID.ChannelId) { - // users may not escrow fees on this channel. Must send packets without a fee message - return sdkerrors.Wrap(types.ErrFeeNotEnabled, "cannot escrow fee for packet") - } - +// escrowPacketFee sends the packet fee to the 29-fee module account to hold in escrow +func (k Keeper) escrowPacketFee(ctx sdk.Context, packetID channeltypes.PacketId, packetFee types.PacketFee) error { // check if the refund address is valid refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) if err != nil { diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index ea915beedf6..e2a43afe586 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -9,117 +9,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ) -func (suite *KeeperTestSuite) TestEscrowPacketFee() { - var ( - err error - refundAcc sdk.AccAddress - ackFee sdk.Coins - receiveFee sdk.Coins - timeoutFee sdk.Coins - packetID channeltypes.PacketId - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", func() {}, true, - }, - { - "success with existing packet fee", func() { - fee := types.Fee{ - RecvFee: receiveFee, - AckFee: ackFee, - TimeoutFee: timeoutFee, - } - - packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) - feesInEscrow := types.NewPacketFees([]types.PacketFee{packetFee}) - - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, feesInEscrow) - }, true, - }, - { - "fee not enabled on this channel", func() { - packetID.ChannelId = "disabled_channel" - }, false, - }, - { - "refundAcc does not exist", func() { - // this acc does not exist on chainA - refundAcc = suite.chainB.SenderAccount.GetAddress() - }, false, - }, - { - "ackFee balance not found", func() { - ackFee = invalidCoins - }, false, - }, - { - "receive balance not found", func() { - receiveFee = invalidCoins - }, false, - }, - { - "timeout balance not found", func() { - timeoutFee = invalidCoins - }, false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() // reset - suite.coordinator.Setup(suite.path) // setup channel - - // setup - refundAcc = suite.chainA.SenderAccount.GetAddress() - receiveFee = defaultRecvFee - ackFee = defaultAckFee - timeoutFee = defaultTimeoutFee - packetID = channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) - - tc.malleate() - fee := types.Fee{ - RecvFee: receiveFee, - AckFee: ackFee, - TimeoutFee: timeoutFee, - } - packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) - - // refundAcc balance before escrow - originalBal := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) - - // escrow the packet fee - err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - - if tc.expPass { - feesInEscrow, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) - suite.Require().True(found) - // check if the escrowed fee is set in state - suite.Require().True(feesInEscrow.PacketFees[0].Fee.AckFee.IsEqual(fee.AckFee)) - suite.Require().True(feesInEscrow.PacketFees[0].Fee.RecvFee.IsEqual(fee.RecvFee)) - suite.Require().True(feesInEscrow.PacketFees[0].Fee.TimeoutFee.IsEqual(fee.TimeoutFee)) - // check if the fee is escrowed correctly - hasBalance := suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(600)}) - suite.Require().True(hasBalance) - expectedBal := originalBal.Amount.Sub(sdk.NewInt(600)) - // check if the refund acc has sent the fee - hasBalance = suite.chainA.GetSimApp().BankKeeper.HasBalance(suite.chainA.GetContext(), refundAcc, sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: expectedBal}) - suite.Require().True(hasBalance) - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *KeeperTestSuite) TestDistributePacketFeesOnAcknowledgement() { +func (suite *KeeperTestSuite) TestDistributeFee() { var ( forwardRelayer string forwardRelayerBal sdk.Coin @@ -243,14 +133,12 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnAcknowledgement() { packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - // escrow the packet fee & store the fee in state + // escrow the packet fees & store the fees in state packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) packetFees = []types.PacketFee{packetFee, packetFee} - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - // escrow a second packet fee to test with multiple fees distributed - err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, packetFee.Fee.Total().Add(packetFee.Fee.Total()...)) suite.Require().NoError(err) tc.malleate() @@ -357,14 +245,12 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - // escrow the packet fee & store the fee in state + // escrow the packet fees & store the fees in state packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) packetFees = []types.PacketFee{packetFee, packetFee} - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - // escrow a second packet fee to test with multiple fees distributed - err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, packetFee.Fee.Total().Add(packetFee.Fee.Total()...)) suite.Require().NoError(err) tc.malleate() @@ -405,7 +291,8 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + suite.Require().NoError(err) expIdentifiedPacketFees = append(expIdentifiedPacketFees, identifiedPacketFees) } @@ -421,7 +308,8 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + suite.Require().NoError(err) expIdentifiedPacketFees = append(expIdentifiedPacketFees, identifiedPacketFees) } @@ -432,7 +320,8 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, "channel-1") suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + suite.Require().NoError(err) expEscrowBal = fee.Total() expRefundBal = expRefundBal.Sub(fee.Total()) @@ -468,7 +357,8 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID2, packetFees) // update escrow account balance for 1 fee - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + suite.Require().NoError(err) expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFee1, identifiedPacketFee2} }, true, @@ -482,7 +372,8 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + suite.Require().NoError(err) expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} }, false, @@ -498,7 +389,8 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, packetFees) - suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) + suite.Require().NoError(err) expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index 43935490f2a..d665c655ccf 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -34,7 +34,7 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPackets() { for i := 0; i < 3; i++ { // escrow packet fees for three different packets packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, uint64(i+1)) - suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) expectedPackets = append(expectedPackets, types.NewIdentifiedPacketFees(packetID, []types.PacketFee{packetFee})) } @@ -116,11 +116,8 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPacket() { fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) - for i := 0; i < 3; i++ { - // escrow three packet fees for the same packet - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - } + packetFees := []types.PacketFee{packetFee, packetFee, packetFee} + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) req = &types.QueryIncentivizedPacketRequest{ PacketId: packetID, @@ -272,11 +269,8 @@ func (suite *KeeperTestSuite) TestQueryTotalRecvFees() { fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) - for i := 0; i < 3; i++ { - // escrow three packet fees for the same packet - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - } + packetFees := []types.PacketFee{packetFee, packetFee, packetFee} + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) req = &types.QueryTotalRecvFeesRequest{ PacketId: packetID, @@ -336,11 +330,8 @@ func (suite *KeeperTestSuite) TestQueryTotalAckFees() { fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) - for i := 0; i < 3; i++ { - // escrow three packet fees for the same packet - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - } + packetFees := []types.PacketFee{packetFee, packetFee, packetFee} + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) req = &types.QueryTotalAckFeesRequest{ PacketId: packetID, @@ -400,11 +391,8 @@ func (suite *KeeperTestSuite) TestQueryTotalTimeoutFees() { fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), []string(nil)) - for i := 0; i < 3; i++ { - // escrow three packet fees for the same packet - err := suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - suite.Require().NoError(err) - } + packetFees := []types.PacketFee{packetFee, packetFee, packetFee} + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) req = &types.QueryTotalTimeoutFeesRequest{ PacketId: packetID, diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index c4be4553c5a..7446ecbab64 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -98,10 +98,10 @@ func (suite *KeeperTestSuite) TestFeesInEscrow() { packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - for i := 1; i < 6; i++ { - packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), nil) - suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), packetID, packetFee) - } + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), nil) + packetFees := []types.PacketFee{packetFee, packetFee, packetFee, packetFee, packetFee} + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) // retrieve the fees in escrow and assert the length of PacketFees feesInEscrow, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index 40a7fb4df9c..69f6520c759 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -31,6 +31,11 @@ func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.Ms func (k Keeper) PayPacketFee(goCtx context.Context, msg *types.MsgPayPacketFee) (*types.MsgPayPacketFeeResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + if !k.IsFeeEnabled(ctx, msg.SourcePortId, msg.SourceChannelId) { + // users may not escrow fees on this channel. Must send packets without a fee message + return nil, types.ErrFeeNotEnabled + } + if k.IsLocked(ctx) { return nil, types.ErrFeeModuleLocked } @@ -41,14 +46,10 @@ func (k Keeper) PayPacketFee(goCtx context.Context, msg *types.MsgPayPacketFee) return nil, channeltypes.ErrSequenceSendNotFound } - packetID := channeltypes.NewPacketId( - msg.SourcePortId, - msg.SourceChannelId, - sequence, - ) - + packetID := channeltypes.NewPacketId(msg.SourcePortId, msg.SourceChannelId, sequence) packetFee := types.NewPacketFee(msg.Fee, msg.Signer, msg.Relayers) - if err := k.EscrowPacketFee(ctx, packetID, packetFee); err != nil { + + if err := k.escrowPacketFee(ctx, packetID, packetFee); err != nil { return nil, err } @@ -61,11 +62,16 @@ func (k Keeper) PayPacketFee(goCtx context.Context, msg *types.MsgPayPacketFee) func (k Keeper) PayPacketFeeAsync(goCtx context.Context, msg *types.MsgPayPacketFeeAsync) (*types.MsgPayPacketFeeAsyncResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + if !k.IsFeeEnabled(ctx, msg.PacketId.PortId, msg.PacketId.ChannelId) { + // users may not escrow fees on this channel. Must send packets without a fee message + return nil, types.ErrFeeNotEnabled + } + if k.IsLocked(ctx) { return nil, types.ErrFeeModuleLocked } - if err := k.EscrowPacketFee(ctx, msg.PacketId, msg.PacketFee); err != nil { + if err := k.escrowPacketFee(ctx, msg.PacketId, msg.PacketFee); err != nil { return nil, err } diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 2954ebcebaf..8a927559a51 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -54,100 +54,257 @@ func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() { } func (suite *KeeperTestSuite) TestPayPacketFee() { + var ( + expEscrowBalance sdk.Coins + expFeesInEscrow []types.PacketFee + msg *types.MsgPayPacketFee + ) + testCases := []struct { name string - expPass bool malleate func() + expPass bool }{ { "success", - true, func() {}, + true, + }, + { + "success with existing packet fees in escrow", + func() { + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), nil) + feesInEscrow := types.NewPacketFees([]types.PacketFee{packetFee}) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, feesInEscrow) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, fee.Total()) + suite.Require().NoError(err) + + expEscrowBalance = expEscrowBalance.Add(fee.Total()...) + expFeesInEscrow = append(expFeesInEscrow, packetFee) + }, + true, }, { "fee module is locked", - false, func() { lockFeeModule(suite.chainA) }, + false, + }, + { + "fee module disabled on channel", + func() { + msg.SourcePortId = "invalid-port" + msg.SourceChannelId = "invalid-channel" + }, + false, + }, + { + "invalid refund address", + func() { + msg.Signer = "invalid-address" + }, + false, + }, + { + "refund account does not exist", + func() { + msg.Signer = suite.chainB.SenderAccount.GetAddress().String() + }, + false, + }, + { + "acknowledgement fee balance not found", + func() { + msg.Fee.AckFee = invalidCoins + }, + false, + }, + { + "receive fee balance not found", + func() { + msg.Fee.RecvFee = invalidCoins + }, + false, + }, + { + "timeout fee balance not found", + func() { + msg.Fee.TimeoutFee = invalidCoins + }, + false, }, } for _, tc := range testCases { - suite.SetupTest() - suite.coordinator.Setup(suite.path) // setup channel - - refundAcc := suite.chainA.SenderAccount.GetAddress() - channelID := suite.path.EndpointA.ChannelID - fee := types.Fee{ - RecvFee: defaultRecvFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, - } - msg := types.NewMsgPayPacketFee(fee, suite.path.EndpointA.ChannelConfig.PortID, channelID, refundAcc.String(), []string{}) + tc := tc - tc.malleate() + suite.Run(tc.name, func() { + suite.SetupTest() + suite.coordinator.Setup(suite.path) // setup channel - _, err := suite.chainA.GetSimApp().IBCFeeKeeper.PayPacketFee(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + msg = types.NewMsgPayPacketFee( + fee, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.chainA.SenderAccount.GetAddress().String(), + nil, + ) - if tc.expPass { - suite.Require().NoError(err) // message committed - } else { - suite.Require().Error(err) - } + expEscrowBalance = fee.Total() + expPacketFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), nil) + expFeesInEscrow = []types.PacketFee{expPacketFee} + + tc.malleate() + + _, err := suite.chainA.GetSimApp().IBCFeeKeeper.PayPacketFee(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) + + if tc.expPass { + suite.Require().NoError(err) // message committed + + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + feesInEscrow, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().True(found) + suite.Require().Equal(expFeesInEscrow, feesInEscrow.PacketFees) + + escrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(expEscrowBalance.AmountOf(sdk.DefaultBondDenom), escrowBalance.Amount) + } else { + suite.Require().Error(err) + + escrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(sdk.NewInt(0), escrowBalance.Amount) + } + }) } } func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { + var ( + expEscrowBalance sdk.Coins + expFeesInEscrow []types.PacketFee + msg *types.MsgPayPacketFeeAsync + ) + testCases := []struct { name string - expPass bool malleate func() + expPass bool }{ { "success", - true, func() {}, + true, + }, + { + "success with existing packet fees in escrow", + func() { + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), nil) + feesInEscrow := types.NewPacketFees([]types.PacketFee{packetFee}) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, feesInEscrow) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, fee.Total()) + suite.Require().NoError(err) + + expEscrowBalance = expEscrowBalance.Add(fee.Total()...) + expFeesInEscrow = append(expFeesInEscrow, packetFee) + }, + true, }, { "fee module is locked", - false, func() { lockFeeModule(suite.chainA) }, + false, + }, + { + "fee module disabled on channel", + func() { + msg.PacketId.PortId = "invalid-port" + msg.PacketId.ChannelId = "invalid-channel" + }, + false, + }, + { + "invalid refund address", + func() { + msg.PacketFee.RefundAddress = "invalid-address" + }, + false, + }, + { + "refund account does not exist", + func() { + msg.PacketFee.RefundAddress = suite.chainB.SenderAccount.GetAddress().String() + }, + false, + }, + { + "acknowledgement fee balance not found", + func() { + msg.PacketFee.Fee.AckFee = invalidCoins + }, + false, + }, + { + "receive fee balance not found", + func() { + msg.PacketFee.Fee.RecvFee = invalidCoins + }, + false, + }, + { + "timeout fee balance not found", + func() { + msg.PacketFee.Fee.TimeoutFee = invalidCoins + }, + false, }, } for _, tc := range testCases { - suite.SetupTest() - suite.coordinator.Setup(suite.path) // setup channel + tc := tc - ctxA := suite.chainA.GetContext() + suite.Run(tc.name, func() { + suite.SetupTest() + suite.coordinator.Setup(suite.path) // setup channel - refundAcc := suite.chainA.SenderAccount.GetAddress() + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), nil) - // build packetID - channelID := suite.path.EndpointA.ChannelID - fee := types.Fee{ - RecvFee: defaultRecvFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, - } - seq, _ := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceSend(ctxA, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + expEscrowBalance = fee.Total() + expFeesInEscrow = []types.PacketFee{packetFee} + msg = types.NewMsgPayPacketFeeAsync(packetID, packetFee) - // build fee - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, channelID, seq) - packetFee := types.NewPacketFee(fee, refundAcc.String(), nil) + tc.malleate() - tc.malleate() + _, err := suite.chainA.GetSimApp().IBCFeeKeeper.PayPacketFeeAsync(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) - msg := types.NewMsgPayPacketFeeAsync(packetID, packetFee) - _, err := suite.chainA.GetSimApp().IBCFeeKeeper.PayPacketFeeAsync(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) + if tc.expPass { + suite.Require().NoError(err) // message committed - if tc.expPass { - suite.Require().NoError(err) // message committed - } else { - suite.Require().Error(err) - } + feesInEscrow, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().True(found) + suite.Require().Equal(expFeesInEscrow, feesInEscrow.PacketFees) + + escrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(expEscrowBalance.AmountOf(sdk.DefaultBondDenom), escrowBalance.Amount) + } else { + suite.Require().Error(err) + + escrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.GetSimApp().IBCFeeKeeper.GetFeeModuleAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(sdk.NewInt(0), escrowBalance.Amount) + } + }) } } From 23fccc53f16ada57191922b55b22c71e7bc40acf Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 19 Apr 2022 10:00:44 +0200 Subject: [PATCH 085/275] add missing changelog entry for bump of sdk 0.45.3 (#1272) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [x] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d718ea85ea..8da21edad21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies +* [\#1247](https://github.com/cosmos/ibc-go/pull/1247) Bump SDK version to v0.45.3 and Tendermint to version 0.34.19 + ### API Breaking * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. From 86638c29107d8a0ad0c70ad1676523edfeea254d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 20 Apr 2022 12:04:12 +0200 Subject: [PATCH 086/275] feat: Add GetAppVersion to ICS4Wrapper (#1022) * feat: Add ICS4Wrapper function GetChannelVersion Add a function to 04-channel keeper which can be used in the ICS4Wrapper interface for obtaining the unwrapped channel verison * add docs * chore: rename GetChannelVersion to GetUnwrappedChannelVersion * add changelog entry * Update CHANGELOG.md * Update docs/ibc/middleware/develop.md * Update docs/ibc/middleware/develop.md * chore: GetUnwrappedChannelVersion -> GetAppVersion * add GetAppVersion for ics29 * add GetAppVersion to ics27 * add extra test for 29-fee * update docs * Apply suggestions from code review Co-authored-by: Sean King Co-authored-by: Sean King Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- CHANGELOG.md | 1 + docs/ibc/middleware/develop.md | 21 +++++ .../controller/ibc_module.go | 5 ++ .../controller/ibc_module_test.go | 21 +++++ .../controller/keeper/keeper.go | 5 ++ .../types/expected_keepers.go | 1 + modules/apps/29-fee/ibc_module.go | 5 ++ modules/apps/29-fee/ibc_module_test.go | 76 +++++++++++++++++++ modules/apps/29-fee/keeper/relay.go | 21 +++++ modules/apps/29-fee/keeper/relay_test.go | 69 +++++++++++++++++ modules/apps/29-fee/types/expected_keepers.go | 1 + modules/core/04-channel/keeper/keeper.go | 10 +++ modules/core/04-channel/keeper/keeper_test.go | 19 +++++ modules/core/05-port/types/module.go | 6 ++ testing/endpoint.go | 9 ++- 15 files changed, 269 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8da21edad21..a72dc61c05a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (middleware) [\#1022](https://github.com/cosmos/ibc-go/pull/1022) Add `GetAppVersion` to the ICS4Wrapper interface. This function should be used by IBC applications to obtain their own version since the version set in the channel structure may be wrapped many times by middleware. * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. * (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index 1d75e3965a8..705040b1db7 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -49,6 +49,7 @@ type Middleware interface { 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 + GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) } ``` @@ -239,4 +240,24 @@ func SendPacket(appPacket channeltypes.Packet) { return ics4Keeper.SendPacket(packet) } + +// middleware must return the underlying application version +func GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + version, found := ics4Keeper.GetAppVersion(ctx, portID, channelID) + if !found { + return "", false + } + + if !MiddlewareEnabled { + return version, true + } + + // unwrap channel version + metadata, err := Unmarshal(version) + if err != nil { + panic(fmt.Errof("unable to unmarshal version: %w", err)) + } + + return metadata.AppVersion, true +} ``` diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module.go b/modules/apps/27-interchain-accounts/controller/ibc_module.go index c00c9f5d1c2..325ec70959b 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module.go @@ -163,3 +163,8 @@ func (im IBCModule) OnTimeoutPacket( return im.app.OnTimeoutPacket(ctx, packet, relayer) } + +// GetAppVersion returns the interchain accounts metadata. +func (im IBCModule) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return im.keeper.GetAppVersion(ctx, portID, channelID) +} diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go index c0163e954e1..608996515c1 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_module_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" + icacontroller "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller" "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" @@ -702,3 +703,23 @@ func (suite *InterchainAccountsTestSuite) TestSingleHostMultipleControllers() { }) } } + +func (suite *InterchainAccountsTestSuite) TestGetAppVersion() { + path := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + controllerModule := cbs.(icacontroller.IBCModule) + + appVersion, found := controllerModule.GetAppVersion(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(path.EndpointA.ChannelConfig.Version, appVersion) +} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index 87af9ae9c6f..86099b954bd 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -102,6 +102,11 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability return k.scopedKeeper.ClaimCapability(ctx, cap, name) } +// GetAppVersion calls the ICS4Wrapper GetAppVersion function. +func (k Keeper) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return k.ics4Wrapper.GetAppVersion(ctx, portID, channelID) +} + // GetActiveChannelID retrieves the active channelID from the store, keyed by the provided connectionID and portID func (k Keeper) GetActiveChannelID(ctx sdk.Context, connectionID, portID string) (string, bool) { store := ctx.KVStore(k.storeKey) diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index 4c6a1708e43..8fb0b743cda 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -21,6 +21,7 @@ type AccountKeeper interface { // ICS4Wrapper defines the expected ICS4Wrapper for middleware type ICS4Wrapper interface { SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error + GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) } // ChannelKeeper defines the expected IBC channel keeper diff --git a/modules/apps/29-fee/ibc_module.go b/modules/apps/29-fee/ibc_module.go index e89b95cb4de..6ed9faa1f34 100644 --- a/modules/apps/29-fee/ibc_module.go +++ b/modules/apps/29-fee/ibc_module.go @@ -267,3 +267,8 @@ func (im IBCModule) OnTimeoutPacket( // call underlying callback return im.app.OnTimeoutPacket(ctx, packet, relayer) } + +// GetAppVersion returns the application version of the underlying application +func (im IBCModule) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + return im.keeper.GetAppVersion(ctx, portID, channelID) +} diff --git a/modules/apps/29-fee/ibc_module_test.go b/modules/apps/29-fee/ibc_module_test.go index cb6a89d13b7..3f5cf64635a 100644 --- a/modules/apps/29-fee/ibc_module_test.go +++ b/modules/apps/29-fee/ibc_module_test.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + fee "github.com/cosmos/ibc-go/v3/modules/apps/29-fee" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -834,3 +835,78 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { }) } } + +func (suite *FeeTestSuite) TestGetAppVersion() { + var ( + portID string + channelID string + expAppVersion string + ) + testCases := []struct { + name string + malleate func() + expFound bool + }{ + { + "success for fee enabled channel", + func() { + expAppVersion = ibcmock.Version + }, + true, + }, + { + "success for non fee enabled channel", + func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + // by default a new path uses a non fee channel + suite.coordinator.Setup(path) + portID = path.EndpointA.ChannelConfig.PortID + channelID = path.EndpointA.ChannelID + + expAppVersion = ibcmock.Version + }, + true, + }, + { + "channel does not exist", + func() { + channelID = "does not exist" + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + suite.coordinator.Setup(suite.path) + + portID = suite.path.EndpointA.ChannelConfig.PortID + channelID = suite.path.EndpointA.ChannelID + + // malleate test case + tc.malleate() + + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) + + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) + + feeModule := cbs.(fee.IBCModule) + + appVersion, found := feeModule.GetAppVersion(suite.chainA.GetContext(), portID, channelID) + + if tc.expFound { + suite.Require().True(found) + suite.Require().Equal(expAppVersion, appVersion) + } else { + suite.Require().False(found) + suite.Require().Empty(appVersion) + } + }) + } +} diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index 34c473e2e83..476497bfbbb 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -1,6 +1,8 @@ package keeper 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" @@ -42,3 +44,22 @@ func (k Keeper) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.C // ics4Wrapper may be core IBC or higher-level middleware return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) } + +// GetAppVersion returns the underlying application version. +func (k Keeper) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + version, found := k.ics4Wrapper.GetAppVersion(ctx, portID, channelID) + if !found { + return "", false + } + + if !k.IsFeeEnabled(ctx, portID, channelID) { + return version, true + } + + var metadata types.Metadata + if err := types.ModuleCdc.UnmarshalJSON([]byte(version), &metadata); err != nil { + panic(fmt.Errorf("unable to unmarshal metadata for fee enabled channel: %w", err)) + } + + return metadata.AppVersion, true +} diff --git a/modules/apps/29-fee/keeper/relay_test.go b/modules/apps/29-fee/keeper/relay_test.go index c853babd527..d0a9e620f9d 100644 --- a/modules/apps/29-fee/keeper/relay_test.go +++ b/modules/apps/29-fee/keeper/relay_test.go @@ -4,6 +4,8 @@ import ( "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" + ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" ) func (suite *KeeperTestSuite) TestWriteAcknowledgementAsync() { @@ -101,3 +103,70 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgementAsyncFeeDisabled() { packetAck, _ := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) suite.Require().Equal(packetAck, channeltypes.CommitAcknowledgement(ack.Acknowledgement())) } + +func (suite *KeeperTestSuite) TestGetAppVersion() { + var ( + portID string + channelID string + expAppVersion string + ) + testCases := []struct { + name string + malleate func() + expFound bool + }{ + { + "success for fee enabled channel", + func() { + expAppVersion = ibcmock.Version + }, + true, + }, + { + "success for non fee enabled channel", + func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + path.EndpointA.ChannelConfig.PortID = ibctesting.MockFeePort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockFeePort + // by default a new path uses a non fee channel + suite.coordinator.Setup(path) + portID = path.EndpointA.ChannelConfig.PortID + channelID = path.EndpointA.ChannelID + + expAppVersion = ibcmock.Version + }, + true, + }, + { + "channel does not exist", + func() { + channelID = "does not exist" + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + suite.coordinator.Setup(suite.path) + + portID = suite.path.EndpointA.ChannelConfig.PortID + channelID = suite.path.EndpointA.ChannelID + + // malleate test case + tc.malleate() + + appVersion, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetAppVersion(suite.chainA.GetContext(), portID, channelID) + + if tc.expFound { + suite.Require().True(found) + suite.Require().Equal(expAppVersion, appVersion) + } else { + suite.Require().False(found) + suite.Require().Empty(appVersion) + } + }) + } +} diff --git a/modules/apps/29-fee/types/expected_keepers.go b/modules/apps/29-fee/types/expected_keepers.go index 3a58f0706b3..1d9d3439b07 100644 --- a/modules/apps/29-fee/types/expected_keepers.go +++ b/modules/apps/29-fee/types/expected_keepers.go @@ -18,6 +18,7 @@ type AccountKeeper interface { type ICS4Wrapper interface { WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error + GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) } // ChannelKeeper defines the expected IBC channel keeper diff --git a/modules/core/04-channel/keeper/keeper.go b/modules/core/04-channel/keeper/keeper.go index 65378039ad9..ca2f824ad48 100644 --- a/modules/core/04-channel/keeper/keeper.go +++ b/modules/core/04-channel/keeper/keeper.go @@ -86,6 +86,16 @@ func (k Keeper) SetChannel(ctx sdk.Context, portID, channelID string, channel ty store.Set(host.ChannelKey(portID, channelID), bz) } +// GetAppVersion gets the version for the specified channel. +func (k Keeper) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return "", false + } + + return channel.Version, true +} + // GetNextChannelSequence gets the next channel sequence from the store. func (k Keeper) GetNextChannelSequence(ctx sdk.Context) uint64 { store := ctx.KVStore(k.storeKey) diff --git a/modules/core/04-channel/keeper/keeper_test.go b/modules/core/04-channel/keeper/keeper_test.go index 60888f11c3c..f04664d71f4 100644 --- a/modules/core/04-channel/keeper/keeper_test.go +++ b/modules/core/04-channel/keeper/keeper_test.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" + ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" ) // KeeperTestSuite is a testing suite to test keeper functions. @@ -62,6 +63,24 @@ func (suite *KeeperTestSuite) TestSetChannel() { suite.Equal(expectedCounterparty, storedChannel.Counterparty) } +func (suite *KeeperTestSuite) TestGetAppVersion() { + // create client and connections on both chains + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + version, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetAppVersion(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().False(found) + suite.Require().Empty(version) + + // init channel + err := path.EndpointA.ChanOpenInit() + suite.NoError(err) + + channelVersion, found := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetAppVersion(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(ibcmock.Version, channelVersion) +} + // TestGetAllChannels creates multiple channels on chain A through various connections // and tests their retrieval. 2 channels are on connA0 and 1 channel is on connA1 func (suite KeeperTestSuite) TestGetAllChannels() { diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 9f754fe0a3e..e6ba8f3449b 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -113,6 +113,12 @@ type ICS4Wrapper interface { packet exported.PacketI, ack exported.Acknowledgement, ) error + + GetAppVersion( + ctx sdk.Context, + portID, + channelID string, + ) (string, bool) } // Middleware must implement IBCModule to wrap communication from core IBC to underlying application diff --git a/testing/endpoint.go b/testing/endpoint.go index 607f7a16843..02c4e9aac39 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -328,7 +328,14 @@ func (endpoint *Endpoint) ChanOpenAck() error { proof, height, endpoint.Chain.SenderAccount.GetAddress().String(), ) - return endpoint.Chain.sendMsgs(msg) + + if err = endpoint.Chain.sendMsgs(msg); err != nil { + return err + } + + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + + return nil } // ChanOpenConfirm will construct and execute a MsgChannelOpenConfirm on the associated endpoint. From 16921d985b56e3e7c83a2a26126f575f72d78e99 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 21 Apr 2022 13:54:28 +0200 Subject: [PATCH 087/275] make URI path for getting all incentivized packets for channel consistent (#1278) * make URI path for getting all incentivized packets for a specific channel consistent * regenerate proto files and add changelog entry * something going with go.mod file... * update changelog entry Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 1 + docs/ibc/proto-docs.md | 2 +- modules/apps/29-fee/types/query.pb.go | 164 +++++++++++----------- modules/apps/29-fee/types/query.pb.gw.go | 2 +- proto/ibc/applications/fee/v1/query.proto | 2 +- 5 files changed, 86 insertions(+), 85 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a72dc61c05a..59091805154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output +* (apps/29-fee) [\#1278](https://github.com/cosmos/ibc-go/pull/1278) The URI path for the query to get all incentivized packets for a specifc channel did not follow the same format as the rest of queries. ## [v3.0.0](https://github.com/cosmos/ibc-go/releases/tag/v3.0.0) - 2022-03-15 diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 267feaeb581..297da93f262 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -1206,7 +1206,7 @@ Query defines the ICS29 gRPC querier service. | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `IncentivizedPackets` | [QueryIncentivizedPacketsRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsRequest) | [QueryIncentivizedPacketsResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsResponse) | IncentivizedPackets returns all incentivized packets and their associated fees | GET|/ibc/apps/fee/v1/incentivized_packets| | `IncentivizedPacket` | [QueryIncentivizedPacketRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketRequest) | [QueryIncentivizedPacketResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketResponse) | IncentivizedPacket returns all packet fees for a packet given its identifier | GET|/ibc/apps/fee/v1/incentivized_packet/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| -| `IncentivizedPacketsForChannel` | [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) | [QueryIncentivizedPacketsForChannelResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse) | Gets all incentivized packets for a specific channel | GET|/ibc/apps/fee/v1/incentivized_packets/{port_id}/{channel_id}| +| `IncentivizedPacketsForChannel` | [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) | [QueryIncentivizedPacketsForChannelResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse) | Gets all incentivized packets for a specific channel | GET|/ibc/apps/fee/v1/incentivized_packets/port/{port_id}/channel/{channel_id}| | `TotalRecvFees` | [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) | [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) | TotalRecvFees returns the total receive fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_recv_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| | `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| | `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| diff --git a/modules/apps/29-fee/types/query.pb.go b/modules/apps/29-fee/types/query.pb.go index 2d2231f85be..32677378fe3 100644 --- a/modules/apps/29-fee/types/query.pb.go +++ b/modules/apps/29-fee/types/query.pb.go @@ -966,88 +966,88 @@ func init() { } var fileDescriptor_0638a8a78ca2503c = []byte{ - // 1292 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xc1, 0x6f, 0x1b, 0xc5, - 0x17, 0xce, 0xa4, 0xf9, 0xb5, 0xc9, 0x24, 0xbf, 0x36, 0x1d, 0x87, 0x36, 0x35, 0x89, 0x9d, 0x4e, - 0x29, 0x84, 0xa0, 0xec, 0x2a, 0x0e, 0x6d, 0x5a, 0x84, 0x50, 0x6b, 0x97, 0xd0, 0x48, 0x08, 0xca, - 0x2a, 0x17, 0x10, 0xc8, 0x5d, 0xef, 0x8e, 0x9d, 0x55, 0x9c, 0x9d, 0xed, 0xee, 0xda, 0xe0, 0xa6, - 0x41, 0x6a, 0xa4, 0x08, 0x09, 0x2a, 0x84, 0x84, 0xc4, 0x01, 0x71, 0xe1, 0x80, 0x90, 0x90, 0xf8, - 0x03, 0xf8, 0x0f, 0x7a, 0xaa, 0x2a, 0x71, 0xe1, 0x64, 0xaa, 0x84, 0x33, 0x07, 0x8b, 0x03, 0x47, - 0xb4, 0x33, 0xb3, 0xeb, 0x75, 0x77, 0x37, 0xf1, 0x96, 0x44, 0x9c, 0x62, 0xcf, 0xbc, 0xf7, 0xe6, - 0xfb, 0xbe, 0xf7, 0x3c, 0xf3, 0x29, 0xf0, 0x82, 0x51, 0xd1, 0x64, 0xd5, 0xb2, 0xea, 0x86, 0xa6, - 0xba, 0x06, 0x35, 0x1d, 0xb9, 0x4a, 0x88, 0xdc, 0x5c, 0x90, 0xef, 0x34, 0x88, 0xdd, 0x92, 0x2c, - 0x9b, 0xba, 0x14, 0x9d, 0x35, 0x2a, 0x9a, 0x14, 0x0e, 0x92, 0xaa, 0x84, 0x48, 0xcd, 0x85, 0xec, - 0x44, 0x8d, 0xd6, 0x28, 0x8b, 0x91, 0xbd, 0x4f, 0x3c, 0x3c, 0x3b, 0x55, 0xa3, 0xb4, 0x56, 0x27, - 0xb2, 0x6a, 0x19, 0xb2, 0x6a, 0x9a, 0xd4, 0x15, 0x49, 0x7c, 0x37, 0xa7, 0x51, 0x67, 0x83, 0x3a, - 0x72, 0x45, 0x75, 0xbc, 0x83, 0x2a, 0xc4, 0x55, 0x17, 0x64, 0x8d, 0x1a, 0xa6, 0xd8, 0x9f, 0x0b, - 0xef, 0x33, 0x14, 0x41, 0x94, 0xa5, 0xd6, 0x0c, 0x93, 0x15, 0x13, 0xb1, 0xe7, 0x93, 0xd0, 0x7b, - 0xf8, 0x78, 0xc8, 0xc5, 0xa4, 0x90, 0x1a, 0x31, 0x89, 0x63, 0x38, 0xe1, 0x4a, 0x1a, 0xb5, 0x89, - 0xac, 0xad, 0xa9, 0xa6, 0x49, 0xea, 0x5e, 0x88, 0xf8, 0xc8, 0x43, 0xf0, 0x03, 0x00, 0xf3, 0xef, - 0x79, 0x78, 0x56, 0x4c, 0x8d, 0x98, 0xae, 0xd1, 0x34, 0xee, 0x12, 0xfd, 0x96, 0xaa, 0xad, 0x13, - 0xd7, 0x51, 0xc8, 0x9d, 0x06, 0x71, 0x5c, 0xb4, 0x0c, 0x61, 0x17, 0xe4, 0x24, 0x98, 0x01, 0xb3, - 0xa3, 0x85, 0x17, 0x25, 0xce, 0x48, 0xf2, 0x18, 0x49, 0x5c, 0x57, 0xc1, 0x48, 0xba, 0xa5, 0xd6, - 0x88, 0xc8, 0x55, 0x42, 0x99, 0xe8, 0x3c, 0x1c, 0x63, 0x81, 0xe5, 0x35, 0x62, 0xd4, 0xd6, 0xdc, - 0xc9, 0xc1, 0x19, 0x30, 0x3b, 0xa4, 0x8c, 0xb2, 0xb5, 0x9b, 0x6c, 0x09, 0x7f, 0x0e, 0xe0, 0x4c, - 0x32, 0x1c, 0xc7, 0xa2, 0xa6, 0x43, 0x50, 0x15, 0x4e, 0x18, 0xa1, 0xed, 0xb2, 0xc5, 0xf7, 0x27, - 0xc1, 0xcc, 0xb1, 0xd9, 0xd1, 0xc2, 0xbc, 0x94, 0xd0, 0x58, 0x69, 0x45, 0xf7, 0x72, 0xaa, 0x86, - 0x5f, 0x71, 0x99, 0x10, 0xa7, 0x38, 0xf4, 0xb0, 0x9d, 0x1f, 0x50, 0x32, 0x46, 0xf4, 0x3c, 0xbc, - 0x03, 0x60, 0x2e, 0x01, 0x8c, 0x2f, 0xcd, 0x35, 0x38, 0xc2, 0x4f, 0x2f, 0x1b, 0xba, 0x50, 0x66, - 0x9a, 0x9d, 0xef, 0xa9, 0x2e, 0xf9, 0x52, 0x37, 0x3d, 0x4d, 0xbc, 0xa8, 0x15, 0x5d, 0x9c, 0x37, - 0x6c, 0x89, 0xef, 0xfd, 0x88, 0xf2, 0x59, 0x72, 0x8f, 0x02, 0x4d, 0x74, 0x98, 0x89, 0xd1, 0x44, - 0x40, 0x7a, 0x26, 0x49, 0x50, 0x54, 0x12, 0xfc, 0x08, 0xc0, 0x97, 0x93, 0xda, 0xb3, 0x4c, 0xed, - 0x12, 0xe7, 0x7b, 0xd8, 0x73, 0x73, 0x16, 0x9e, 0xb0, 0xa8, 0xcd, 0x24, 0xf6, 0xd4, 0x19, 0x51, - 0x8e, 0x7b, 0x5f, 0x57, 0x74, 0x34, 0x0d, 0xa1, 0x90, 0xd8, 0xdb, 0x3b, 0xc6, 0xf6, 0x46, 0xc4, - 0x4a, 0x8c, 0xb4, 0x43, 0x51, 0x69, 0xbf, 0x04, 0x70, 0xae, 0x1f, 0x42, 0x42, 0xe5, 0xdb, 0x87, - 0x38, 0x79, 0xf1, 0x33, 0xf7, 0x11, 0x3c, 0xc7, 0xf0, 0xac, 0x52, 0x57, 0xad, 0x2b, 0x44, 0x6b, - 0xb2, 0xd0, 0xc3, 0x9a, 0x36, 0xfc, 0x2d, 0x80, 0xd9, 0xb8, 0xfa, 0x82, 0xdf, 0x3d, 0x38, 0x62, - 0x13, 0xad, 0x59, 0xae, 0x12, 0xe2, 0x93, 0x3a, 0xd7, 0xd3, 0x30, 0xbf, 0x55, 0x25, 0x6a, 0x98, - 0xc5, 0x1b, 0x5e, 0xf1, 0x4e, 0x3b, 0x3f, 0xde, 0x52, 0x37, 0xea, 0xaf, 0xe1, 0x20, 0x13, 0xff, - 0xf4, 0x7b, 0x7e, 0xb6, 0x66, 0xb8, 0x6b, 0x8d, 0x8a, 0xa4, 0xd1, 0x0d, 0x59, 0xdc, 0x7d, 0xfc, - 0xcf, 0xbc, 0xa3, 0xaf, 0xcb, 0x6e, 0xcb, 0x22, 0x0e, 0x2b, 0xe2, 0x28, 0xc3, 0xb6, 0x40, 0x81, - 0x3f, 0x84, 0x93, 0x5d, 0x6c, 0xd7, 0xb5, 0xf5, 0xc3, 0xa5, 0xfe, 0x0d, 0x08, 0x4b, 0x1b, 0x94, - 0x17, 0xcc, 0x5b, 0x70, 0x58, 0xd5, 0xd6, 0xfb, 0x24, 0x5e, 0x12, 0xc4, 0x4f, 0x71, 0xe2, 0x7e, - 0x62, 0x3a, 0xde, 0x27, 0x54, 0x0e, 0x01, 0xdf, 0x86, 0x53, 0x5d, 0x5c, 0xab, 0xc6, 0x06, 0xa1, - 0x0d, 0xf7, 0x70, 0xa9, 0xff, 0x08, 0xe0, 0x74, 0xc2, 0x11, 0x82, 0xfe, 0x0e, 0x80, 0x63, 0x2e, - 0x5f, 0xef, 0x53, 0x83, 0xb7, 0x84, 0x06, 0x19, 0xae, 0x41, 0x38, 0x39, 0x9d, 0x0e, 0xa3, 0x6e, - 0x17, 0x0f, 0xfe, 0xce, 0xbf, 0xea, 0x4a, 0xb4, 0x61, 0xba, 0xc4, 0xb6, 0x54, 0xdb, 0x6d, 0x5d, - 0xd7, 0x75, 0x9b, 0x38, 0x81, 0x1e, 0xaf, 0xf6, 0xfc, 0xea, 0x3d, 0x41, 0x46, 0x8a, 0xcf, 0x75, - 0xda, 0xf9, 0xd3, 0x1c, 0x49, 0x77, 0x0f, 0x87, 0x2f, 0x83, 0x12, 0x3c, 0x65, 0x93, 0xba, 0xda, - 0x22, 0x76, 0x59, 0xe5, 0xf5, 0xf8, 0x65, 0x52, 0xcc, 0x76, 0xda, 0xf9, 0x33, 0xfe, 0x04, 0xf7, - 0x04, 0x60, 0xe5, 0xa4, 0x58, 0x11, 0x08, 0x70, 0x53, 0xbc, 0x4e, 0xb1, 0xe8, 0x84, 0x94, 0x0a, - 0x9c, 0xd0, 0x42, 0xdb, 0xc1, 0x69, 0x1c, 0x68, 0xbe, 0xd3, 0xce, 0x3f, 0x2f, 0x80, 0xc6, 0x44, - 0x61, 0x25, 0xa3, 0x45, 0x6b, 0xe3, 0x2f, 0xfc, 0x97, 0x68, 0x99, 0x90, 0x37, 0x4d, 0xb5, 0x52, - 0x27, 0xba, 0xb8, 0x9a, 0xfe, 0x8b, 0x47, 0xfa, 0x07, 0xbf, 0x49, 0x71, 0x68, 0x84, 0x0a, 0xf7, - 0x01, 0x9c, 0xa8, 0x12, 0x52, 0x26, 0x7c, 0xbf, 0x2c, 0x1a, 0xe1, 0x0f, 0xd6, 0x5c, 0xe2, 0x55, - 0x19, 0xa9, 0x59, 0xbc, 0x20, 0x26, 0x4d, 0xc8, 0x16, 0x57, 0x15, 0x2b, 0xa8, 0x1a, 0xc1, 0x82, - 0xb7, 0xfd, 0xb1, 0x8f, 0xd4, 0xf4, 0x45, 0x7b, 0xa5, 0xfb, 0xb2, 0xf0, 0xf6, 0xa0, 0x4e, 0x3b, - 0x7f, 0x92, 0x9f, 0x23, 0x36, 0x70, 0xf0, 0xda, 0xf4, 0xce, 0xdd, 0x60, 0x7f, 0x73, 0x87, 0xdf, - 0x4f, 0xea, 0x5c, 0x20, 0xd5, 0x12, 0x1c, 0x0d, 0x71, 0x62, 0x40, 0x86, 0x8b, 0x67, 0x3a, 0xed, - 0x3c, 0x8a, 0x10, 0xc6, 0x0a, 0xec, 0xf2, 0x2c, 0x7c, 0x3f, 0x0e, 0xff, 0xc7, 0x6a, 0xa3, 0x5f, - 0x00, 0xcc, 0xc4, 0xbc, 0x60, 0xe8, 0x4a, 0xa2, 0xcc, 0x07, 0x78, 0xbe, 0xec, 0xd5, 0x67, 0xc8, - 0xe4, 0x7c, 0xf0, 0xfc, 0xf6, 0xaf, 0x7f, 0x7c, 0x3d, 0xf8, 0x12, 0xba, 0x28, 0x0b, 0x97, 0x1a, - 0xb8, 0xd3, 0xb8, 0xb7, 0x13, 0x3d, 0x18, 0x84, 0x28, 0x5a, 0x0e, 0x2d, 0xa5, 0x05, 0xe0, 0x23, - 0xbf, 0x92, 0x3e, 0x51, 0x00, 0xdf, 0x06, 0x0c, 0xf9, 0x3d, 0x74, 0xb7, 0x1f, 0xe4, 0xb2, 0x37, - 0x16, 0xf2, 0x66, 0x70, 0x35, 0x4b, 0x62, 0x60, 0xb6, 0x02, 0xb3, 0x1d, 0xda, 0xeb, 0x0e, 0xc7, - 0x96, 0xec, 0x78, 0x40, 0x4d, 0x8d, 0x84, 0xf7, 0xfd, 0xb5, 0x2d, 0xf4, 0x27, 0x80, 0xd3, 0xfb, - 0x9a, 0x11, 0x54, 0x4c, 0xdd, 0x9a, 0x88, 0x35, 0xcb, 0x96, 0xfe, 0x55, 0x0d, 0xa1, 0xd7, 0x0d, - 0x26, 0xd7, 0x1b, 0xe8, 0xf5, 0xbe, 0x1a, 0x2d, 0x6f, 0x06, 0x02, 0x6d, 0x86, 0xe4, 0x40, 0x7f, - 0x03, 0xf8, 0xff, 0x1e, 0x37, 0x82, 0x0a, 0xfb, 0x83, 0x8b, 0xb3, 0x46, 0xd9, 0xc5, 0x54, 0x39, - 0x82, 0xc0, 0xa7, 0x8c, 0xc0, 0x27, 0xa8, 0x19, 0x21, 0xe0, 0x7a, 0xf1, 0xe5, 0xc0, 0xd1, 0x1c, - 0x51, 0xaf, 0xff, 0x02, 0x70, 0x2c, 0xec, 0x46, 0xd0, 0x42, 0x1f, 0x2c, 0x7a, 0x8d, 0x51, 0xb6, - 0x90, 0x26, 0x45, 0xf0, 0xde, 0x62, 0xbc, 0x3f, 0x46, 0x8d, 0x04, 0xde, 0xbe, 0xa1, 0x39, 0x22, - 0xda, 0x3b, 0x83, 0x70, 0xfc, 0x69, 0x27, 0x82, 0x2e, 0xf5, 0xc1, 0x23, 0x6a, 0x8e, 0xb2, 0x97, - 0xd3, 0xa6, 0x09, 0x09, 0xee, 0xf3, 0xdf, 0xfa, 0x26, 0x6a, 0x25, 0x68, 0x10, 0x36, 0x34, 0x47, - 0xa4, 0xc3, 0x13, 0x00, 0x33, 0x31, 0x4e, 0xe2, 0xa0, 0x5b, 0x3b, 0xd9, 0x1a, 0x1d, 0x74, 0x6b, - 0xef, 0x63, 0x5b, 0xf0, 0x2a, 0xd3, 0xe3, 0x1d, 0xf4, 0x76, 0x44, 0x8f, 0x38, 0x9f, 0x22, 0x6f, - 0x3e, 0xe5, 0x95, 0x42, 0x52, 0x84, 0x7f, 0xdc, 0x3f, 0x03, 0x88, 0xa2, 0x2e, 0xe1, 0xa0, 0xcb, - 0x3d, 0xd1, 0xe5, 0x1c, 0x74, 0xb9, 0x27, 0x1b, 0x12, 0xfc, 0x02, 0xe3, 0x97, 0x43, 0x53, 0x11, - 0x7e, 0xa1, 0xf7, 0x15, 0x3d, 0x02, 0xf0, 0x74, 0xa4, 0x08, 0xba, 0x9c, 0xf2, 0x54, 0x1f, 0xed, - 0x52, 0xea, 0x3c, 0x01, 0xf6, 0x26, 0x03, 0x5b, 0x44, 0xd7, 0xf6, 0x03, 0xeb, 0x4f, 0x65, 0x64, - 0x16, 0x43, 0x0d, 0x28, 0xbe, 0xfb, 0x70, 0x37, 0x07, 0x1e, 0xef, 0xe6, 0xc0, 0x93, 0xdd, 0x1c, - 0xf8, 0x6a, 0x2f, 0x37, 0xf0, 0x78, 0x2f, 0x37, 0xf0, 0xdb, 0x5e, 0x6e, 0xe0, 0x83, 0x4b, 0x51, - 0x87, 0x6e, 0x54, 0xb4, 0xf9, 0x1a, 0x95, 0x9b, 0x8b, 0xf2, 0x06, 0xd5, 0x1b, 0x75, 0xe2, 0xf0, - 0xa3, 0x0b, 0x57, 0xe7, 0xbd, 0xd3, 0x99, 0x69, 0xaf, 0x1c, 0x67, 0xff, 0x37, 0x5a, 0xfc, 0x27, - 0x00, 0x00, 0xff, 0xff, 0xac, 0x50, 0xbb, 0x05, 0x64, 0x13, 0x00, 0x00, + // 1281 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x4f, 0x6f, 0x1b, 0x45, + 0x1c, 0xcd, 0xa4, 0xa1, 0x4d, 0x26, 0xa1, 0x4d, 0xc7, 0xa1, 0x4d, 0x4d, 0x62, 0xa7, 0x53, 0x0a, + 0x21, 0x28, 0xbb, 0x8a, 0x43, 0x9b, 0x96, 0x53, 0x6b, 0x43, 0x68, 0x04, 0x82, 0x76, 0x95, 0x0b, + 0x08, 0xe4, 0xae, 0x77, 0xc7, 0xce, 0x2a, 0xce, 0xce, 0x76, 0x77, 0x6d, 0x70, 0xd3, 0x20, 0x35, + 0x52, 0x84, 0x04, 0x15, 0x42, 0x42, 0xe2, 0x80, 0xb8, 0x22, 0x24, 0x24, 0xb8, 0xf3, 0x0d, 0x7a, + 0xaa, 0x2a, 0x71, 0xe1, 0x64, 0xaa, 0x84, 0x4f, 0x60, 0x71, 0x40, 0xe2, 0x82, 0x76, 0x66, 0x76, + 0xbd, 0xee, 0xee, 0x26, 0xde, 0x92, 0x88, 0x53, 0xec, 0xf9, 0xfd, 0x99, 0xf7, 0xde, 0xfc, 0x3c, + 0xf3, 0x14, 0x78, 0xc1, 0xa8, 0x68, 0xb2, 0x6a, 0x59, 0x75, 0x43, 0x53, 0x5d, 0x83, 0x9a, 0x8e, + 0x5c, 0x25, 0x44, 0x6e, 0x2e, 0xc8, 0x77, 0x1a, 0xc4, 0x6e, 0x49, 0x96, 0x4d, 0x5d, 0x8a, 0xce, + 0x1a, 0x15, 0x4d, 0x0a, 0x27, 0x49, 0x55, 0x42, 0xa4, 0xe6, 0x42, 0x76, 0xa2, 0x46, 0x6b, 0x94, + 0xe5, 0xc8, 0xde, 0x27, 0x9e, 0x9e, 0x9d, 0xaa, 0x51, 0x5a, 0xab, 0x13, 0x59, 0xb5, 0x0c, 0x59, + 0x35, 0x4d, 0xea, 0x8a, 0x22, 0x1e, 0xcd, 0x69, 0xd4, 0xd9, 0xa0, 0x8e, 0x5c, 0x51, 0x1d, 0x6f, + 0xa3, 0x0a, 0x71, 0xd5, 0x05, 0x59, 0xa3, 0x86, 0x29, 0xe2, 0x73, 0xe1, 0x38, 0x43, 0x11, 0x64, + 0x59, 0x6a, 0xcd, 0x30, 0x59, 0x33, 0x91, 0x7b, 0x3e, 0x09, 0xbd, 0x87, 0x8f, 0xa7, 0x5c, 0x4c, + 0x4a, 0xa9, 0x11, 0x93, 0x38, 0x86, 0x13, 0xee, 0xa4, 0x51, 0x9b, 0xc8, 0xda, 0x9a, 0x6a, 0x9a, + 0xa4, 0xee, 0xa5, 0x88, 0x8f, 0x3c, 0x05, 0x3f, 0x00, 0x30, 0x7f, 0xcb, 0xc3, 0xb3, 0x62, 0x6a, + 0xc4, 0x74, 0x8d, 0xa6, 0x71, 0x97, 0xe8, 0x37, 0x55, 0x6d, 0x9d, 0xb8, 0x8e, 0x42, 0xee, 0x34, + 0x88, 0xe3, 0xa2, 0x65, 0x08, 0xbb, 0x20, 0x27, 0xc1, 0x0c, 0x98, 0x1d, 0x2d, 0xbc, 0x2c, 0x71, + 0x46, 0x92, 0xc7, 0x48, 0xe2, 0xba, 0x0a, 0x46, 0xd2, 0x4d, 0xb5, 0x46, 0x44, 0xad, 0x12, 0xaa, + 0x44, 0xe7, 0xe1, 0x18, 0x4b, 0x2c, 0xaf, 0x11, 0xa3, 0xb6, 0xe6, 0x4e, 0x0e, 0xce, 0x80, 0xd9, + 0x21, 0x65, 0x94, 0xad, 0xdd, 0x60, 0x4b, 0xf8, 0x0b, 0x00, 0x67, 0x92, 0xe1, 0x38, 0x16, 0x35, + 0x1d, 0x82, 0xaa, 0x70, 0xc2, 0x08, 0x85, 0xcb, 0x16, 0x8f, 0x4f, 0x82, 0x99, 0x63, 0xb3, 0xa3, + 0x85, 0x79, 0x29, 0xe1, 0x60, 0xa5, 0x15, 0xdd, 0xab, 0xa9, 0x1a, 0x7e, 0xc7, 0x65, 0x42, 0x9c, + 0xe2, 0xd0, 0xc3, 0x76, 0x7e, 0x40, 0xc9, 0x18, 0xd1, 0xfd, 0xf0, 0x0e, 0x80, 0xb9, 0x04, 0x30, + 0xbe, 0x34, 0xd7, 0xe0, 0x08, 0xdf, 0xbd, 0x6c, 0xe8, 0x42, 0x99, 0x69, 0xb6, 0xbf, 0xa7, 0xba, + 0xe4, 0x4b, 0xdd, 0xf4, 0x34, 0xf1, 0xb2, 0x56, 0x74, 0xb1, 0xdf, 0xb0, 0x25, 0xbe, 0xf7, 0x23, + 0xca, 0xe7, 0xc9, 0x67, 0x14, 0x68, 0xa2, 0xc3, 0x4c, 0x8c, 0x26, 0x02, 0xd2, 0x33, 0x49, 0x82, + 0xa2, 0x92, 0xe0, 0x47, 0x00, 0xbe, 0x9a, 0x74, 0x3c, 0xcb, 0xd4, 0x2e, 0x71, 0xbe, 0x87, 0x3d, + 0x37, 0x67, 0xe1, 0x09, 0x8b, 0xda, 0x4c, 0x62, 0x4f, 0x9d, 0x11, 0xe5, 0xb8, 0xf7, 0x75, 0x45, + 0x47, 0xd3, 0x10, 0x0a, 0x89, 0xbd, 0xd8, 0x31, 0x16, 0x1b, 0x11, 0x2b, 0x31, 0xd2, 0x0e, 0x45, + 0xa5, 0xfd, 0x0a, 0xc0, 0xb9, 0x7e, 0x08, 0x09, 0x95, 0x6f, 0x1f, 0xe2, 0xe4, 0xc5, 0xcf, 0xdc, + 0xc7, 0xf0, 0x1c, 0xc3, 0xb3, 0x4a, 0x5d, 0xb5, 0xae, 0x10, 0xad, 0xc9, 0x52, 0x0f, 0x6b, 0xda, + 0xf0, 0x77, 0x00, 0x66, 0xe3, 0xfa, 0x0b, 0x7e, 0xf7, 0xe0, 0x88, 0x4d, 0xb4, 0x66, 0xb9, 0x4a, + 0x88, 0x4f, 0xea, 0x5c, 0xcf, 0x81, 0xf9, 0x47, 0x55, 0xa2, 0x86, 0x59, 0x7c, 0xd3, 0x6b, 0xde, + 0x69, 0xe7, 0xc7, 0x5b, 0xea, 0x46, 0xfd, 0x0d, 0x1c, 0x54, 0xe2, 0x9f, 0xfe, 0xc8, 0xcf, 0xd6, + 0x0c, 0x77, 0xad, 0x51, 0x91, 0x34, 0xba, 0x21, 0x8b, 0xbb, 0x8f, 0xff, 0x99, 0x77, 0xf4, 0x75, + 0xd9, 0x6d, 0x59, 0xc4, 0x61, 0x4d, 0x1c, 0x65, 0xd8, 0x16, 0x28, 0xf0, 0x47, 0x70, 0xb2, 0x8b, + 0xed, 0xba, 0xb6, 0x7e, 0xb8, 0xd4, 0xbf, 0x05, 0x61, 0x69, 0x83, 0xf6, 0x82, 0x79, 0x0b, 0x0e, + 0xab, 0xda, 0x7a, 0x9f, 0xc4, 0x4b, 0x82, 0xf8, 0x29, 0x4e, 0xdc, 0x2f, 0x4c, 0xc7, 0xfb, 0x84, + 0xca, 0x21, 0xe0, 0xdb, 0x70, 0xaa, 0x8b, 0x6b, 0xd5, 0xd8, 0x20, 0xb4, 0xe1, 0x1e, 0x2e, 0xf5, + 0x1f, 0x01, 0x9c, 0x4e, 0xd8, 0x42, 0xd0, 0xdf, 0x01, 0x70, 0xcc, 0xe5, 0xeb, 0x7d, 0x6a, 0xf0, + 0xb6, 0xd0, 0x20, 0xc3, 0x35, 0x08, 0x17, 0xa7, 0xd3, 0x61, 0xd4, 0xed, 0xe2, 0xc1, 0xdf, 0xfb, + 0x57, 0x5d, 0x89, 0x36, 0x4c, 0x97, 0xd8, 0x96, 0x6a, 0xbb, 0xad, 0xeb, 0xba, 0x6e, 0x13, 0x27, + 0xd0, 0xe3, 0xf5, 0x9e, 0x5f, 0xbd, 0x27, 0xc8, 0x48, 0xf1, 0x85, 0x4e, 0x3b, 0x7f, 0x9a, 0x23, + 0xe9, 0xc6, 0x70, 0xf8, 0x32, 0x28, 0xc1, 0x53, 0x36, 0xa9, 0xab, 0x2d, 0x62, 0x97, 0x55, 0xde, + 0x8f, 0x5f, 0x26, 0xc5, 0x6c, 0xa7, 0x9d, 0x3f, 0xe3, 0x4f, 0x70, 0x4f, 0x02, 0x56, 0x4e, 0x8a, + 0x15, 0x81, 0x00, 0x37, 0xc5, 0xeb, 0x14, 0x8b, 0x4e, 0x48, 0xa9, 0xc0, 0x09, 0x2d, 0x14, 0x0e, + 0x76, 0xe3, 0x40, 0xf3, 0x9d, 0x76, 0xfe, 0x45, 0x01, 0x34, 0x26, 0x0b, 0x2b, 0x19, 0x2d, 0xda, + 0x1b, 0x7f, 0xe9, 0xbf, 0x44, 0xcb, 0x84, 0xbc, 0x65, 0xaa, 0x95, 0x3a, 0xd1, 0xc5, 0xd5, 0xf4, + 0x7f, 0x3c, 0xd2, 0x3f, 0xf8, 0x87, 0x14, 0x87, 0x46, 0xa8, 0x70, 0x1f, 0xc0, 0x89, 0x2a, 0x21, + 0x65, 0xc2, 0xe3, 0x65, 0x71, 0x10, 0xfe, 0x60, 0xcd, 0x25, 0x5e, 0x95, 0x91, 0x9e, 0xc5, 0x0b, + 0x62, 0xd2, 0x84, 0x6c, 0x71, 0x5d, 0xb1, 0x82, 0xaa, 0x11, 0x2c, 0x78, 0xdb, 0x1f, 0xfb, 0x48, + 0x4f, 0x5f, 0xb4, 0xd7, 0xba, 0x2f, 0x0b, 0x3f, 0x1e, 0xd4, 0x69, 0xe7, 0x4f, 0xf2, 0x7d, 0x44, + 0x00, 0x07, 0xaf, 0x4d, 0xef, 0xdc, 0x0d, 0xf6, 0x37, 0x77, 0xf8, 0x83, 0xa4, 0x93, 0x0b, 0xa4, + 0x5a, 0x82, 0xa3, 0x21, 0x4e, 0x0c, 0xc8, 0x70, 0xf1, 0x4c, 0xa7, 0x9d, 0x47, 0x11, 0xc2, 0x58, + 0x81, 0x5d, 0x9e, 0x85, 0x5f, 0xc6, 0xe1, 0x73, 0xac, 0x37, 0xfa, 0x15, 0xc0, 0x4c, 0xcc, 0x0b, + 0x86, 0xae, 0x24, 0xca, 0x7c, 0x80, 0xe7, 0xcb, 0x5e, 0x7d, 0x86, 0x4a, 0xce, 0x07, 0xcf, 0x6f, + 0xff, 0xf6, 0xe7, 0x37, 0x83, 0xaf, 0xa0, 0x8b, 0xb2, 0x70, 0xa9, 0x81, 0x3b, 0x8d, 0x7b, 0x3b, + 0xd1, 0x83, 0x41, 0x88, 0xa2, 0xed, 0xd0, 0x52, 0x5a, 0x00, 0x3e, 0xf2, 0x2b, 0xe9, 0x0b, 0x05, + 0xf0, 0x6d, 0xc0, 0x90, 0xdf, 0x43, 0x77, 0xfb, 0x41, 0x2e, 0x7b, 0x63, 0x21, 0x6f, 0x06, 0x57, + 0xb3, 0x24, 0x06, 0x66, 0x2b, 0x30, 0xdb, 0xa1, 0x58, 0x77, 0x38, 0xb6, 0x64, 0xc7, 0x03, 0x6a, + 0x6a, 0x24, 0x1c, 0xf7, 0xd7, 0xb6, 0xd0, 0x3f, 0x00, 0x4e, 0xef, 0x6b, 0x46, 0x50, 0x31, 0xf5, + 0xd1, 0x44, 0xac, 0x59, 0xb6, 0xf4, 0x9f, 0x7a, 0x08, 0xbd, 0x6e, 0x31, 0xb9, 0xde, 0x41, 0x2b, + 0x7d, 0x1d, 0xb4, 0xaf, 0x57, 0x44, 0xa5, 0x90, 0x36, 0xe8, 0x6f, 0x00, 0x9f, 0xef, 0xb1, 0x26, + 0xa8, 0xb0, 0x3f, 0xd2, 0x38, 0x9f, 0x94, 0x5d, 0x4c, 0x55, 0x23, 0xd8, 0x7c, 0xc6, 0xd8, 0x7c, + 0x8a, 0x9a, 0x11, 0x36, 0xae, 0x97, 0x5f, 0x0e, 0xec, 0xcd, 0x11, 0x1d, 0xfc, 0x5f, 0x00, 0x8e, + 0x85, 0xad, 0x09, 0x5a, 0xe8, 0x83, 0x45, 0xaf, 0x4b, 0xca, 0x16, 0xd2, 0x94, 0x08, 0xde, 0x5b, + 0x8c, 0xf7, 0x27, 0xa8, 0x91, 0xc0, 0xdb, 0x77, 0x37, 0x47, 0x44, 0x7b, 0x67, 0x10, 0x8e, 0x3f, + 0x6d, 0x4b, 0xd0, 0xa5, 0x3e, 0x78, 0x44, 0x9d, 0x52, 0xf6, 0x72, 0xda, 0x32, 0x21, 0xc1, 0x7d, + 0xfe, 0xc3, 0xdf, 0x44, 0xad, 0x04, 0x0d, 0xc2, 0xee, 0xe6, 0x88, 0x74, 0x78, 0x02, 0x60, 0x26, + 0xc6, 0x56, 0x1c, 0x74, 0x85, 0x27, 0xfb, 0xa4, 0x83, 0xae, 0xf0, 0x7d, 0x3c, 0x0c, 0x5e, 0x65, + 0x7a, 0xbc, 0x87, 0xde, 0x8d, 0xe8, 0x11, 0x67, 0x5a, 0xe4, 0xcd, 0xa7, 0x8c, 0x53, 0xc2, 0x8f, + 0xfb, 0x67, 0x00, 0x51, 0xd4, 0x32, 0x1c, 0x74, 0xd3, 0x27, 0x5a, 0x9e, 0x83, 0x6e, 0xfa, 0x64, + 0x77, 0x82, 0x5f, 0x62, 0xfc, 0x72, 0x68, 0x2a, 0xc2, 0x2f, 0xf4, 0xd8, 0xa2, 0x47, 0x00, 0x9e, + 0x8e, 0x34, 0x41, 0x97, 0x53, 0xee, 0xea, 0xa3, 0x5d, 0x4a, 0x5d, 0x27, 0xc0, 0xde, 0x60, 0x60, + 0x8b, 0xe8, 0xda, 0x7e, 0x60, 0xfb, 0xb9, 0x5d, 0x8b, 0xef, 0x3f, 0xdc, 0xcd, 0x81, 0xc7, 0xbb, + 0x39, 0xf0, 0x64, 0x37, 0x07, 0xbe, 0xde, 0xcb, 0x0d, 0x3c, 0xde, 0xcb, 0x0d, 0xfc, 0xbe, 0x97, + 0x1b, 0xf8, 0xf0, 0x52, 0xd4, 0xae, 0x1b, 0x15, 0x6d, 0xbe, 0x46, 0xe5, 0xe6, 0xa2, 0xbc, 0x41, + 0xf5, 0x46, 0x9d, 0x38, 0x7c, 0xeb, 0xc2, 0xd5, 0x79, 0x6f, 0x77, 0xe6, 0xe0, 0x2b, 0xc7, 0xd9, + 0x3f, 0x91, 0x16, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x61, 0x8e, 0x05, 0x2f, 0x71, 0x13, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/apps/29-fee/types/query.pb.gw.go b/modules/apps/29-fee/types/query.pb.gw.go index 37c38769d20..9b9e47c5939 100644 --- a/modules/apps/29-fee/types/query.pb.gw.go +++ b/modules/apps/29-fee/types/query.pb.gw.go @@ -1228,7 +1228,7 @@ var ( pattern_Query_IncentivizedPacket_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "incentivized_packet", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_IncentivizedPacketsForChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 1, 0, 4, 1, 5, 6}, []string{"ibc", "apps", "fee", "v1", "incentivized_packets", "port_id", "channel_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_IncentivizedPacketsForChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8}, []string{"ibc", "apps", "fee", "v1", "incentivized_packets", "port", "port_id", "channel", "channel_id"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_TotalRecvFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_recv_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) diff --git a/proto/ibc/applications/fee/v1/query.proto b/proto/ibc/applications/fee/v1/query.proto index f36a1414203..acab12f5161 100644 --- a/proto/ibc/applications/fee/v1/query.proto +++ b/proto/ibc/applications/fee/v1/query.proto @@ -29,7 +29,7 @@ service Query { // Gets all incentivized packets for a specific channel rpc IncentivizedPacketsForChannel(QueryIncentivizedPacketsForChannelRequest) returns (QueryIncentivizedPacketsForChannelResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/incentivized_packets/{port_id}/{channel_id}"; + option (google.api.http).get = "/ibc/apps/fee/v1/incentivized_packets/port/{port_id}/channel/{channel_id}"; } // TotalRecvFees returns the total receive fees for a packet given its identifier From a1878038ca40d117defd3688ad1494e9872b2ffb Mon Sep 17 00:00:00 2001 From: vuong <56973102+nguyenvuong1122000@users.noreply.github.com> Date: Thu, 21 Apr 2022 23:14:57 +0700 Subject: [PATCH 088/275] chore : add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse (#1279) ## Description - Add a version field to MsgChannelOpenInitResponse and MsgChannelOpenTryResponse in proto and gen proto - Set the selected channel version in the [MsgChannelOpenInitResponse](https://github.com/notional-labs/ibc-go/blob/ed7a082565fadb9ce27067fa1efb56c23fafc8ef/modules/core/keeper/msg_server.go#L197) and [MsgChannelOpenTryResponse](https://github.com/notional-labs/ibc-go/blob/ed7a082565fadb9ce27067fa1efb56c23fafc8ef/modules/core/keeper/msg_server.go#L237) --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes closes: #1204 --- CHANGELOG.md | 3 +- docs/ibc/proto-docs.md | 6 + modules/core/04-channel/keeper/events.go | 2 + modules/core/04-channel/types/events.go | 1 + modules/core/04-channel/types/tx.pb.go | 265 ++++++++++++++++------- modules/core/keeper/msg_server.go | 5 +- proto/ibc/core/channel/v1/tx.proto | 5 +- 7 files changed, 203 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59091805154..6b84cecfd72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (middleware) [\#1022](https://github.com/cosmos/ibc-go/pull/1022) Add `GetAppVersion` to the ICS4Wrapper interface. This function should be used by IBC applications to obtain their own version since the version set in the channel structure may be wrapped many times by middleware. * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. -* (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. +* (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. +* (modules/core/04-channel) [\#1279](https://github.com/cosmos/ibc-go/pull/1279) Add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse. Emit channel version during OpenInit/OpenTry ### Features diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 297da93f262..cf411ade14c 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -2809,6 +2809,7 @@ MsgChannelOpenInitResponse defines the Msg/ChannelOpenInit response type. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `channel_id` | [string](#string) | | | +| `version` | [string](#string) | | | @@ -2844,6 +2845,11 @@ value will be ignored by core IBC. MsgChannelOpenTryResponse defines the Msg/ChannelOpenTry response type. +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `version` | [string](#string) | | | + + diff --git a/modules/core/04-channel/keeper/events.go b/modules/core/04-channel/keeper/events.go index d299d6afeda..731d298a2ae 100644 --- a/modules/core/04-channel/keeper/events.go +++ b/modules/core/04-channel/keeper/events.go @@ -20,6 +20,7 @@ func EmitChannelOpenInitEvent(ctx sdk.Context, portID string, channelID string, sdk.NewAttribute(types.AttributeCounterpartyPortID, channel.Counterparty.PortId), sdk.NewAttribute(types.AttributeCounterpartyChannelID, channel.Counterparty.ChannelId), sdk.NewAttribute(types.AttributeKeyConnectionID, channel.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeVersion, channel.Version), ), }) @@ -41,6 +42,7 @@ func EmitChannelOpenTryEvent(ctx sdk.Context, portID string, channelID string, c sdk.NewAttribute(types.AttributeCounterpartyPortID, channel.Counterparty.PortId), sdk.NewAttribute(types.AttributeCounterpartyChannelID, channel.Counterparty.ChannelId), sdk.NewAttribute(types.AttributeKeyConnectionID, channel.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeVersion, channel.Version), ), }) ctx.EventManager().EmitEvents(sdk.Events{ diff --git a/modules/core/04-channel/types/events.go b/modules/core/04-channel/types/events.go index 4154b856c5d..e9f909a695d 100644 --- a/modules/core/04-channel/types/events.go +++ b/modules/core/04-channel/types/events.go @@ -11,6 +11,7 @@ const ( AttributeKeyConnectionID = "connection_id" AttributeKeyPortID = "port_id" AttributeKeyChannelID = "channel_id" + AttributeVersion = "version" AttributeCounterpartyPortID = "counterparty_port_id" AttributeCounterpartyChannelID = "counterparty_channel_id" diff --git a/modules/core/04-channel/types/tx.pb.go b/modules/core/04-channel/types/tx.pb.go index 8f9ebe6ec63..fe6f344384d 100644 --- a/modules/core/04-channel/types/tx.pb.go +++ b/modules/core/04-channel/types/tx.pb.go @@ -105,6 +105,7 @@ var xxx_messageInfo_MsgChannelOpenInit proto.InternalMessageInfo // MsgChannelOpenInitResponse defines the Msg/ChannelOpenInit response type. type MsgChannelOpenInitResponse struct { ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` } func (m *MsgChannelOpenInitResponse) Reset() { *m = MsgChannelOpenInitResponse{} } @@ -147,6 +148,13 @@ func (m *MsgChannelOpenInitResponse) GetChannelId() string { return "" } +func (m *MsgChannelOpenInitResponse) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + // MsgChannelOpenInit defines a msg sent by a Relayer to try to open a channel // on Chain B. The version field within the Channel field has been deprecated. Its // value will be ignored by core IBC. @@ -198,6 +206,7 @@ var xxx_messageInfo_MsgChannelOpenTry proto.InternalMessageInfo // MsgChannelOpenTryResponse defines the Msg/ChannelOpenTry response type. type MsgChannelOpenTryResponse struct { + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` } func (m *MsgChannelOpenTryResponse) Reset() { *m = MsgChannelOpenTryResponse{} } @@ -233,6 +242,13 @@ func (m *MsgChannelOpenTryResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgChannelOpenTryResponse proto.InternalMessageInfo +func (m *MsgChannelOpenTryResponse) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + // MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge // the change of channel state to TRYOPEN on Chain B. type MsgChannelOpenAck struct { @@ -902,87 +918,88 @@ func init() { func init() { proto.RegisterFile("ibc/core/channel/v1/tx.proto", fileDescriptor_bc4637e0ac3fc7b7) } var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ - // 1275 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcd, 0x6e, 0xdb, 0x46, - 0x10, 0xd6, 0x5f, 0x64, 0x67, 0xe4, 0xda, 0x32, 0x65, 0x3b, 0x32, 0x65, 0x8b, 0x2a, 0x0f, 0xb1, - 0xe1, 0xc2, 0x52, 0x6c, 0xa7, 0x28, 0x62, 0x14, 0x28, 0x2c, 0x55, 0x41, 0x8d, 0xd6, 0x3f, 0xa0, - 0xe4, 0x02, 0x75, 0x8b, 0x0a, 0x12, 0xb5, 0x91, 0x09, 0x49, 0x5c, 0x95, 0xa4, 0x94, 0xe8, 0x0d, - 0x02, 0x9f, 0x72, 0x0e, 0x60, 0x20, 0x45, 0x4f, 0x45, 0x0f, 0xe9, 0x63, 0xe4, 0x98, 0x53, 0x5b, - 0xf4, 0x20, 0x14, 0xf6, 0xa5, 0x67, 0x3d, 0x41, 0xc1, 0xe5, 0x92, 0xa2, 0x24, 0x12, 0xa6, 0x13, - 0xdb, 0xcd, 0x6d, 0x77, 0xe6, 0xdb, 0xd9, 0xd9, 0xef, 0x1b, 0xee, 0x0f, 0x61, 0x49, 0xaa, 0x88, - 0x19, 0x11, 0x2b, 0x28, 0x23, 0x9e, 0x94, 0x65, 0x19, 0x35, 0x32, 0x9d, 0x8d, 0x8c, 0xf6, 0x2c, - 0xdd, 0x52, 0xb0, 0x86, 0x99, 0x98, 0x54, 0x11, 0xd3, 0xba, 0x37, 0x4d, 0xbd, 0xe9, 0xce, 0x06, - 0x3b, 0x57, 0xc3, 0x35, 0x4c, 0xfc, 0x19, 0xbd, 0x65, 0x40, 0x59, 0x6e, 0x10, 0xa8, 0x21, 0x21, - 0x59, 0xd3, 0xe3, 0x18, 0x2d, 0x0a, 0xf8, 0xd8, 0x69, 0x26, 0x33, 0x2c, 0x81, 0xf0, 0x3f, 0xfb, - 0x81, 0xd9, 0x53, 0x6b, 0x39, 0xc3, 0x78, 0xd0, 0x42, 0xf2, 0xae, 0x2c, 0x69, 0xcc, 0x27, 0x30, - 0xd1, 0xc2, 0x8a, 0x56, 0x92, 0xaa, 0x71, 0x7f, 0xca, 0xbf, 0x7a, 0x37, 0xcb, 0xf4, 0x7b, 0xdc, - 0x74, 0xb7, 0xdc, 0x6c, 0x6c, 0xf3, 0xd4, 0xc1, 0x0b, 0x61, 0xbd, 0xb5, 0x5b, 0x65, 0x3e, 0x87, - 0x09, 0x1a, 0x34, 0x1e, 0x48, 0xf9, 0x57, 0x23, 0x9b, 0x4b, 0x69, 0x87, 0x45, 0xa4, 0xe9, 0x1c, - 0xd9, 0xd0, 0x9b, 0x1e, 0xe7, 0x13, 0xcc, 0x21, 0xcc, 0x02, 0x84, 0x55, 0xa9, 0x26, 0x23, 0x25, - 0x1e, 0xd4, 0x67, 0x12, 0x68, 0x6f, 0x7b, 0xf2, 0xf9, 0x2b, 0xce, 0xf7, 0xef, 0x2b, 0xce, 0xc7, - 0x0b, 0xc0, 0x8e, 0xa7, 0x28, 0x20, 0xb5, 0x85, 0x65, 0x15, 0x31, 0x0f, 0x01, 0x68, 0xa8, 0x41, - 0xb6, 0xf3, 0xfd, 0x1e, 0x37, 0x6b, 0x64, 0x3b, 0xf0, 0xf1, 0xc2, 0x5d, 0xda, 0xd9, 0xad, 0xf2, - 0x7f, 0x04, 0x61, 0x76, 0x38, 0x68, 0x51, 0xe9, 0x5e, 0x6d, 0xd9, 0xfb, 0x10, 0x6b, 0x29, 0xa8, - 0x23, 0xe1, 0xb6, 0x5a, 0xb2, 0x65, 0x10, 0x20, 0x03, 0x93, 0xfd, 0x1e, 0xc7, 0xd2, 0x81, 0xe3, - 0x20, 0x5e, 0x98, 0x35, 0xad, 0x39, 0x33, 0x25, 0x3b, 0x8d, 0xc1, 0xab, 0xd3, 0x28, 0xc0, 0x9c, - 0x88, 0xdb, 0xb2, 0x86, 0x94, 0x56, 0x59, 0xd1, 0xba, 0xa5, 0x0e, 0x52, 0x54, 0x09, 0xcb, 0xf1, - 0x10, 0x49, 0x87, 0xeb, 0xf7, 0xb8, 0x04, 0x25, 0xc4, 0x01, 0xc5, 0x0b, 0x31, 0xbb, 0xf9, 0x5b, - 0xc3, 0xaa, 0x53, 0xdb, 0x52, 0x30, 0x7e, 0x52, 0x92, 0x64, 0x49, 0x8b, 0xdf, 0x49, 0xf9, 0x57, - 0xa7, 0xec, 0xd4, 0x0e, 0x7c, 0xbc, 0x70, 0x97, 0x74, 0x48, 0xed, 0x1c, 0xc3, 0x94, 0xe1, 0x39, - 0x41, 0x52, 0xed, 0x44, 0x8b, 0x87, 0xc9, 0x62, 0x58, 0xdb, 0x62, 0x8c, 0x1a, 0xed, 0x6c, 0xa4, - 0xbf, 0x22, 0x88, 0x6c, 0x42, 0x5f, 0x4a, 0xbf, 0xc7, 0xc5, 0xec, 0x71, 0x8d, 0xd1, 0xbc, 0x10, - 0x21, 0x5d, 0x03, 0x69, 0x2b, 0x96, 0x09, 0x97, 0x62, 0x49, 0xc0, 0xe2, 0x98, 0xae, 0x66, 0xad, - 0xf0, 0x7f, 0x8e, 0xa9, 0xbe, 0x23, 0xd6, 0xaf, 0xa6, 0xfa, 0x70, 0xb9, 0x05, 0xbc, 0x95, 0x1b, - 0x73, 0x0c, 0xf7, 0x86, 0x78, 0xb7, 0x85, 0x20, 0x55, 0x9f, 0xe5, 0xfb, 0x3d, 0x2e, 0xe9, 0x20, - 0x90, 0x3d, 0xde, 0xbc, 0xdd, 0x33, 0xa8, 0x9b, 0x9b, 0x50, 0x7e, 0x03, 0x0c, 0x41, 0x4b, 0x9a, - 0xd2, 0xa5, 0xc2, 0xcf, 0xf5, 0x7b, 0x5c, 0xd4, 0x2e, 0x90, 0xa6, 0x74, 0x79, 0x61, 0x92, 0xb4, - 0xf5, 0x6f, 0xe7, 0x03, 0x93, 0x7d, 0x47, 0xac, 0x5b, 0xb2, 0xff, 0x16, 0x80, 0xf9, 0x61, 0x6f, - 0x0e, 0xcb, 0x4f, 0x24, 0xa5, 0x79, 0x1b, 0xd2, 0x5b, 0x54, 0x96, 0xc5, 0x3a, 0x11, 0xdb, 0x81, - 0xca, 0xb2, 0x58, 0x37, 0xa9, 0xd4, 0x0b, 0x72, 0x94, 0xca, 0xd0, 0x8d, 0x50, 0x79, 0xc7, 0x85, - 0x4a, 0x0e, 0x96, 0x1d, 0xc9, 0xb2, 0xe8, 0x7c, 0xe9, 0x87, 0xd8, 0x00, 0x91, 0x6b, 0x60, 0x15, - 0x5d, 0xfd, 0xd0, 0x78, 0x37, 0x32, 0x2f, 0x3f, 0x2c, 0x96, 0x21, 0xe1, 0x90, 0x9b, 0x95, 0xfb, - 0xeb, 0x00, 0x2c, 0x8c, 0xf8, 0x6f, 0xb1, 0x16, 0x86, 0x37, 0xd4, 0xe0, 0x3b, 0x6e, 0xa8, 0xb7, - 0x5b, 0x0e, 0x29, 0x48, 0x3a, 0x13, 0x66, 0x71, 0xfa, 0x22, 0x00, 0x1f, 0xed, 0xa9, 0x35, 0x01, - 0x89, 0x9d, 0xc3, 0xb2, 0x58, 0x47, 0x1a, 0xf3, 0x08, 0xc2, 0x2d, 0xd2, 0x22, 0x4c, 0x46, 0x36, - 0x13, 0x8e, 0x27, 0x99, 0x01, 0xa6, 0x07, 0x19, 0x1d, 0xc0, 0x3c, 0x86, 0xa8, 0x91, 0xae, 0x88, - 0x9b, 0x4d, 0x49, 0x6b, 0x22, 0x59, 0x23, 0xf4, 0x4e, 0x65, 0x13, 0xfd, 0x1e, 0x77, 0xcf, 0xbe, - 0xa0, 0x01, 0x82, 0x17, 0x66, 0x88, 0x29, 0x67, 0x59, 0xc6, 0x48, 0x0b, 0xde, 0x08, 0x69, 0x21, - 0x17, 0xd2, 0x7e, 0x24, 0x1b, 0xce, 0x80, 0x11, 0xeb, 0xb6, 0xf2, 0x05, 0x84, 0x15, 0xa4, 0xb6, - 0x1b, 0x06, 0x33, 0xd3, 0x9b, 0x2b, 0x8e, 0xcc, 0x98, 0x70, 0x81, 0x40, 0x8b, 0xdd, 0x16, 0x12, - 0xe8, 0xb0, 0xed, 0x90, 0x3e, 0x07, 0xff, 0x77, 0x00, 0x60, 0x4f, 0xad, 0x15, 0xa5, 0x26, 0xc2, - 0xed, 0xeb, 0xe1, 0xbb, 0x2d, 0x2b, 0x48, 0x44, 0x52, 0x07, 0x55, 0xdd, 0xf8, 0x1e, 0x20, 0x4c, - 0xbe, 0x8f, 0x2c, 0xcb, 0x8d, 0xf2, 0xfd, 0x35, 0x30, 0x32, 0x7a, 0xa6, 0x95, 0x54, 0xf4, 0x53, - 0x1b, 0xc9, 0x22, 0x2a, 0x29, 0x48, 0xec, 0x10, 0xee, 0x43, 0xd9, 0xe5, 0x7e, 0x8f, 0x5b, 0x34, - 0x22, 0x8c, 0x63, 0x78, 0x21, 0xaa, 0x1b, 0x0b, 0xd4, 0xa6, 0xeb, 0xe1, 0xa1, 0xe2, 0xbf, 0x27, - 0x57, 0x62, 0xca, 0xed, 0x75, 0x2b, 0xf7, 0xd2, 0xb8, 0x82, 0xd0, 0xe8, 0x07, 0x32, 0xf9, 0xa2, - 0x3e, 0x04, 0x01, 0x3f, 0x83, 0x08, 0xfd, 0xac, 0xf4, 0x8c, 0xe8, 0xe6, 0xb4, 0xd0, 0xef, 0x71, - 0xcc, 0xd0, 0x37, 0xa7, 0x3b, 0x79, 0xc1, 0xd8, 0xc6, 0x8c, 0xdc, 0x6f, 0x72, 0x7b, 0x72, 0x56, - 0xfe, 0xce, 0xfb, 0x2a, 0x1f, 0x76, 0x51, 0xbe, 0x42, 0x6e, 0x11, 0xc3, 0xda, 0x5c, 0x77, 0x01, - 0xfc, 0x1e, 0x20, 0xe5, 0xb5, 0x23, 0xd6, 0x65, 0xfc, 0xb4, 0x81, 0xaa, 0x35, 0x44, 0xf6, 0xab, - 0xf7, 0xa8, 0x80, 0x55, 0x98, 0x29, 0x0f, 0x47, 0x33, 0x0a, 0x40, 0x18, 0x35, 0x0f, 0x34, 0xd6, - 0x07, 0x56, 0xdd, 0x34, 0x26, 0x4e, 0x53, 0xe3, 0x1d, 0xbd, 0xf3, 0x3f, 0x1f, 0x41, 0x22, 0x79, - 0x00, 0x8e, 0x30, 0x76, 0xcd, 0xba, 0xac, 0xfd, 0xea, 0x07, 0x66, 0x1c, 0xc4, 0x7c, 0x0a, 0x29, - 0x21, 0x5f, 0x38, 0x3c, 0xd8, 0x2f, 0xe4, 0x4b, 0x42, 0xbe, 0x70, 0xf4, 0x4d, 0xb1, 0x54, 0xfc, - 0xee, 0x30, 0x5f, 0x3a, 0xda, 0x2f, 0x1c, 0xe6, 0x73, 0xbb, 0x8f, 0x77, 0xf3, 0x5f, 0x46, 0x7d, - 0xec, 0xcc, 0xe9, 0x59, 0x2a, 0x62, 0x33, 0x31, 0x2b, 0xb0, 0xe8, 0x38, 0x6c, 0xff, 0xe0, 0xe0, - 0x30, 0xea, 0x67, 0x27, 0x4f, 0xcf, 0x52, 0x21, 0xbd, 0xcd, 0xac, 0xc3, 0x92, 0x23, 0xb0, 0x70, - 0x94, 0xcb, 0xe5, 0x0b, 0x85, 0x68, 0x80, 0x8d, 0x9c, 0x9e, 0xa5, 0x26, 0x68, 0x97, 0x0d, 0x3d, - 0xff, 0x25, 0xe9, 0xdb, 0x7c, 0x3d, 0x09, 0xc1, 0x3d, 0xb5, 0xc6, 0xd4, 0x61, 0x66, 0xf4, 0xe5, - 0xee, 0xbc, 0xfa, 0xf1, 0xf7, 0x33, 0x9b, 0xf1, 0x08, 0xb4, 0x78, 0x3e, 0x81, 0xe9, 0x91, 0xe7, - 0xf2, 0x7d, 0x0f, 0x21, 0x8a, 0x4a, 0x97, 0x4d, 0x7b, 0xc3, 0xb9, 0xcc, 0xa4, 0xdf, 0x88, 0xbd, - 0xcc, 0xb4, 0x23, 0xd6, 0x3d, 0xcd, 0x64, 0x7b, 0x19, 0x30, 0x1a, 0x30, 0x0e, 0xaf, 0x82, 0x35, - 0x0f, 0x51, 0x28, 0x96, 0xdd, 0xf4, 0x8e, 0xb5, 0x66, 0x95, 0x21, 0x3a, 0x76, 0x79, 0x5e, 0xbd, - 0x24, 0x8e, 0x85, 0x64, 0x1f, 0x78, 0x45, 0x5a, 0xf3, 0x3d, 0x85, 0x98, 0xe3, 0x85, 0xd7, 0x4b, - 0x20, 0x73, 0x9d, 0x5b, 0x57, 0x00, 0x5b, 0x13, 0xff, 0x00, 0x60, 0xbb, 0x15, 0xf2, 0x6e, 0x21, - 0x06, 0x18, 0x76, 0xed, 0x72, 0x8c, 0x15, 0xbd, 0x00, 0x13, 0xe6, 0x05, 0x88, 0x73, 0x1b, 0x46, - 0x01, 0xec, 0xca, 0x25, 0x00, 0x7b, 0xed, 0x8d, 0x9c, 0xcd, 0xf7, 0x2f, 0x19, 0x4a, 0x71, 0xee, - 0xb5, 0xe7, 0x72, 0x9e, 0xd4, 0x61, 0x66, 0xf4, 0x10, 0x70, 0xcd, 0x72, 0x04, 0xe8, 0xfe, 0xf1, - 0xba, 0x6c, 0x92, 0xd9, 0xc2, 0x9b, 0xf3, 0xa4, 0xff, 0xed, 0x79, 0xd2, 0xff, 0xcf, 0x79, 0xd2, - 0xff, 0xe2, 0x22, 0xe9, 0x7b, 0x7b, 0x91, 0xf4, 0xfd, 0x75, 0x91, 0xf4, 0x1d, 0x3f, 0xaa, 0x49, - 0xda, 0x49, 0xbb, 0x92, 0x16, 0x71, 0x33, 0x23, 0x62, 0xb5, 0x89, 0xd5, 0x8c, 0x54, 0x11, 0xd7, - 0x6b, 0x38, 0xd3, 0xd9, 0xca, 0x34, 0x71, 0xb5, 0xdd, 0x40, 0xaa, 0xf1, 0x13, 0xf1, 0xc1, 0xc3, - 0x75, 0xf3, 0x3f, 0xa2, 0xd6, 0x6d, 0x21, 0xb5, 0x12, 0x26, 0xff, 0x10, 0xb7, 0xfe, 0x0b, 0x00, - 0x00, 0xff, 0xff, 0xec, 0xba, 0x10, 0x62, 0xd2, 0x14, 0x00, 0x00, + // 1294 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4d, 0x6f, 0xe2, 0x56, + 0x17, 0xc6, 0x40, 0x20, 0x39, 0xe4, 0x4d, 0x88, 0x49, 0x32, 0xc4, 0x24, 0x98, 0xd7, 0x8b, 0x49, + 0x94, 0x2a, 0x30, 0x49, 0x66, 0x54, 0x4d, 0x54, 0xa9, 0x0a, 0x94, 0x51, 0xa3, 0x36, 0x1f, 0x32, + 0xa4, 0x52, 0xd3, 0xaa, 0x08, 0xcc, 0x1d, 0x62, 0x01, 0x36, 0xb5, 0x0d, 0x33, 0xfc, 0x83, 0x51, + 0x56, 0xb3, 0x1e, 0x29, 0xd2, 0x54, 0x5d, 0x55, 0x5d, 0x4c, 0x7f, 0xc6, 0x2c, 0x67, 0xd5, 0x56, + 0x5d, 0xa0, 0x2a, 0xd9, 0x74, 0xcd, 0x2f, 0xa8, 0x7c, 0x7d, 0x6d, 0x0c, 0xd8, 0x8a, 0x33, 0x93, + 0x64, 0xba, 0xf3, 0xbd, 0xe7, 0xb9, 0xe7, 0x9c, 0xfb, 0x9c, 0xe7, 0x7e, 0x19, 0x96, 0xc5, 0x8a, + 0x90, 0x11, 0x64, 0x05, 0x65, 0x84, 0xd3, 0xb2, 0x24, 0xa1, 0x46, 0xa6, 0xb3, 0x99, 0xd1, 0x9e, + 0xa7, 0x5b, 0x8a, 0xac, 0xc9, 0x74, 0x4c, 0xac, 0x08, 0x69, 0xdd, 0x9a, 0x26, 0xd6, 0x74, 0x67, + 0x93, 0x99, 0xaf, 0xc9, 0x35, 0x19, 0xdb, 0x33, 0xfa, 0x97, 0x01, 0x65, 0xd8, 0x81, 0xa3, 0x86, + 0x88, 0x24, 0x4d, 0xf7, 0x63, 0x7c, 0x11, 0xc0, 0xff, 0x9d, 0x22, 0x99, 0x6e, 0x31, 0x84, 0xfb, + 0x89, 0x02, 0x7a, 0x5f, 0xad, 0xe5, 0x8c, 0xce, 0xc3, 0x16, 0x92, 0xf6, 0x24, 0x51, 0xa3, 0x3f, + 0x81, 0x70, 0x4b, 0x56, 0xb4, 0x92, 0x58, 0x8d, 0x53, 0x29, 0x6a, 0x6d, 0x2a, 0x4b, 0xf7, 0x7b, + 0xec, 0x4c, 0xb7, 0xdc, 0x6c, 0xec, 0x70, 0xc4, 0xc0, 0xf1, 0x21, 0xfd, 0x6b, 0xaf, 0x4a, 0x7f, + 0x06, 0x61, 0xe2, 0x34, 0xee, 0x4f, 0x51, 0x6b, 0x91, 0xad, 0xe5, 0xb4, 0xc3, 0x24, 0xd2, 0x24, + 0x46, 0x36, 0xf8, 0xb6, 0xc7, 0xfa, 0x78, 0x73, 0x08, 0xbd, 0x08, 0x21, 0x55, 0xac, 0x49, 0x48, + 0x89, 0x07, 0xf4, 0x48, 0x3c, 0x69, 0xed, 0x4c, 0xbe, 0x78, 0xcd, 0xfa, 0xfe, 0x79, 0xcd, 0xfa, + 0xb8, 0x06, 0x30, 0xe3, 0x29, 0xf2, 0x48, 0x6d, 0xc9, 0x92, 0x8a, 0xe8, 0x87, 0x00, 0xc4, 0xd5, + 0x20, 0xdb, 0x85, 0x7e, 0x8f, 0x9d, 0x33, 0xb2, 0x1d, 0xd8, 0x38, 0x7e, 0x8a, 0x34, 0xf6, 0xaa, + 0x74, 0x1c, 0xc2, 0x1d, 0xa4, 0xa8, 0xa2, 0x2c, 0xe1, 0x9c, 0xa7, 0x78, 0xb3, 0xc9, 0xfd, 0x1e, + 0x80, 0xb9, 0xe1, 0x70, 0x45, 0xa5, 0x7b, 0x3d, 0x42, 0x0e, 0x20, 0xd6, 0x52, 0x50, 0x47, 0x94, + 0xdb, 0x6a, 0xc9, 0x96, 0x1b, 0x0e, 0x94, 0x4d, 0xf6, 0x7b, 0x2c, 0x43, 0x06, 0x8e, 0x83, 0x38, + 0x7e, 0xce, 0xec, 0xcd, 0x59, 0xc9, 0xda, 0x08, 0x0e, 0x5c, 0x9f, 0x60, 0x1e, 0xe6, 0x05, 0xb9, + 0x2d, 0x69, 0x48, 0x69, 0x95, 0x15, 0xad, 0x5b, 0x32, 0xe7, 0x1d, 0xc4, 0xe9, 0xb0, 0xfd, 0x1e, + 0x9b, 0x20, 0x54, 0x39, 0xa0, 0x38, 0x3e, 0x66, 0xef, 0xfe, 0xc6, 0xe8, 0xd5, 0x49, 0x6f, 0x29, + 0xb2, 0xfc, 0xb4, 0x24, 0x4a, 0xa2, 0x16, 0x9f, 0x48, 0x51, 0x6b, 0xd3, 0x76, 0xd2, 0x07, 0x36, + 0x8e, 0x9f, 0xc2, 0x0d, 0xac, 0xaa, 0x13, 0x98, 0x36, 0x2c, 0xa7, 0x48, 0xac, 0x9d, 0x6a, 0xf1, + 0x10, 0x9e, 0x0c, 0x63, 0x9b, 0x8c, 0xa1, 0xde, 0xce, 0x66, 0xfa, 0x4b, 0x8c, 0xc8, 0x26, 0xf4, + 0xa9, 0xf4, 0x7b, 0x6c, 0xcc, 0xee, 0xd7, 0x18, 0xcd, 0xf1, 0x11, 0xdc, 0x34, 0x90, 0x36, 0x19, + 0x85, 0x5d, 0x64, 0xf4, 0x08, 0x96, 0xc6, 0xea, 0x6a, 0xa9, 0xc8, 0xa6, 0x07, 0x6a, 0x58, 0x0f, + 0x7f, 0x8c, 0xe9, 0x61, 0x57, 0xa8, 0x5f, 0x4f, 0x0f, 0xc3, 0x12, 0xf5, 0x7b, 0x94, 0xe8, 0x09, + 0xdc, 0x1b, 0xaa, 0x88, 0xcd, 0x05, 0x5e, 0x29, 0x59, 0xae, 0xdf, 0x63, 0x93, 0x0e, 0xa5, 0xb3, + 0xfb, 0x5b, 0xb0, 0x5b, 0x06, 0x8a, 0xba, 0x0d, 0x4d, 0x6c, 0x82, 0x51, 0xea, 0x92, 0xa6, 0x74, + 0x89, 0x24, 0xe6, 0xfb, 0x3d, 0x36, 0x6a, 0x2f, 0x9d, 0xa6, 0x74, 0x39, 0x7e, 0x12, 0x7f, 0xeb, + 0xab, 0xea, 0xe3, 0x0a, 0x22, 0x31, 0x2a, 0x88, 0x5d, 0xa1, 0x6e, 0x0a, 0x82, 0xfb, 0xd5, 0x0f, + 0x0b, 0xc3, 0xd6, 0x9c, 0x2c, 0x3d, 0x15, 0x95, 0xe6, 0x5d, 0x94, 0xde, 0xa2, 0xb2, 0x2c, 0xd4, + 0x71, 0xb1, 0x1d, 0xa8, 0x2c, 0x0b, 0x75, 0x93, 0x4a, 0x5d, 0x90, 0xa3, 0x54, 0x06, 0x6f, 0x85, + 0xca, 0x09, 0x17, 0x2a, 0x59, 0x58, 0x71, 0x24, 0xcb, 0xa2, 0xf3, 0x15, 0x05, 0xb1, 0x01, 0x22, + 0xd7, 0x90, 0x55, 0x74, 0xfd, 0x83, 0xe6, 0xfd, 0xc8, 0xbc, 0xfa, 0x80, 0x59, 0x81, 0x84, 0x43, + 0x6e, 0x56, 0xee, 0x6f, 0xfc, 0xb0, 0x38, 0x62, 0xbf, 0x43, 0x2d, 0x0c, 0x6f, 0xb5, 0x81, 0xf7, + 0xdc, 0x6a, 0xef, 0x56, 0x0e, 0x29, 0x48, 0x3a, 0x13, 0x66, 0x71, 0xfa, 0xd2, 0x0f, 0xff, 0xdb, + 0x57, 0x6b, 0x3c, 0x12, 0x3a, 0x47, 0x65, 0xa1, 0x8e, 0x34, 0xfa, 0x31, 0x84, 0x5a, 0xf8, 0x0b, + 0x33, 0x19, 0xd9, 0x4a, 0x38, 0x9e, 0x71, 0x06, 0x98, 0x1c, 0x71, 0x64, 0x00, 0xfd, 0x04, 0xa2, + 0x46, 0xba, 0x82, 0xdc, 0x6c, 0x8a, 0x5a, 0x13, 0x49, 0x1a, 0xa6, 0x77, 0x3a, 0x9b, 0xe8, 0xf7, + 0xd8, 0x7b, 0xf6, 0x09, 0x0d, 0x10, 0x1c, 0x3f, 0x8b, 0xbb, 0x72, 0x56, 0xcf, 0x18, 0x69, 0x81, + 0x5b, 0x21, 0x2d, 0xe8, 0x42, 0xda, 0x0f, 0x78, 0xc3, 0x19, 0x30, 0x62, 0x9d, 0x4d, 0x9f, 0x43, + 0x48, 0x41, 0x6a, 0xbb, 0x61, 0x30, 0x33, 0xb3, 0xb5, 0xea, 0xc8, 0x8c, 0x09, 0xe7, 0x31, 0xb4, + 0xd8, 0x6d, 0x21, 0x9e, 0x0c, 0xdb, 0x09, 0xea, 0x31, 0xb8, 0xbf, 0xfc, 0x00, 0xfb, 0x6a, 0xad, + 0x28, 0x36, 0x91, 0xdc, 0xbe, 0x19, 0xbe, 0xdb, 0x92, 0x82, 0x04, 0x24, 0x76, 0x50, 0xd5, 0x8d, + 0xef, 0x01, 0xc2, 0xe4, 0xfb, 0xd8, 0xea, 0xb9, 0x55, 0xbe, 0xbf, 0x02, 0x5a, 0x42, 0xcf, 0xb5, + 0x92, 0x8a, 0x7e, 0x6c, 0x23, 0x49, 0x40, 0x25, 0x05, 0x09, 0x1d, 0xcc, 0x7d, 0x30, 0xbb, 0xd2, + 0xef, 0xb1, 0x4b, 0x86, 0x87, 0x71, 0x0c, 0xc7, 0x47, 0xf5, 0xce, 0x02, 0xe9, 0xd3, 0xeb, 0xe1, + 0x41, 0xf1, 0xdf, 0xe1, 0x6b, 0x34, 0xe1, 0xf6, 0xa6, 0x2b, 0xf7, 0xca, 0xb8, 0x82, 0x10, 0xef, + 0x87, 0x12, 0x5e, 0x51, 0xff, 0x85, 0x02, 0x7e, 0x0a, 0x11, 0xb2, 0xac, 0xf4, 0x8c, 0xc8, 0xe6, + 0xb4, 0xd8, 0xef, 0xb1, 0xf4, 0xd0, 0x9a, 0xd3, 0x8d, 0x1c, 0x6f, 0x6c, 0x63, 0x46, 0xee, 0xb7, + 0xb9, 0x3d, 0x39, 0x57, 0x7e, 0xe2, 0x43, 0x2b, 0x1f, 0x72, 0xa9, 0x7c, 0x05, 0xdf, 0x22, 0x86, + 0x6b, 0x73, 0xd3, 0x02, 0xf8, 0xcd, 0x8f, 0xe5, 0xb5, 0x2b, 0xd4, 0x25, 0xf9, 0x59, 0x03, 0x55, + 0x6b, 0x08, 0xef, 0x57, 0x1f, 0xa0, 0x80, 0x35, 0x98, 0x2d, 0x0f, 0x7b, 0x33, 0x04, 0xc0, 0x8f, + 0x76, 0x0f, 0x6a, 0xac, 0x0f, 0xac, 0xba, 0xd5, 0x18, 0x1b, 0xcd, 0x1a, 0xef, 0xea, 0x8d, 0x8f, + 0x7c, 0x04, 0x09, 0xf8, 0xd1, 0x38, 0xc2, 0xd8, 0x0d, 0xd7, 0x65, 0xfd, 0x17, 0x0a, 0xe8, 0x71, + 0x10, 0xfd, 0x08, 0x52, 0x7c, 0xbe, 0x70, 0x74, 0x78, 0x50, 0xc8, 0x97, 0xf8, 0x7c, 0xe1, 0xf8, + 0xeb, 0x62, 0xa9, 0xf8, 0xed, 0x51, 0xbe, 0x74, 0x7c, 0x50, 0x38, 0xca, 0xe7, 0xf6, 0x9e, 0xec, + 0xe5, 0xbf, 0x88, 0xfa, 0x98, 0xd9, 0xb3, 0xf3, 0x54, 0xc4, 0xd6, 0x45, 0xaf, 0xc2, 0x92, 0xe3, + 0xb0, 0x83, 0xc3, 0xc3, 0xa3, 0x28, 0xc5, 0x4c, 0x9e, 0x9d, 0xa7, 0x82, 0xfa, 0x37, 0xbd, 0x01, + 0xcb, 0x8e, 0xc0, 0xc2, 0x71, 0x2e, 0x97, 0x2f, 0x14, 0xa2, 0x7e, 0x26, 0x72, 0x76, 0x9e, 0x0a, + 0x93, 0x26, 0x13, 0x7c, 0xf1, 0x73, 0xd2, 0xb7, 0xf5, 0x66, 0x12, 0x02, 0xfb, 0x6a, 0x8d, 0xae, + 0xc3, 0xec, 0xe8, 0x6b, 0xdf, 0x79, 0xf6, 0xe3, 0x6f, 0x6e, 0x26, 0xe3, 0x11, 0x68, 0xf1, 0x7c, + 0x0a, 0x33, 0x23, 0x0f, 0xe9, 0xfb, 0x1e, 0x5c, 0x14, 0x95, 0x2e, 0x93, 0xf6, 0x86, 0x73, 0x89, + 0xa4, 0xdf, 0x88, 0xbd, 0x44, 0xda, 0x15, 0xea, 0x9e, 0x22, 0xd9, 0x5e, 0x06, 0xb4, 0x06, 0xb4, + 0xc3, 0xab, 0x60, 0xdd, 0x83, 0x17, 0x82, 0x65, 0xb6, 0xbc, 0x63, 0xad, 0xa8, 0x12, 0x44, 0xc7, + 0x2e, 0xcf, 0x6b, 0x57, 0xf8, 0xb1, 0x90, 0xcc, 0x03, 0xaf, 0x48, 0x2b, 0xde, 0x33, 0x88, 0x39, + 0x5e, 0x78, 0xbd, 0x38, 0x32, 0xe7, 0xb9, 0x7d, 0x0d, 0xb0, 0x15, 0xf8, 0x7b, 0x00, 0xdb, 0xad, + 0x90, 0x73, 0x73, 0x31, 0xc0, 0x30, 0xeb, 0x57, 0x63, 0x2c, 0xef, 0x05, 0x08, 0x9b, 0x17, 0x20, + 0xd6, 0x6d, 0x18, 0x01, 0x30, 0xab, 0x57, 0x00, 0xec, 0xda, 0x1b, 0x39, 0x9b, 0xef, 0x5f, 0x31, + 0x94, 0xe0, 0xdc, 0xb5, 0xe7, 0x72, 0x9e, 0xd4, 0x61, 0x76, 0xf4, 0x10, 0x70, 0xcd, 0x72, 0x04, + 0xe8, 0xbe, 0x78, 0x5d, 0x36, 0xc9, 0x6c, 0xe1, 0xed, 0x45, 0x92, 0x7a, 0x77, 0x91, 0xa4, 0xfe, + 0xbe, 0x48, 0x52, 0x2f, 0x2f, 0x93, 0xbe, 0x77, 0x97, 0x49, 0xdf, 0x9f, 0x97, 0x49, 0xdf, 0xc9, + 0xe3, 0x9a, 0xa8, 0x9d, 0xb6, 0x2b, 0x69, 0x41, 0x6e, 0x66, 0x04, 0x59, 0x6d, 0xca, 0x6a, 0x46, + 0xac, 0x08, 0x1b, 0x35, 0x39, 0xd3, 0xd9, 0xce, 0x34, 0xe5, 0x6a, 0xbb, 0x81, 0x54, 0xe3, 0xc7, + 0xe3, 0x83, 0x87, 0x1b, 0xe6, 0xbf, 0x47, 0xad, 0xdb, 0x42, 0x6a, 0x25, 0x84, 0xff, 0x3b, 0x6e, + 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x51, 0x2e, 0xf7, 0xe5, 0x06, 0x15, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1478,6 +1495,13 @@ func (m *MsgChannelOpenInitResponse) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintTx(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0x12 + } if len(m.ChannelId) > 0 { i -= len(m.ChannelId) copy(dAtA[i:], m.ChannelId) @@ -1586,6 +1610,13 @@ func (m *MsgChannelOpenTryResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintTx(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0xa + } return len(dAtA) - i, nil } @@ -2326,6 +2357,10 @@ func (m *MsgChannelOpenInitResponse) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + l = len(m.Version) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } return n } @@ -2368,6 +2403,10 @@ func (m *MsgChannelOpenTryResponse) Size() (n int) { } var l int _ = l + l = len(m.Version) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } return n } @@ -2877,6 +2916,38 @@ func (m *MsgChannelOpenInitResponse) Unmarshal(dAtA []byte) error { } m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -3205,6 +3276,38 @@ func (m *MsgChannelOpenTryResponse) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: MsgChannelOpenTryResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index be18391c698..e8b7c0fd254 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -194,6 +194,7 @@ func (k Keeper) ChannelOpenInit(goCtx context.Context, msg *channeltypes.MsgChan return &channeltypes.MsgChannelOpenInitResponse{ ChannelId: channelID, + Version: msg.Channel.Version, }, nil } @@ -232,7 +233,9 @@ func (k Keeper) ChannelOpenTry(goCtx context.Context, msg *channeltypes.MsgChann // Write channel into state k.ChannelKeeper.WriteOpenTryChannel(ctx, msg.PortId, channelID, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.Channel.Counterparty, version) - return &channeltypes.MsgChannelOpenTryResponse{}, nil + return &channeltypes.MsgChannelOpenTryResponse{ + Version: version, + }, nil } // ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck. diff --git a/proto/ibc/core/channel/v1/tx.proto b/proto/ibc/core/channel/v1/tx.proto index 15714173a1a..d34b00e9124 100644 --- a/proto/ibc/core/channel/v1/tx.proto +++ b/proto/ibc/core/channel/v1/tx.proto @@ -68,6 +68,7 @@ message MsgChannelOpenInit { // MsgChannelOpenInitResponse defines the Msg/ChannelOpenInit response type. message MsgChannelOpenInitResponse { string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string version = 2; } // MsgChannelOpenInit defines a msg sent by a Relayer to try to open a channel @@ -91,7 +92,9 @@ message MsgChannelOpenTry { } // MsgChannelOpenTryResponse defines the Msg/ChannelOpenTry response type. -message MsgChannelOpenTryResponse {} +message MsgChannelOpenTryResponse { + string version = 1; +} // MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge // the change of channel state to TRYOPEN on Chain B. From 21c77444ec0473329d767375851bf3f609e8d82f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Apr 2022 19:44:54 +0200 Subject: [PATCH 089/275] build(deps): bump github/codeql-action from 1 to 2 (#1289) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v1...v2) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 11d7c0e90bb..d6f53753177 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -49,7 +49,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -61,7 +61,7 @@ jobs: # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -75,5 +75,5 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 if: env.GIT_DIFF From 2239625b7842be9ffc802437ce02b33c1703f1e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Apr 2022 14:50:48 +0200 Subject: [PATCH 090/275] build(deps): bump google.golang.org/grpc from 1.45.0 to 1.46.0 (#1290) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.45.0 to 1.46.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.45.0...v1.46.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4f56c03dd9e..93b896af533 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac - google.golang.org/grpc v1.45.0 + google.golang.org/grpc v1.46.0 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index a8f6d150085..5e4189ab15a 100644 --- a/go.sum +++ b/go.sum @@ -297,6 +297,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= @@ -1587,8 +1588,9 @@ google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From bace9885f56e30daf00266f954764bcfcd667fbf Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 26 Apr 2022 20:47:12 +0200 Subject: [PATCH 091/275] fixing dead links from sdk default branch update (#1301) --- docs/apps/interchain-accounts/transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/apps/interchain-accounts/transactions.md b/docs/apps/interchain-accounts/transactions.md index a78a917387f..e17571a6e00 100644 --- a/docs/apps/interchain-accounts/transactions.md +++ b/docs/apps/interchain-accounts/transactions.md @@ -16,6 +16,6 @@ Transactions are executed via the ICS27 [`SendTx` API](./auth-modules.md#trysend ## Atomicity -As the Interchain Accounts module supports the execution of multiple transactions using the Cosmos SDK `Msg` interface, it provides the same atomicity guarantees as Cosmos SDK-based applications, leveraging the [`CacheMultiStore`](https://docs.cosmos.network/master/core/store.html#cachemultistore) architecture provided by the [`Context`](https://docs.cosmos.network/master/core/context.html) type. +As the Interchain Accounts module supports the execution of multiple transactions using the Cosmos SDK `Msg` interface, it provides the same atomicity guarantees as Cosmos SDK-based applications, leveraging the [`CacheMultiStore`](https://docs.cosmos.network/main/core/store.html#cachemultistore) architecture provided by the [`Context`](https://docs.cosmos.network/main/core/context.html) type. This provides atomic execution of transactions when using Interchain Accounts, where state changes are only committed if all `Msg`s succeed. From 9aea0fe5a2098fa104b461c7fd322e5303484514 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 27 Apr 2022 12:19:24 +0200 Subject: [PATCH 092/275] change fee version string to make it consistent with transfer version (#1305) * change version to make it consistent with transfer version * add changelog entry --- CHANGELOG.md | 1 + modules/apps/29-fee/types/keys.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b84cecfd72..1a19e914587 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. * (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. * (modules/core/04-channel) [\#1279](https://github.com/cosmos/ibc-go/pull/1279) Add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse. Emit channel version during OpenInit/OpenTry +* (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` ### Features diff --git a/modules/apps/29-fee/types/keys.go b/modules/apps/29-fee/types/keys.go index 188a75e7ac3..87318496a37 100644 --- a/modules/apps/29-fee/types/keys.go +++ b/modules/apps/29-fee/types/keys.go @@ -23,7 +23,7 @@ const ( // QuerierRoute is the querier route for IBC fee module QuerierRoute = ModuleName - Version = "fee29-1" + Version = "ics29-1" // FeeEnabledPrefix is the key prefix for storing fee enabled flag FeeEnabledKeyPrefix = "feeEnabled" From 0a98ac6490d95b61e2b9500fe6e5af131f23614c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Apr 2022 10:08:13 +0200 Subject: [PATCH 093/275] build(deps): bump github.com/armon/go-metrics from 0.3.10 to 0.3.11 (#1306) Bumps [github.com/armon/go-metrics](https://github.com/armon/go-metrics) from 0.3.10 to 0.3.11. - [Release notes](https://github.com/armon/go-metrics/releases) - [Commits](https://github.com/armon/go-metrics/compare/v0.3.10...v0.3.11) --- updated-dependencies: - dependency-name: github.com/armon/go-metrics dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 93b896af533..2245322cb94 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ module github.com/cosmos/ibc-go/v3 replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 require ( - github.com/armon/go-metrics v0.3.10 + github.com/armon/go-metrics v0.3.11 github.com/confio/ics23/go v0.7.0 github.com/cosmos/cosmos-sdk v0.45.3 github.com/gogo/protobuf v1.3.3 diff --git a/go.sum b/go.sum index 5e4189ab15a..e8eca38e6b0 100644 --- a/go.sum +++ b/go.sum @@ -128,8 +128,9 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-metrics v0.3.10 h1:FR+drcQStOe+32sYyJYyZ7FIdgoGGBnwLl+flodp8Uo= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.3.11 h1:/q4zqTAH+/mtFjimfc0SC7yuuxZshlS4TaCeBm+7sZ0= +github.com/armon/go-metrics v0.3.11/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= From cc4cd7b9cfe437c5d848e4f65b53c54a13a10fee Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 28 Apr 2022 18:17:21 +0200 Subject: [PATCH 094/275] refactor: cleanup middleware stacks (#1248) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: UX improvements for middleware * fix: move fee keeper * fix: remove unncessary wrapping * refactor: ica module stack setup * fix: define icaControllerStack as type porttypes.IBCModule * add back controller routing for port * refactor: remove unncessary SendPacket * refactor: panic instead of return nil * refactor: changing structure to init all keepers, then stacks & routing * docs: add comments * nit: comment * chore: rename files * chore: comment + nit * refactor: stacks * Update modules/apps/27-interchain-accounts/controller/ibc_middleware.go Co-authored-by: Aditya * nits: nits * chore: comment * chore: chore Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Aditya --- .../{ibc_module.go => ibc_middleware.go} | 75 ++++++---- ..._module_test.go => ibc_middleware_test.go} | 2 +- modules/apps/27-interchain-accounts/module.go | 2 - .../{ibc_module.go => ibc_middleware.go} | 74 ++++++---- ..._module_test.go => ibc_middleware_test.go} | 2 +- modules/apps/29-fee/module.go | 2 - testing/simapp/app.go | 137 ++++++++++++------ 7 files changed, 191 insertions(+), 103 deletions(-) rename modules/apps/27-interchain-accounts/controller/{ibc_module.go => ibc_middleware.go} (67%) rename modules/apps/27-interchain-accounts/controller/{ibc_module_test.go => ibc_middleware_test.go} (99%) rename modules/apps/29-fee/{ibc_module.go => ibc_middleware.go} (82%) rename modules/apps/29-fee/{ibc_module_test.go => ibc_middleware_test.go} (99%) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go similarity index 67% rename from modules/apps/27-interchain-accounts/controller/ibc_module.go rename to modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 325ec70959b..c12f5d3e9ce 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -13,27 +13,30 @@ import ( ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" ) -// IBCModule implements the ICS26 interface for interchain accounts controller chains -type IBCModule struct { - keeper keeper.Keeper +var _ porttypes.Middleware = &IBCMiddleware{} + +// IBCMiddleware implements the ICS26 callbacks for the fee middleware given the +// ICA controller keeper and the underlying application. +type IBCMiddleware struct { app porttypes.IBCModule + keeper keeper.Keeper } -// NewIBCModule creates a new IBCModule given the associated keeper and underlying application -func NewIBCModule(k keeper.Keeper, app porttypes.IBCModule) IBCModule { - return IBCModule{ - keeper: k, +// IBCMiddleware creates a new IBCMiddleware given the associated keeper and underlying application +func NewIBCMiddleware(app porttypes.IBCModule, k keeper.Keeper) IBCMiddleware { + return IBCMiddleware{ app: app, + keeper: k, } } -// OnChanOpenInit implements the IBCModule interface +// OnChanOpenInit implements the IBCMiddleware interface // // Interchain Accounts is implemented to act as middleware for connected authentication modules on // the controller side. The connected modules may not change the controller side portID or // version. They will be allowed to perform custom logic without changing // the parameters stored within a channel struct. -func (im IBCModule) OnChanOpenInit( +func (im IBCMiddleware) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, connectionHops []string, @@ -56,8 +59,8 @@ func (im IBCModule) OnChanOpenInit( chanCap, counterparty, version) } -// OnChanOpenTry implements the IBCModule interface -func (im IBCModule) OnChanOpenTry( +// OnChanOpenTry implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, connectionHops []string, @@ -70,13 +73,13 @@ func (im IBCModule) OnChanOpenTry( return "", sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") } -// OnChanOpenAck implements the IBCModule interface +// OnChanOpenAck implements the IBCMiddleware interface // // Interchain Accounts is implemented to act as middleware for connected authentication modules on // the controller side. The connected modules may not change the portID or // version. They will be allowed to perform custom logic without changing // the parameters stored within a channel struct. -func (im IBCModule) OnChanOpenAck( +func (im IBCMiddleware) OnChanOpenAck( ctx sdk.Context, portID, channelID string, @@ -95,8 +98,8 @@ func (im IBCModule) OnChanOpenAck( return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) } -// OnChanOpenAck implements the IBCModule interface -func (im IBCModule) OnChanOpenConfirm( +// OnChanOpenAck implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenConfirm( ctx sdk.Context, portID, channelID string, @@ -104,8 +107,8 @@ func (im IBCModule) OnChanOpenConfirm( return sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") } -// OnChanCloseInit implements the IBCModule interface -func (im IBCModule) OnChanCloseInit( +// OnChanCloseInit implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanCloseInit( ctx sdk.Context, portID, channelID string, @@ -114,8 +117,8 @@ func (im IBCModule) OnChanCloseInit( return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") } -// OnChanCloseConfirm implements the IBCModule interface -func (im IBCModule) OnChanCloseConfirm( +// OnChanCloseConfirm implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanCloseConfirm( ctx sdk.Context, portID, channelID string, @@ -123,8 +126,8 @@ func (im IBCModule) OnChanCloseConfirm( return im.keeper.OnChanCloseConfirm(ctx, portID, channelID) } -// OnRecvPacket implements the IBCModule interface -func (im IBCModule) OnRecvPacket( +// OnRecvPacket implements the IBCMiddleware interface +func (im IBCMiddleware) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, _ sdk.AccAddress, @@ -132,8 +135,8 @@ func (im IBCModule) OnRecvPacket( return channeltypes.NewErrorAcknowledgement("cannot receive packet on controller chain") } -// OnAcknowledgementPacket implements the IBCModule interface -func (im IBCModule) OnAcknowledgementPacket( +// OnAcknowledgementPacket implements the IBCMiddleware interface +func (im IBCMiddleware) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, @@ -147,8 +150,8 @@ func (im IBCModule) OnAcknowledgementPacket( return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) } -// OnTimeoutPacket implements the IBCModule interface -func (im IBCModule) OnTimeoutPacket( +// OnTimeoutPacket implements the IBCMiddleware interface +func (im IBCMiddleware) OnTimeoutPacket( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, @@ -164,7 +167,27 @@ func (im IBCModule) OnTimeoutPacket( return im.app.OnTimeoutPacket(ctx, packet, relayer) } +// SendPacket implements the ICS4 Wrapper interface +// The ICA controller module builds the outgoing ICA packet and calls the core IBC SendPacket +func (im IBCMiddleware) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet ibcexported.PacketI, +) error { + panic("SendPacket not supported for ICA-auth module. Please use SendTx") +} + +// WriteAcknowledgement implements the ICS4 Wrapper interface +func (im IBCMiddleware) WriteAcknowledgement( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet ibcexported.PacketI, + ack ibcexported.Acknowledgement, +) error { + panic("WriteAcknowledgement not supported for ICA controller module") +} + // GetAppVersion returns the interchain accounts metadata. -func (im IBCModule) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { +func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { return im.keeper.GetAppVersion(ctx, portID, channelID) } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go similarity index 99% rename from modules/apps/27-interchain-accounts/controller/ibc_module_test.go rename to modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 608996515c1..ea1b5185af2 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -717,7 +717,7 @@ func (suite *InterchainAccountsTestSuite) TestGetAppVersion() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - controllerModule := cbs.(icacontroller.IBCModule) + controllerModule := cbs.(icacontroller.IBCMiddleware) appVersion, found := controllerModule.GetAppVersion(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) suite.Require().True(found) diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index 1bb870fca5d..c7a5651baa6 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -16,7 +16,6 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/client/cli" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller" controllerkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/keeper" controllertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host" @@ -31,7 +30,6 @@ var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ porttypes.IBCModule = controller.IBCModule{} _ porttypes.IBCModule = host.IBCModule{} ) diff --git a/modules/apps/29-fee/ibc_module.go b/modules/apps/29-fee/ibc_middleware.go similarity index 82% rename from modules/apps/29-fee/ibc_module.go rename to modules/apps/29-fee/ibc_middleware.go index 6ed9faa1f34..236c7456b0d 100644 --- a/modules/apps/29-fee/ibc_module.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -12,22 +12,25 @@ import ( "github.com/cosmos/ibc-go/v3/modules/core/exported" ) -// IBCModule implements the ICS26 callbacks for the fee middleware given the fee keeper and the underlying application. -type IBCModule struct { - keeper keeper.Keeper +var _ porttypes.Middleware = &IBCMiddleware{} + +// IBCMiddleware implements the ICS26 callbacks for the fee middleware given the +// fee keeper and the underlying application. +type IBCMiddleware struct { app porttypes.IBCModule + keeper keeper.Keeper } -// NewIBCModule creates a new IBCModule given the keeper and underlying application -func NewIBCModule(k keeper.Keeper, app porttypes.IBCModule) IBCModule { - return IBCModule{ - keeper: k, +// NewIBCMiddleware creates a new IBCMiddlware given the keeper and underlying application +func NewIBCMiddleware(app porttypes.IBCModule, k keeper.Keeper) IBCMiddleware { + return IBCMiddleware{ app: app, + keeper: k, } } -// OnChanOpenInit implements the IBCModule interface -func (im IBCModule) OnChanOpenInit( +// OnChanOpenInit implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, connectionHops []string, @@ -57,10 +60,10 @@ func (im IBCModule) OnChanOpenInit( chanCap, counterparty, versionMetadata.AppVersion) } -// OnChanOpenTry implements the IBCModule interface +// OnChanOpenTry implements the IBCMiddleware interface // If the channel is not fee enabled the underlying application version will be returned // If the channel is fee enabled we merge the underlying application version with the ics29 version -func (im IBCModule) OnChanOpenTry( +func (im IBCMiddleware) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, connectionHops []string, @@ -100,8 +103,8 @@ func (im IBCModule) OnChanOpenTry( return string(versionBytes), nil } -// OnChanOpenAck implements the IBCModule interface -func (im IBCModule) OnChanOpenAck( +// OnChanOpenAck implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenAck( ctx sdk.Context, portID, channelID string, @@ -128,8 +131,8 @@ func (im IBCModule) OnChanOpenAck( return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) } -// OnChanOpenConfirm implements the IBCModule interface -func (im IBCModule) OnChanOpenConfirm( +// OnChanOpenConfirm implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanOpenConfirm( ctx sdk.Context, portID, channelID string, @@ -138,8 +141,8 @@ func (im IBCModule) OnChanOpenConfirm( return im.app.OnChanOpenConfirm(ctx, portID, channelID) } -// OnChanCloseInit implements the IBCModule interface -func (im IBCModule) OnChanCloseInit( +// OnChanCloseInit implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanCloseInit( ctx sdk.Context, portID, channelID string, @@ -155,8 +158,8 @@ func (im IBCModule) OnChanCloseInit( return nil } -// OnChanCloseConfirm implements the IBCModule interface -func (im IBCModule) OnChanCloseConfirm( +// OnChanCloseConfirm implements the IBCMiddleware interface +func (im IBCMiddleware) OnChanCloseConfirm( ctx sdk.Context, portID, channelID string, @@ -172,9 +175,9 @@ func (im IBCModule) OnChanCloseConfirm( return nil } -// OnRecvPacket implements the IBCModule interface. +// OnRecvPacket implements the IBCMiddleware interface. // If fees are not enabled, this callback will default to the ibc-core packet callback -func (im IBCModule) OnRecvPacket( +func (im IBCMiddleware) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, @@ -197,9 +200,9 @@ func (im IBCModule) OnRecvPacket( return types.NewIncentivizedAcknowledgement(forwardRelayer, ack.Acknowledgement(), ack.Success()) } -// OnAcknowledgementPacket implements the IBCModule interface +// OnAcknowledgementPacket implements the IBCMiddleware interface // If fees are not enabled, this callback will default to the ibc-core packet callback -func (im IBCModule) OnAcknowledgementPacket( +func (im IBCMiddleware) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, @@ -239,9 +242,9 @@ func (im IBCModule) OnAcknowledgementPacket( return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer) } -// OnTimeoutPacket implements the IBCModule interface +// OnTimeoutPacket implements the IBCMiddleware interface // If fees are not enabled, this callback will default to the ibc-core packet callback -func (im IBCModule) OnTimeoutPacket( +func (im IBCMiddleware) OnTimeoutPacket( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, @@ -268,7 +271,26 @@ func (im IBCModule) OnTimeoutPacket( return im.app.OnTimeoutPacket(ctx, packet, relayer) } +// SendPacket implements the ICS4 Wrapper interface +func (im IBCMiddleware) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, +) error { + return im.keeper.SendPacket(ctx, chanCap, packet) +} + +// WriteAcknowledgement implements the ICS4 Wrapper interface +func (im IBCMiddleware) WriteAcknowledgement( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, + ack exported.Acknowledgement, +) error { + return im.keeper.WriteAcknowledgement(ctx, chanCap, packet, ack) +} + // GetAppVersion returns the application version of the underlying application -func (im IBCModule) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { +func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { return im.keeper.GetAppVersion(ctx, portID, channelID) } diff --git a/modules/apps/29-fee/ibc_module_test.go b/modules/apps/29-fee/ibc_middleware_test.go similarity index 99% rename from modules/apps/29-fee/ibc_module_test.go rename to modules/apps/29-fee/ibc_middleware_test.go index 3f5cf64635a..d46c414270e 100644 --- a/modules/apps/29-fee/ibc_module_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -896,7 +896,7 @@ func (suite *FeeTestSuite) TestGetAppVersion() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - feeModule := cbs.(fee.IBCModule) + feeModule := cbs.(fee.IBCMiddleware) appVersion, found := feeModule.GetAppVersion(suite.chainA.GetContext(), portID, channelID) diff --git a/modules/apps/29-fee/module.go b/modules/apps/29-fee/module.go index e493e047837..895a475b512 100644 --- a/modules/apps/29-fee/module.go +++ b/modules/apps/29-fee/module.go @@ -20,12 +20,10 @@ import ( "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/client/cli" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/keeper" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" ) var ( _ module.AppModule = AppModule{} - _ porttypes.IBCModule = IBCModule{} _ module.AppModuleBasic = AppModuleBasic{} ) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 738e29cdd59..f707ba6087b 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -300,7 +300,8 @@ func NewSimApp( // seal capability keeper after scoping modules app.CapabilityKeeper.Seal() - // add keepers + // SDK module keepers + app.AccountKeeper = authkeeper.NewAccountKeeper( appCodec, keys[authtypes.StoreKey], app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms, ) @@ -334,13 +335,14 @@ func NewSimApp( stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()), ) - // Create IBC Keeper + app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.BaseApp.MsgServiceRouter()) + + // IBC Keepers + app.IBCKeeper = ibckeeper.NewKeeper( appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper, ) - app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.BaseApp.MsgServiceRouter()) - // register the proposal types govRouter := govtypes.NewRouter() govRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). @@ -353,69 +355,111 @@ func NewSimApp( &stakingKeeper, govRouter, ) - app.IBCFeeKeeper = ibcfeekeeper.NewKeeper(appCodec, keys[ibcfeetypes.StoreKey], app.GetSubspace(ibcfeetypes.ModuleName), - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, + // IBC Fee Module keeper + app.IBCFeeKeeper = ibcfeekeeper.NewKeeper( + appCodec, keys[ibcfeetypes.StoreKey], app.GetSubspace(ibcfeetypes.ModuleName), + app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, + ) + + // ICA Controller keeper + app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( + appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), + app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee + app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + scopedICAControllerKeeper, app.MsgServiceRouter(), ) + // ICA Host keeper + app.ICAHostKeeper = icahostkeeper.NewKeeper( + appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), + app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), + ) + + // Create IBC Router + ibcRouter := porttypes.NewRouter() + + // Middleware Stacks + // Create Transfer Keeper and pass IBCFeeKeeper as expected Channel and PortKeeper // since fee middleware will wrap the IBCKeeper for underlying application. app.TransferKeeper = ibctransferkeeper.NewKeeper( appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName), - app.IBCFeeKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware + app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, ) - transferModule := transfer.NewAppModule(app.TransferKeeper) - transferIBCModule := transfer.NewIBCModule(app.TransferKeeper) - - // create fee-wrapped transfer module - feeTransferModule := ibcfee.NewIBCModule(app.IBCFeeKeeper, transferIBCModule) - feeModule := ibcfee.NewAppModule(app.IBCFeeKeeper) + // Mock Module Stack + // Mock Module setup for testing IBC and also acts as the interchain accounts authentication module // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // not replicate if you do not need to test core IBC or light clients. mockModule := ibcmock.NewAppModule(&app.IBCKeeper.PortKeeper) - // create fee wrapped mock module - feeMockModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp(MockFeePort, scopedFeeMockKeeper)) - app.FeeMockModule = feeMockModule + // The mock module is used for testing IBC + mockIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp(ibcmock.ModuleName, scopedIBCMockKeeper)) + ibcRouter.AddRoute(ibcmock.ModuleName, mockIBCModule) - feeWithMockModule := ibcfee.NewIBCModule(app.IBCFeeKeeper, feeMockModule) + // Create Transfer Stack + // SendPacket, since it is originating from the application to core IBC: + // transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket - mockIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp(ibcmock.ModuleName, scopedIBCMockKeeper)) + // RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way + // channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket - app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( - appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - scopedICAControllerKeeper, app.MsgServiceRouter(), - ) + // transfer stack contains (from top to bottom): + // - IBC Fee Middleware + // - Transfer - app.ICAHostKeeper = icahostkeeper.NewKeeper( - appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), - ) + // create IBC module from bottom to top of stack + var transferStack porttypes.IBCModule + transferStack = transfer.NewIBCModule(app.TransferKeeper) + transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) + + // Add transfer stack to IBC Router + ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) - icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) + // Create Interchain Accounts Stack + // SendPacket, since it is originating from the application to core IBC: + // icaAuthModuleKeeper.SendTx -> icaControllerKeeper.SendPacket -> channel.SendPacket // initialize ICA module with mock module as the authentication module on the controller side - icaAuthModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) - app.ICAAuthModule = icaAuthModule + var icaControllerStack porttypes.IBCModule + icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) + app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) + icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) - icaControllerIBCModule := icacontroller.NewIBCModule(app.ICAControllerKeeper, icaAuthModule) icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - // Create static IBC router, add app routes, then set and seal it - // pass in top-level (fully-wrapped) IBCModules to IBC Router - ibcRouter := porttypes.NewRouter() - ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerIBCModule). + // Add host, controller & ica auth modules to IBC router + ibcRouter. + // the ICA Controller middleware needs to be explicitly added to the IBC Router because the + // ICA controller module owns the port capability for ICA. The ICA authentication module + // owns the channel capability. + AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). - AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerIBCModule). // ica with mock auth module stack route to ica (top level of middleware stack) - AddRoute(ibctransfertypes.ModuleName, feeTransferModule). - AddRoute(ibcmock.ModuleName, mockIBCModule). - AddRoute(MockFeePort, feeWithMockModule) + AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) + + // Create Mock IBC Fee module stack for testing + // SendPacket, since it is originating from the application to core IBC: + // mockModule.SendPacket -> fee.SendPacket -> channel.SendPacket + + // OnRecvPacket, message that originates from core IBC and goes down to app, the flow is the otherway + // channel.RecvPacket -> fee.OnRecvPacket -> mockModule.OnRecvPacket + // OnAcknowledgementPacket as this is where fee's are paid out + // mockModule.OnAcknowledgementPacket -> fee.OnAcknowledgementPacket -> channel.OnAcknowledgementPacket + + // create fee wrapped mock module + feeMockModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp(MockFeePort, scopedFeeMockKeeper)) + app.FeeMockModule = feeMockModule + feeWithMockModule := ibcfee.NewIBCMiddleware(feeMockModule, app.IBCFeeKeeper) + ibcRouter.AddRoute(MockFeePort, feeWithMockModule) + + // Seal the IBC Router app.IBCKeeper.SetRouter(ibcRouter) // create evidence keeper with router @@ -434,6 +478,7 @@ func NewSimApp( // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.mm = module.NewManager( + // SDK app modules genutil.NewAppModule( app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx, encodingConfig.TxConfig, @@ -454,9 +499,11 @@ func NewSimApp( ibc.NewAppModule(app.IBCKeeper), params.NewAppModule(app.ParamsKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), - transferModule, - feeModule, - icaModule, + + // IBC modules + transfer.NewAppModule(app.TransferKeeper), + ibcfee.NewAppModule(app.IBCFeeKeeper), + ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper), mockModule, ) @@ -516,7 +563,7 @@ func NewSimApp( evidence.NewAppModule(app.EvidenceKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), ibc.NewAppModule(app.IBCKeeper), - transferModule, + transfer.NewAppModule(app.TransferKeeper), ) app.sm.RegisterStoreDecoders() From f2577f97c5341c09232a0c56d8a1a62ad6ea0b8a Mon Sep 17 00:00:00 2001 From: khanh <50263489+catShaark@users.noreply.github.com> Date: Fri, 29 Apr 2022 12:32:00 +0700 Subject: [PATCH 095/275] add empty keepers checking in ibc NewKeeper (#1284) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add empty keepers checking in ibc NewKeeper * check for empty exported keepers instead of empty sdk-defined keeper structs * Update modules/core/keeper/keeper.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * remove func checkEmptyKeepers(), check empty keepers directly within func NewKeeper() * modules/core/keeper KeeperTestSuite -> MsgServerTestSuite; creat new modules/core/keeper KeeperTestSuite for testing ibckeeper.NewKeeper() * update CHANGELOG.md * DummyStakingKeeper -> MockStakingKeeper * refactor modules/core/keeper test * Update modules/core/keeper/keeper_test.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update modules/core/keeper/keeper.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- CHANGELOG.md | 1 + modules/core/keeper/keeper.go | 16 +++ modules/core/keeper/keeper_test.go | 138 +++++++++++++++++++++++++ modules/core/keeper/msg_server_test.go | 32 ------ 4 files changed, 155 insertions(+), 32 deletions(-) create mode 100644 modules/core/keeper/keeper_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a19e914587..1f699f30ff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. * (middleware) [\#1022](https://github.com/cosmos/ibc-go/pull/1022) Add `GetAppVersion` to the ICS4Wrapper interface. This function should be used by IBC applications to obtain their own version since the version set in the channel structure may be wrapped many times by middleware. * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. * (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 69044e9e4ea..3a6cc5cb23b 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -1,6 +1,9 @@ package keeper import ( + "fmt" + "reflect" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" @@ -46,6 +49,19 @@ func NewKeeper( paramSpace = paramSpace.WithKeyTable(keyTable) } + // panic if any of the keepers passed in is empty + if reflect.ValueOf(stakingKeeper).IsZero() { + panic(fmt.Errorf("cannot initialize IBC keeper: empty staking keeper")) + } + + if reflect.ValueOf(upgradeKeeper).IsZero() { + panic(fmt.Errorf("cannot initialize IBC keeper: empty upgrade keeper")) + } + + if reflect.DeepEqual(capabilitykeeper.ScopedKeeper{}, scopedKeeper) { + panic(fmt.Errorf("cannot initialize IBC keeper: empty scoped keeper")) + } + clientKeeper := clientkeeper.NewKeeper(cdc, key, paramSpace, stakingKeeper, upgradeKeeper) connectionKeeper := connectionkeeper.NewKeeper(cdc, key, paramSpace, clientKeeper) portKeeper := portkeeper.NewKeeper(scopedKeeper) diff --git a/modules/core/keeper/keeper_test.go b/modules/core/keeper/keeper_test.go new file mode 100644 index 00000000000..d40d1ab34c5 --- /dev/null +++ b/modules/core/keeper/keeper_test.go @@ -0,0 +1,138 @@ +package keeper_test + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + "github.com/stretchr/testify/suite" + + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +type KeeperTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) + + // TODO: remove + // commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1) + suite.coordinator.CommitNBlocks(suite.chainA, 2) + suite.coordinator.CommitNBlocks(suite.chainB, 2) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +// MockStakingKeeper implements clienttypes.StakingKeeper used in ibckeeper.NewKeeper +type MockStakingKeeper struct { + mockField string +} + +func (d MockStakingKeeper) GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) { + return stakingtypes.HistoricalInfo{}, true +} + +func (d MockStakingKeeper) UnbondingTime(ctx sdk.Context) time.Duration { + return 0 +} + +// Test ibckeeper.NewKeeper used to initialize IBCKeeper when creating an app instance. +// It verifies if ibckeeper.NewKeeper panic when any of the keepers passed in is empty. +func (suite *KeeperTestSuite) TestNewKeeper() { + var ( + stakingKeeper clienttypes.StakingKeeper + upgradeKeeper clienttypes.UpgradeKeeper + scopedKeeper capabilitykeeper.ScopedKeeper + newIBCKeeper = func() { + ibckeeper.NewKeeper( + suite.chainA.GetSimApp().AppCodec(), + suite.chainA.GetSimApp().GetKey(ibchost.StoreKey), + suite.chainA.GetSimApp().GetSubspace(ibchost.ModuleName), + stakingKeeper, + upgradeKeeper, + scopedKeeper, + ) + } + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + {"failure: empty staking keeper", func() { + emptyStakingKeeper := stakingkeeper.Keeper{} + + stakingKeeper = emptyStakingKeeper + + }, false}, + {"failure: empty mock staking keeper", func() { + // use a different implementation of clienttypes.StakingKeeper + emptyMockStakingKeeper := MockStakingKeeper{} + + stakingKeeper = emptyMockStakingKeeper + + }, false}, + {"failure: empty upgrade keeper", func() { + emptyUpgradeKeeper := upgradekeeper.Keeper{} + + upgradeKeeper = emptyUpgradeKeeper + + }, false}, + {"failure: empty scoped keeper", func() { + emptyScopedKeeper := capabilitykeeper.ScopedKeeper{} + + scopedKeeper = emptyScopedKeeper + }, false}, + {"success: replace stakingKeeper with non-empty MockStakingKeeper", func() { + // use a different implementation of clienttypes.StakingKeeper + mockStakingKeeper := MockStakingKeeper{"not empty"} + + stakingKeeper = mockStakingKeeper + }, true}, + } + + for _, tc := range testCases { + tc := tc + suite.SetupTest() + + suite.Run(tc.name, func() { + + stakingKeeper = suite.chainA.GetSimApp().StakingKeeper + upgradeKeeper = suite.chainA.GetSimApp().UpgradeKeeper + scopedKeeper = suite.chainA.GetSimApp().ScopedIBCKeeper + + tc.malleate() + + if tc.expPass { + suite.Require().NotPanics( + newIBCKeeper, + ) + } else { + suite.Require().Panics( + newIBCKeeper, + ) + } + + }) + } +} diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 1e1933ee724..7e01241be81 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -1,11 +1,8 @@ package keeper_test import ( - "testing" - sdk "github.com/cosmos/cosmos-sdk/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/stretchr/testify/suite" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -18,40 +15,11 @@ import ( ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" ) -const height = 10 - var ( timeoutHeight = clienttypes.NewHeight(0, 10000) maxSequence = uint64(10) ) -type KeeperTestSuite struct { - suite.Suite - - coordinator *ibctesting.Coordinator - - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain -} - -// SetupTest creates a coordinator with 2 test chains. -func (suite *KeeperTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) - - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) - - // TODO: remove - // commit some blocks so that QueryProof returns valid proof (cannot return valid query if height <= 1) - suite.coordinator.CommitNBlocks(suite.chainA, 2) - suite.coordinator.CommitNBlocks(suite.chainB, 2) - -} - -func TestIBCTestSuite(t *testing.T) { - suite.Run(t, new(KeeperTestSuite)) -} - // tests the IBC handler receiving a packet on ordered and unordered channels. // It verifies that the storing of an acknowledgement on success occurs. It // tests high level properties like ordering and basic sanity checks. More From f962485f4d84cbed2536d6c4491a5162f0bc5c65 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 29 Apr 2022 16:00:32 +0200 Subject: [PATCH 096/275] add query flags to command for querying counterparty address (#1313) --- modules/apps/29-fee/client/cli/query.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index a183c8f89d3..4da82704fb0 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -272,6 +272,8 @@ func GetCmdCounterpartyAddress() *cobra.Command { }, } + flags.AddQueryFlagsToCmd(cmd) + return cmd } From d91d1adae0ebc32be62bbd1525cdf1912e5aaeb5 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 2 May 2022 10:31:50 +0200 Subject: [PATCH 097/275] add validation of packet ID in CLI to query packet (#1314) --- modules/apps/29-fee/client/cli/query.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index 4da82704fb0..092b7441453 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -20,22 +20,23 @@ func GetCmdIncentivizedPacket() *cobra.Command { Short: "Query for an unrelayed incentivized packet by port-id, channel-id and packet sequence.", Long: "Query for an unrelayed incentivized packet by port-id, channel-id and packet sequence.", Args: cobra.ExactArgs(3), - Example: fmt.Sprintf("%s query ibc-fee packet-by-id", version.AppName), + Example: fmt.Sprintf("%s query ibc-fee packet", version.AppName), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } + portID, channelID := args[0], args[1] seq, err := strconv.ParseUint(args[2], 10, 64) if err != nil { return err } - packetID := channeltypes.PacketId{ - PortId: args[0], - ChannelId: args[1], - Sequence: seq, + packetID := channeltypes.NewPacketId(portID, channelID, seq) + + if err := packetID.Validate(); err != nil { + return err } req := &types.QueryIncentivizedPacketRequest{ From bd086506f9256c4d5776bc38d2e930b523eb5125 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 11:44:31 +0200 Subject: [PATCH 098/275] build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.3 to 0.45.4 (#1300) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.3 to 0.45.4 Bumps [github.com/cosmos/cosmos-sdk](https://github.com/cosmos/cosmos-sdk) from 0.45.3 to 0.45.4. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.45.4/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/v0.45.3...v0.45.4) --- updated-dependencies: - dependency-name: github.com/cosmos/cosmos-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * update changelog Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f699f30ff3..bad11038acb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies -* [\#1247](https://github.com/cosmos/ibc-go/pull/1247) Bump SDK version to v0.45.3 and Tendermint to version 0.34.19 +* [\#1300](https://github.com/cosmos/ibc-go/pull/1300) Bump SDK version to v0.45.4 ### API Breaking diff --git a/go.mod b/go.mod index 2245322cb94..a75781504d2 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alp require ( github.com/armon/go-metrics v0.3.11 github.com/confio/ics23/go v0.7.0 - github.com/cosmos/cosmos-sdk v0.45.3 + github.com/cosmos/cosmos-sdk v0.45.4 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 diff --git a/go.sum b/go.sum index e8eca38e6b0..a33e5366c6d 100644 --- a/go.sum +++ b/go.sum @@ -230,8 +230,8 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= -github.com/cosmos/cosmos-sdk v0.45.3 h1:PiVSU3IkNEDPhoxOZHk2lPnhwBBJgEYAtAR0jGXRN4g= -github.com/cosmos/cosmos-sdk v0.45.3/go.mod h1:qYm5JEr0ZlbnmoP/Q3b+dYMOliHf4ddHirpILiwZzqg= +github.com/cosmos/cosmos-sdk v0.45.4 h1:eStDAhJdMY8n5arbBRe+OwpNeBSunxSBHp1g55ulfdA= +github.com/cosmos/cosmos-sdk v0.45.4/go.mod h1:WOqtDxN3eCCmnYLVla10xG7lEXkFjpTaqm2a2WasgCc= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= From 7bb609c52dd0ad7806ce809ad842007f8a292cd9 Mon Sep 17 00:00:00 2001 From: Sean King Date: Wed, 4 May 2022 15:53:50 +0200 Subject: [PATCH 099/275] refactor: renaming Result in IncentivizedAcknowledgement to AppAcknowledgement (#1338) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: renaming Result in IncentivizedAcknowledgement to AppAcknowledgement * chore: changelog * Update proto/ibc/applications/fee/v1/ack.proto Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * chore: yaml Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- CHANGELOG.md | 1 + docs/ibc/proto-docs.md | 2 +- modules/apps/29-fee/ibc_middleware.go | 4 +- modules/apps/29-fee/ibc_middleware_test.go | 10 ++-- modules/apps/29-fee/types/ack.go | 2 +- modules/apps/29-fee/types/ack.pb.go | 69 +++++++++++----------- proto/ibc/applications/fee/v1/ack.proto | 4 +- 7 files changed, 47 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bad11038acb..65274b8fa95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. +* (modules/29-fee)[\#1338](https://github.com/cosmos/ibc-go/pull/1338) Renaming `Result` field in `IncentivizedAcknowledgement` to `AppAcknowledgement`. ### State Machine Breaking diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index cf411ade14c..799ad8243ec 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -355,7 +355,7 @@ IncentivizedAcknowledgement is the acknowledgement format to be used by applicat | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `result` | [bytes](#bytes) | | the underlying app acknowledgement result bytes | +| `app_acknowledgement` | [bytes](#bytes) | | the underlying app acknowledgement bytes | | `forward_relayer_address` | [string](#string) | | the relayer address which submits the recv packet message | | `underlying_app_success` | [bool](#bool) | | success flag of the base application callback | diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 236c7456b0d..96bb8be4030 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -226,7 +226,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( // for fee enabled channels // // Please see ADR 004 for more information. - return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer) + return im.app.OnAcknowledgementPacket(ctx, packet, ack.AppAcknowledgement, relayer) } packetID := channeltypes.NewPacketId(packet.SourcePort, packet.SourceChannel, packet.Sequence) @@ -239,7 +239,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( } // call underlying callback - return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer) + return im.app.OnAcknowledgementPacket(ctx, packet, ack.AppAcknowledgement, relayer) } // OnTimeoutPacket implements the IBCMiddleware interface diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index d46c414270e..8c76720ad3e 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -526,7 +526,7 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { forwardAddr, _ := suite.chainB.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) expectedAck := types.IncentivizedAcknowledgement{ - Result: ibcmock.MockAcknowledgement.Acknowledgement(), + AppAcknowledgement: ibcmock.MockAcknowledgement.Acknowledgement(), ForwardRelayerAddress: forwardAddr, UnderlyingAppSuccess: true, } @@ -545,7 +545,7 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { case !tc.forwardRelayer: expectedAck := types.IncentivizedAcknowledgement{ - Result: ibcmock.MockAcknowledgement.Acknowledgement(), + AppAcknowledgement: ibcmock.MockAcknowledgement.Acknowledgement(), ForwardRelayerAddress: "", UnderlyingAppSuccess: true, } @@ -584,7 +584,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeesInEscrow(suite.chainA.GetContext(), packetID) ack = types.IncentivizedAcknowledgement{ - Result: ibcmock.MockAcknowledgement.Acknowledgement(), + AppAcknowledgement: ibcmock.MockAcknowledgement.Acknowledgement(), ForwardRelayerAddress: suite.chainA.SenderAccount.GetAddress().String(), }.Acknowledgement() @@ -626,7 +626,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { blockedAddr := suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() ack = types.IncentivizedAcknowledgement{ - Result: ibcmock.MockAcknowledgement.Acknowledgement(), + AppAcknowledgement: ibcmock.MockAcknowledgement.Acknowledgement(), ForwardRelayerAddress: blockedAddr.String(), }.Acknowledgement() @@ -673,7 +673,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { // must be changed explicitly ack = types.IncentivizedAcknowledgement{ - Result: ibcmock.MockAcknowledgement.Acknowledgement(), + AppAcknowledgement: ibcmock.MockAcknowledgement.Acknowledgement(), ForwardRelayerAddress: relayerAddr.String(), }.Acknowledgement() diff --git a/modules/apps/29-fee/types/ack.go b/modules/apps/29-fee/types/ack.go index 229d8e4cc3f..d0fe4269868 100644 --- a/modules/apps/29-fee/types/ack.go +++ b/modules/apps/29-fee/types/ack.go @@ -7,7 +7,7 @@ import ( // NewIncentivizedAcknowledgement creates a new instance of IncentivizedAcknowledgement func NewIncentivizedAcknowledgement(relayer string, ack []byte, success bool) IncentivizedAcknowledgement { return IncentivizedAcknowledgement{ - Result: ack, + AppAcknowledgement: ack, ForwardRelayerAddress: relayer, UnderlyingAppSuccess: success, } diff --git a/modules/apps/29-fee/types/ack.pb.go b/modules/apps/29-fee/types/ack.pb.go index 4f6437da224..3a3e6eae58e 100644 --- a/modules/apps/29-fee/types/ack.pb.go +++ b/modules/apps/29-fee/types/ack.pb.go @@ -25,8 +25,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware type IncentivizedAcknowledgement struct { - // the underlying app acknowledgement result bytes - Result []byte `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` + // the underlying app acknowledgement bytes + AppAcknowledgement []byte `protobuf:"bytes,1,opt,name=app_acknowledgement,json=appAcknowledgement,proto3" json:"app_acknowledgement,omitempty" yaml:"app_acknowledgement"` // the relayer address which submits the recv packet message ForwardRelayerAddress string `protobuf:"bytes,2,opt,name=forward_relayer_address,json=forwardRelayerAddress,proto3" json:"forward_relayer_address,omitempty" yaml:"forward_relayer_address"` // success flag of the base application callback @@ -66,9 +66,9 @@ func (m *IncentivizedAcknowledgement) XXX_DiscardUnknown() { var xxx_messageInfo_IncentivizedAcknowledgement proto.InternalMessageInfo -func (m *IncentivizedAcknowledgement) GetResult() []byte { +func (m *IncentivizedAcknowledgement) GetAppAcknowledgement() []byte { if m != nil { - return m.Result + return m.AppAcknowledgement } return nil } @@ -94,27 +94,28 @@ func init() { func init() { proto.RegisterFile("ibc/applications/fee/v1/ack.proto", fileDescriptor_ab2834946fb65ea4) } var fileDescriptor_ab2834946fb65ea4 = []byte{ - // 315 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0xb1, 0x4e, 0xf3, 0x30, - 0x14, 0x85, 0xeb, 0xff, 0x97, 0x2a, 0x88, 0x98, 0xa2, 0xd2, 0x56, 0x20, 0x85, 0x92, 0xa9, 0x4b, - 0x63, 0x95, 0x8a, 0x01, 0xb6, 0x76, 0x63, 0x42, 0x0a, 0x0b, 0xea, 0x12, 0x39, 0xf6, 0x6d, 0xb0, - 0xea, 0xd8, 0x96, 0xed, 0xa4, 0x0a, 0x4f, 0xc1, 0x63, 0x31, 0x76, 0x64, 0x42, 0xa8, 0x1d, 0xd9, - 0x78, 0x02, 0x94, 0xa6, 0x12, 0x1d, 0x60, 0xbb, 0xf7, 0x9c, 0x4f, 0x67, 0xf8, 0xbc, 0x4b, 0x9e, - 0x52, 0x4c, 0xb4, 0x16, 0x9c, 0x12, 0xc7, 0x95, 0xb4, 0x78, 0x01, 0x80, 0xcb, 0x31, 0x26, 0x74, - 0x19, 0x69, 0xa3, 0x9c, 0xf2, 0x7b, 0x3c, 0xa5, 0xd1, 0x21, 0x12, 0x2d, 0x00, 0xa2, 0x72, 0x7c, - 0xd6, 0xc9, 0x54, 0xa6, 0x76, 0x0c, 0xae, 0xaf, 0x06, 0x0f, 0x3f, 0x91, 0x77, 0x7e, 0x27, 0x29, - 0x48, 0xc7, 0x4b, 0xfe, 0x0c, 0x6c, 0x4a, 0x97, 0x52, 0xad, 0x04, 0xb0, 0x0c, 0x72, 0x90, 0xce, - 0xef, 0x7a, 0x6d, 0x03, 0xb6, 0x10, 0xae, 0x8f, 0x06, 0x68, 0x78, 0x12, 0xef, 0x3f, 0x7f, 0xee, - 0xf5, 0x16, 0xca, 0xac, 0x88, 0x61, 0x89, 0x01, 0x41, 0x2a, 0x30, 0x09, 0x61, 0xcc, 0x80, 0xb5, - 0xfd, 0x7f, 0x03, 0x34, 0x3c, 0x9e, 0x85, 0x5f, 0xef, 0x17, 0x41, 0x45, 0x72, 0x71, 0x1b, 0xfe, - 0x01, 0x86, 0xf1, 0xe9, 0xbe, 0x89, 0x9b, 0x62, 0xda, 0xe4, 0xfe, 0xa3, 0xd7, 0x2d, 0x24, 0x03, - 0x23, 0x2a, 0x2e, 0xb3, 0x84, 0x68, 0x9d, 0xd8, 0x82, 0xd2, 0x7a, 0xfa, 0xff, 0x00, 0x0d, 0x8f, - 0x0e, 0xa7, 0x7f, 0xe7, 0x44, 0x18, 0x77, 0x7e, 0x9a, 0xa9, 0xd6, 0x0f, 0x4d, 0x3e, 0xbb, 0x7f, - 0xdd, 0x04, 0x68, 0xbd, 0x09, 0xd0, 0xc7, 0x26, 0x40, 0x2f, 0xdb, 0xa0, 0xb5, 0xde, 0x06, 0xad, - 0xb7, 0x6d, 0xd0, 0x9a, 0x5f, 0x67, 0xdc, 0x3d, 0x15, 0x69, 0x44, 0x55, 0x8e, 0xa9, 0xb2, 0xb9, - 0xb2, 0x98, 0xa7, 0x74, 0x94, 0x29, 0x5c, 0x4e, 0x70, 0xae, 0x58, 0x21, 0xc0, 0xd6, 0xe6, 0x2d, - 0xbe, 0xba, 0x19, 0xd5, 0xd2, 0x5d, 0xa5, 0xc1, 0xa6, 0xed, 0x9d, 0xc5, 0xc9, 0x77, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x2e, 0x38, 0x5f, 0x80, 0x99, 0x01, 0x00, 0x00, + // 329 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xb1, 0x4e, 0xc2, 0x40, + 0x1c, 0xc6, 0x29, 0x26, 0x46, 0x1b, 0xa7, 0x8a, 0x42, 0x30, 0x39, 0xb0, 0x13, 0x0b, 0xbd, 0x20, + 0x71, 0xd0, 0x0d, 0x36, 0x27, 0x92, 0xba, 0x18, 0x96, 0xe6, 0x7a, 0xfd, 0x53, 0x2f, 0x5c, 0xef, + 0x2e, 0x77, 0x6d, 0x49, 0x7d, 0x0a, 0x1f, 0xc2, 0x87, 0x71, 0x64, 0x74, 0x22, 0x06, 0xde, 0x80, + 0x27, 0x30, 0xa5, 0x26, 0xa2, 0xc1, 0xed, 0xf2, 0x7d, 0xbf, 0xfc, 0x72, 0xf9, 0x7f, 0xf6, 0x35, + 0x0b, 0x29, 0x26, 0x4a, 0x71, 0x46, 0x49, 0xca, 0xa4, 0x30, 0x78, 0x06, 0x80, 0xf3, 0x01, 0x26, + 0x74, 0xee, 0x29, 0x2d, 0x53, 0xe9, 0x34, 0x59, 0x48, 0xbd, 0x7d, 0xc4, 0x9b, 0x01, 0x78, 0xf9, + 0xa0, 0xdd, 0x88, 0x65, 0x2c, 0x77, 0x0c, 0x2e, 0x5f, 0x15, 0xee, 0xbe, 0xd5, 0xed, 0xab, 0x07, + 0x41, 0x41, 0xa4, 0x2c, 0x67, 0x2f, 0x10, 0x8d, 0xe8, 0x5c, 0xc8, 0x05, 0x87, 0x28, 0x86, 0x04, + 0x44, 0xea, 0x4c, 0xec, 0x73, 0xa2, 0x54, 0x40, 0x7e, 0xc7, 0x2d, 0xab, 0x6b, 0xf5, 0xce, 0xc6, + 0x68, 0xbb, 0xea, 0xb4, 0x0b, 0x92, 0xf0, 0x7b, 0xf7, 0x00, 0xe4, 0xfa, 0x0e, 0x51, 0xea, 0xaf, + 0x70, 0x6a, 0x37, 0x67, 0x52, 0x2f, 0x88, 0x8e, 0x02, 0x0d, 0x9c, 0x14, 0xa0, 0x03, 0x12, 0x45, + 0x1a, 0x8c, 0x69, 0xd5, 0xbb, 0x56, 0xef, 0x74, 0xec, 0x6e, 0x57, 0x1d, 0x54, 0x49, 0xff, 0x01, + 0x5d, 0xff, 0xe2, 0xbb, 0xf1, 0xab, 0x62, 0x54, 0xe5, 0xce, 0x93, 0x7d, 0x99, 0x89, 0x08, 0x34, + 0x2f, 0x98, 0x88, 0x83, 0xf2, 0x4b, 0x26, 0xa3, 0xb4, 0x54, 0x1f, 0x75, 0xad, 0xde, 0xc9, 0xbe, + 0xfa, 0x30, 0xc7, 0x5d, 0xbf, 0xf1, 0xd3, 0x8c, 0x94, 0x7a, 0xac, 0xf2, 0xf1, 0xe4, 0x7d, 0x8d, + 0xac, 0xe5, 0x1a, 0x59, 0x9f, 0x6b, 0x64, 0xbd, 0x6e, 0x50, 0x6d, 0xb9, 0x41, 0xb5, 0x8f, 0x0d, + 0xaa, 0x4d, 0x6f, 0x63, 0x96, 0x3e, 0x67, 0xa1, 0x47, 0x65, 0x82, 0xa9, 0x34, 0x89, 0x34, 0x98, + 0x85, 0xb4, 0x1f, 0x4b, 0x9c, 0x0f, 0x71, 0x22, 0xa3, 0x8c, 0x83, 0x29, 0x27, 0x33, 0xf8, 0xe6, + 0xae, 0x5f, 0xae, 0x95, 0x16, 0x0a, 0x4c, 0x78, 0xbc, 0x3b, 0xff, 0xf0, 0x2b, 0x00, 0x00, 0xff, + 0xff, 0x08, 0xe8, 0xda, 0xf9, 0xd2, 0x01, 0x00, 0x00, } func (m *IncentivizedAcknowledgement) Marshal() (dAtA []byte, err error) { @@ -154,10 +155,10 @@ func (m *IncentivizedAcknowledgement) MarshalToSizedBuffer(dAtA []byte) (int, er i-- dAtA[i] = 0x12 } - if len(m.Result) > 0 { - i -= len(m.Result) - copy(dAtA[i:], m.Result) - i = encodeVarintAck(dAtA, i, uint64(len(m.Result))) + if len(m.AppAcknowledgement) > 0 { + i -= len(m.AppAcknowledgement) + copy(dAtA[i:], m.AppAcknowledgement) + i = encodeVarintAck(dAtA, i, uint64(len(m.AppAcknowledgement))) i-- dAtA[i] = 0xa } @@ -181,7 +182,7 @@ func (m *IncentivizedAcknowledgement) Size() (n int) { } var l int _ = l - l = len(m.Result) + l = len(m.AppAcknowledgement) if l > 0 { n += 1 + l + sovAck(uint64(l)) } @@ -232,7 +233,7 @@ func (m *IncentivizedAcknowledgement) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AppAcknowledgement", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -259,9 +260,9 @@ func (m *IncentivizedAcknowledgement) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Result = append(m.Result[:0], dAtA[iNdEx:postIndex]...) - if m.Result == nil { - m.Result = []byte{} + m.AppAcknowledgement = append(m.AppAcknowledgement[:0], dAtA[iNdEx:postIndex]...) + if m.AppAcknowledgement == nil { + m.AppAcknowledgement = []byte{} } iNdEx = postIndex case 2: diff --git a/proto/ibc/applications/fee/v1/ack.proto b/proto/ibc/applications/fee/v1/ack.proto index 728c7536c6b..88b4d9fdd2c 100644 --- a/proto/ibc/applications/fee/v1/ack.proto +++ b/proto/ibc/applications/fee/v1/ack.proto @@ -8,8 +8,8 @@ import "gogoproto/gogo.proto"; // IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware message IncentivizedAcknowledgement { - // the underlying app acknowledgement result bytes - bytes result = 1; + // the underlying app acknowledgement bytes + bytes app_acknowledgement = 1 [(gogoproto.moretags) = "yaml:\"app_acknowledgement\""]; // the relayer address which submits the recv packet message string forward_relayer_address = 2 [(gogoproto.moretags) = "yaml:\"forward_relayer_address\""]; // success flag of the base application callback From af3d5228ed7af40b9a43cebe0af49729f22cf673 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 9 May 2022 14:59:22 +0200 Subject: [PATCH 100/275] update mergify.yaml (#1332) --- .github/mergify.yml | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/mergify.yml b/.github/mergify.yml index 70c3828d03f..868594d1d57 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -18,22 +18,6 @@ pull_request_rules: commit_message_template: | {{ title }} (#{{ number }}) {{ body }} - - name: backport patches to v1.1.x branch - conditions: - - base=main - - label=backport-to-v1.1.x - actions: - backport: - branches: - - release/v1.1.x - - name: backport patches to v1.2.x branch - conditions: - - base=main - - label=backport-to-v1.2.x - actions: - backport: - branches: - - release/v1.2.x - name: backport patches to v1.3.x branch conditions: - base=main @@ -49,15 +33,15 @@ pull_request_rules: actions: backport: branches: - - release/v1.4.x - - name: backport patches to v2.0.x branch + - release/v1.4.x + - name: backport patches to v1.5.x branch conditions: - base=main - - label=backport-to-v2.0.x + - label=backport-to-v1.5.x actions: backport: branches: - - release/v2.0.x + - release/v1.5.x - name: backport patches to v2.1.x branch conditions: - base=main @@ -73,7 +57,15 @@ pull_request_rules: actions: backport: branches: - - release/v2.2.x + - release/v2.2.x + - name: backport patches to v2.3.x branch + conditions: + - base=main + - label=backport-to-v2.3.x + actions: + backport: + branches: + - release/v2.3.x - name: backport patches to v3.0.x branch conditions: - base=main @@ -82,3 +74,11 @@ pull_request_rules: backport: branches: - release/v3.0.x + - name: backport patches to v3.1.x branch + conditions: + - base=main + - label=backport-to-v3.1.x + actions: + backport: + branches: + - release/v3.1.x From ce7ac2e2f09d537d491686d928981a9a47a224e9 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 10 May 2022 09:22:58 +0200 Subject: [PATCH 101/275] chore: renaming KeyForwardRelayerAddress to KeyRelayerAddressForAsyncAck (#1343) * renaming KeyForwardRelayerAddress to KeyRelayerAddressForAsyncAck * adding changelog entry Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 1 + modules/apps/29-fee/keeper/keeper.go | 8 ++++---- modules/apps/29-fee/types/keys.go | 8 ++++---- modules/apps/29-fee/types/keys_test.go | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65274b8fa95..b38ee315afc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. * (modules/29-fee)[\#1338](https://github.com/cosmos/ibc-go/pull/1338) Renaming `Result` field in `IncentivizedAcknowledgement` to `AppAcknowledgement`. +* (modules/29-fee)[\#1343](https://github.com/cosmos/ibc-go/pull/1343) Renaming `KeyForwardRelayerAddress` to `KeyRelayerAddressForAsyncAck`, and `ParseKeyForwardRelayerAddress` to `ParseKeyRelayerAddressForAsyncAck`. ### State Machine Breaking diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index e0317d3660a..da24e5a2772 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -191,13 +191,13 @@ func (k Keeper) GetAllRelayerAddresses(ctx sdk.Context) []types.RegisteredRelaye // SetRelayerAddressForAsyncAck sets the forward relayer address during OnRecvPacket in case of async acknowledgement func (k Keeper) SetRelayerAddressForAsyncAck(ctx sdk.Context, packetID channeltypes.PacketId, address string) { store := ctx.KVStore(k.storeKey) - store.Set(types.KeyForwardRelayerAddress(packetID), []byte(address)) + store.Set(types.KeyRelayerAddressForAsyncAck(packetID), []byte(address)) } // GetRelayerAddressForAsyncAck gets forward relayer address for a particular packet func (k Keeper) GetRelayerAddressForAsyncAck(ctx sdk.Context, packetID channeltypes.PacketId) (string, bool) { store := ctx.KVStore(k.storeKey) - key := types.KeyForwardRelayerAddress(packetID) + key := types.KeyRelayerAddressForAsyncAck(packetID) if !store.Has(key) { return "", false } @@ -214,7 +214,7 @@ func (k Keeper) GetAllForwardRelayerAddresses(ctx sdk.Context) []types.ForwardRe var forwardRelayerAddr []types.ForwardRelayerAddress for ; iterator.Valid(); iterator.Next() { - packetID, err := types.ParseKeyForwardRelayerAddress(string(iterator.Key())) + packetID, err := types.ParseKeyRelayerAddressForAsyncAck(string(iterator.Key())) if err != nil { panic(err) } @@ -233,7 +233,7 @@ func (k Keeper) GetAllForwardRelayerAddresses(ctx sdk.Context) []types.ForwardRe // Deletes the forwardRelayerAddr associated with the packetID func (k Keeper) DeleteForwardRelayerAddress(ctx sdk.Context, packetID channeltypes.PacketId) { store := ctx.KVStore(k.storeKey) - key := types.KeyForwardRelayerAddress(packetID) + key := types.KeyRelayerAddressForAsyncAck(packetID) store.Delete(key) } diff --git a/modules/apps/29-fee/types/keys.go b/modules/apps/29-fee/types/keys.go index 87318496a37..cf93967f84a 100644 --- a/modules/apps/29-fee/types/keys.go +++ b/modules/apps/29-fee/types/keys.go @@ -87,13 +87,13 @@ func ParseKeyCounterpartyRelayer(key string) (address string, channelID string, return keySplit[1], keySplit[2], nil } -// KeyForwardRelayerAddress returns the key for packetID -> forwardAddress mapping -func KeyForwardRelayerAddress(packetID channeltypes.PacketId) []byte { +// KeyRelayerAddressForAsyncAck returns the key for packetID -> forwardAddress mapping +func KeyRelayerAddressForAsyncAck(packetID channeltypes.PacketId) []byte { return []byte(fmt.Sprintf("%s/%s/%s/%d", ForwardRelayerPrefix, packetID.PortId, packetID.ChannelId, packetID.Sequence)) } -// ParseKeyForwardRelayerAddress parses the key used to store the forward relayer address and returns the packetID -func ParseKeyForwardRelayerAddress(key string) (channeltypes.PacketId, error) { +// ParseKeyRelayerAddressForAsyncAck parses the key used to store the forward relayer address and returns the packetID +func ParseKeyRelayerAddressForAsyncAck(key string) (channeltypes.PacketId, error) { keySplit := strings.Split(key, "/") if len(keySplit) != 4 { return channeltypes.PacketId{}, sdkerrors.Wrapf( diff --git a/modules/apps/29-fee/types/keys_test.go b/modules/apps/29-fee/types/keys_test.go index 22dc91b6a57..1bd229b57a3 100644 --- a/modules/apps/29-fee/types/keys_test.go +++ b/modules/apps/29-fee/types/keys_test.go @@ -113,7 +113,7 @@ func TestParseKeyForwardRelayerAddress(t *testing.T) { }{ { "success", - string(types.KeyForwardRelayerAddress(validPacketID)), + string(types.KeyRelayerAddressForAsyncAck(validPacketID)), true, }, { @@ -129,7 +129,7 @@ func TestParseKeyForwardRelayerAddress(t *testing.T) { } for _, tc := range testCases { - packetID, err := types.ParseKeyForwardRelayerAddress(tc.key) + packetID, err := types.ParseKeyRelayerAddressForAsyncAck(tc.key) if tc.expPass { require.NoError(t, err) From dcd0681d8f07c624f53b9a9ffe9de2f122486207 Mon Sep 17 00:00:00 2001 From: Sean King Date: Tue, 10 May 2022 17:27:59 +0200 Subject: [PATCH 102/275] refactor: channel handshake version improvements (#1283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: returning version from OnChanOpenInit * refactor: update tests and add version to proto resp * refactor: adding version to msg server resp * refactor: remove unncessary if & update version on Endpoint.Ack * fix: ics29 OnChanOpenInit remake versionMetaData before returning * chore: update godoc * test: adding check for expected version string * test: adding test case for passing empty version string to ics20 onChanOpenInit * Update modules/apps/29-fee/ibc_module.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * chore: comment * chore: changelog * fix: ica now discards auth module version * chore: update changelog * adding default version for ics29 * fix: using transfer module directly rather than calling full middleware stack * fix testing bug * refactor: test now uses bool for isFeeEnabled rather than direct check * docs: updating comment and migration docs Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- CHANGELOG.md | 1 + docs/migrations/v3-to-v4.md | 6 ++- .../controller/ibc_middleware.go | 17 ++++--- .../controller/ibc_middleware_test.go | 19 ++++++-- .../27-interchain-accounts/host/ibc_module.go | 4 +- modules/apps/29-fee/ibc_middleware.go | 44 ++++++++++++++----- modules/apps/29-fee/ibc_middleware_test.go | 42 +++++++++++++++--- modules/apps/29-fee/transfer_test.go | 1 - modules/apps/transfer/ibc_module.go | 15 ++++--- modules/apps/transfer/ibc_module_test.go | 18 +++++--- modules/core/05-port/types/module.go | 16 ++++--- modules/core/keeper/msg_server.go | 7 +-- testing/endpoint.go | 4 ++ testing/mock/ibc_app.go | 2 +- testing/mock/ibc_module.go | 12 +++-- 15 files changed, 151 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b38ee315afc..7968f31ea84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. +* (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) The `OnChanOpenInit` application callback now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). * (modules/29-fee)[\#1338](https://github.com/cosmos/ibc-go/pull/1338) Renaming `Result` field in `IncentivizedAcknowledgement` to `AppAcknowledgement`. * (modules/29-fee)[\#1343](https://github.com/cosmos/ibc-go/pull/1343) Renaming `KeyForwardRelayerAddress` to `KeyRelayerAddressForAsyncAck`, and `ParseKeyForwardRelayerAddress` to `ParseKeyRelayerAddressForAsyncAck`. diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 90e9af256d2..5a3d61deaae 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -1,4 +1,4 @@ -# Migrating from ibc-go v2 to v3 +# Migrating from ibc-go v3 to v4 This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. Any changes that must be done by a user of ibc-go should be documented here. @@ -23,4 +23,8 @@ No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-g The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. This is an API breaking change and as such IBC application developers will have to update any calls to `WriteAcknowledgement`. +The `OnChanOpenInit` application callback has been modified. +The return signature now includes the application version as detailed in the latest IBC [spec changes](https://github.com/cosmos/ibc/pull/629). + + diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index c12f5d3e9ce..9bf874fa8eb 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -45,18 +45,23 @@ func (im IBCMiddleware) OnChanOpenInit( chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { +) (string, error) { if !im.keeper.IsControllerEnabled(ctx) { - return types.ErrControllerSubModuleDisabled + return "", types.ErrControllerSubModuleDisabled } if err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version); err != nil { - return err + return "", err + } + + // call underlying app's OnChanOpenInit callback with the passed in version + // the version returned is discarded as the ica-auth module does not have permission to edit the version string. + // ics27 will always return the version string containing the Metadata struct which is created during the `RegisterInterchainAccount` call. + if _, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version); err != nil { + return "", err } - // call underlying app's OnChanOpenInit callback with the appVersion - return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, - chanCap, counterparty, version) + return version, nil } // OnChanOpenTry implements the IBCMiddleware interface diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index ea1b5185af2..dd7849efca9 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -147,8 +147,8 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID, channelID string, chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, - ) error { - return fmt.Errorf("mock ica auth fails") + ) (string, error) { + return "", fmt.Errorf("mock ica auth fails") } }, false, }, @@ -197,11 +197,24 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(), ) if tc.expPass { + expMetadata := icatypes.NewMetadata( + icatypes.Version, + path.EndpointA.ConnectionID, + path.EndpointB.ConnectionID, + "", + icatypes.EncodingProtobuf, + icatypes.TxTypeSDKMultiMsg, + ) + + expBytes, err := icatypes.ModuleCdc.MarshalJSON(&expMetadata) + suite.Require().NoError(err) + + suite.Require().Equal(version, string(expBytes)) suite.Require().NoError(err) } else { suite.Require().Error(err) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index fb403c71937..1598801601f 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -34,8 +34,8 @@ func (im IBCModule) OnChanOpenInit( chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { - return sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") +) (string, error) { + return "", sdkerrors.Wrap(icatypes.ErrInvalidChannelFlow, "channel handshake must be initiated by controller chain") } // OnChanOpenTry implements the IBCModule interface diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 96bb8be4030..3e6e7afb26d 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -1,6 +1,8 @@ package fee import ( + "strings" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" @@ -39,25 +41,44 @@ func (im IBCMiddleware) OnChanOpenInit( chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { +) (string, error) { var versionMetadata types.Metadata - if err := types.ModuleCdc.UnmarshalJSON([]byte(version), &versionMetadata); err != nil { - // Since it is valid for fee version to not be specified, the above middleware version may be for a middleware - // lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying - // application. - return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, - chanCap, counterparty, version) + + if strings.TrimSpace(version) == "" { + // default version + versionMetadata = types.Metadata{ + FeeVersion: types.Version, + AppVersion: "", + } + } else { + if err := types.ModuleCdc.UnmarshalJSON([]byte(version), &versionMetadata); err != nil { + // Since it is valid for fee version to not be specified, the above middleware version may be for a middleware + // lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying + // application. + return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, + chanCap, counterparty, version) + } } if versionMetadata.FeeVersion != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) + return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) + } + + appVersion, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, versionMetadata.AppVersion) + if err != nil { + return "", err + } + + versionMetadata.AppVersion = appVersion + versionBytes, err := types.ModuleCdc.MarshalJSON(&versionMetadata) + if err != nil { + return "", err } im.keeper.SetFeeEnabled(ctx, portID, channelID) // call underlying app's OnChanOpenInit callback with the appVersion - return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, - chanCap, counterparty, versionMetadata.AppVersion) + return string(versionBytes), nil } // OnChanOpenTry implements the IBCMiddleware interface @@ -94,7 +115,6 @@ func (im IBCMiddleware) OnChanOpenTry( } versionMetadata.AppVersion = appVersion - versionBytes, err := types.ModuleCdc.MarshalJSON(&versionMetadata) if err != nil { return "", err @@ -116,7 +136,7 @@ func (im IBCMiddleware) OnChanOpenAck( if im.keeper.IsFeeEnabled(ctx, portID, channelID) { var versionMetadata types.Metadata if err := types.ModuleCdc.UnmarshalJSON([]byte(counterpartyVersion), &versionMetadata); err != nil { - return sdkerrors.Wrap(types.ErrInvalidVersion, "failed to unmarshal ICS29 counterparty version metadata") + return sdkerrors.Wrapf(err, "failed to unmarshal ICS29 counterparty version metadata: %s", counterpartyVersion) } if versionMetadata.FeeVersion != types.Version { diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 8c76720ad3e..4b6d7f98959 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -25,34 +25,46 @@ var ( // Tests OnChanOpenInit on ChainA func (suite *FeeTestSuite) TestOnChanOpenInit() { testCases := []struct { - name string - version string - expPass bool + name string + version string + expPass bool + isFeeEnabled bool }{ { "success - valid fee middleware and mock version", string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), true, + true, }, { "success - fee version not included, only perform mock logic", ibcmock.Version, true, + false, }, { "invalid fee middleware version", string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: "invalid-ics29-1", AppVersion: ibcmock.Version})), false, + false, }, { "invalid mock version", string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: "invalid-mock-version"})), false, + false, }, { "mock version not wrapped", types.Version, false, + false, + }, + { + "passing an empty string returns default version", + "", + true, + true, }, } @@ -68,11 +80,11 @@ func (suite *FeeTestSuite) TestOnChanOpenInit() { suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID, channelID string, chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, - ) error { + ) (string, error) { if version != ibcmock.Version { - return fmt.Errorf("incorrect mock version") + return "", fmt.Errorf("incorrect mock version") } - return nil + return ibcmock.Version, nil } suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID @@ -95,13 +107,29 @@ func (suite *FeeTestSuite) TestOnChanOpenInit() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, chanCap, counterparty, channel.Version) if tc.expPass { + // check if the channel is fee enabled. If so version string should include metaData + if tc.isFeeEnabled { + versionMetadata := types.Metadata{ + FeeVersion: types.Version, + AppVersion: ibcmock.Version, + } + + versionBytes, err := types.ModuleCdc.MarshalJSON(&versionMetadata) + suite.Require().NoError(err) + + suite.Require().Equal(version, string(versionBytes)) + } else { + suite.Require().Equal(ibcmock.Version, version) + } + suite.Require().NoError(err, "unexpected error from version: %s", tc.version) } else { suite.Require().Error(err, "error not returned for version: %s", tc.version) + suite.Require().Equal("", version) } }) } diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 9d7557fd6c4..ba1f505d9c0 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -68,5 +68,4 @@ func (suite *FeeTestSuite) TestFeeTransfer() { fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)).Sub(originalChainASenderAccountBalance), ) - } diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index f5ed807d8b2..b9bfc2be189 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -3,6 +3,7 @@ package transfer import ( "fmt" "math" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -70,21 +71,25 @@ func (im IBCModule) OnChanOpenInit( chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { +) (string, error) { if err := ValidateTransferChannelParams(ctx, im.keeper, order, portID, channelID); err != nil { - return err + return "", err + } + + if strings.TrimSpace(version) == "" { + version = types.Version } if version != types.Version { - return sdkerrors.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version) + return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version) } // Claim channel capability passed back by IBC module if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err + return "", err } - return nil + return version, nil } // OnChanOpenTry implements the IBCModule interface. diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 3dcb5518cbb..95779ad2e8e 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -5,6 +5,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/ibc-go/v3/modules/apps/transfer" "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v3/modules/core/24-host" @@ -28,6 +29,11 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { { "success", func() {}, true, }, + { + "empty version string", func() { + channel.Version = "" + }, true, + }, { "max channels reached", func() { path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(math.MaxUint32 + 1) @@ -74,25 +80,23 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { Version: types.Version, } - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) - suite.Require().NoError(err) - + var err error chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, path.EndpointA.ChannelID)) suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) - tc.malleate() // explicitly change fields in channel and testChannel - err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + transferModule := transfer.NewIBCModule(suite.chainA.GetSimApp().TransferKeeper) + version, err := transferModule.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, counterparty, channel.GetVersion(), ) if tc.expPass { suite.Require().NoError(err) + suite.Require().Equal(types.Version, version) } else { suite.Require().Error(err) + suite.Require().Equal(version, "") } }) diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index e6ba8f3449b..7ac57479dbd 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -11,10 +11,16 @@ import ( // IBCModule defines an interface that implements all the callbacks // that modules must define as specified in ICS-26 type IBCModule interface { - // OnChanOpenInit will verify that the relayer-chosen parameters are - // valid and perform any custom INIT logic.It may return an error if - // the chosen parameters are invalid in which case the handshake is aborted. - // OnChanOpenInit should return an error if the provided version is invalid. + // OnChanOpenInit will verify that the relayer-chosen parameters + // are valid and perform any custom INIT logic. + // It may return an error if the chosen parameters are invalid + // in which case the handshake is aborted. + // If the provided version string is non-empty, OnChanOpenInit should return + // the version string if valid or an error if the provided version is invalid. + // If the version string is empty, OnChanOpenInit is expected to + // return a default version string representing the version(s) it supports. + // If there is no default version string for the application, + // it should return an error if provided version is empty string. OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, @@ -24,7 +30,7 @@ type IBCModule interface { channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, - ) error + ) (string, error) // OnChanOpenTry will verify the relayer-chosen parameters along with the // counterparty-chosen version string and perform custom TRY logic. diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index e8b7c0fd254..a4aeb496f6f 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -185,16 +185,17 @@ func (k Keeper) ChannelOpenInit(goCtx context.Context, msg *channeltypes.MsgChan } // Perform application logic callback - if err = cbs.OnChanOpenInit(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, channelID, cap, msg.Channel.Counterparty, msg.Channel.Version); err != nil { + version, err := cbs.OnChanOpenInit(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, channelID, cap, msg.Channel.Counterparty, msg.Channel.Version) + if err != nil { return nil, sdkerrors.Wrap(err, "channel open init callback failed") } // Write channel into state - k.ChannelKeeper.WriteOpenInitChannel(ctx, msg.PortId, channelID, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.Channel.Counterparty, msg.Channel.Version) + k.ChannelKeeper.WriteOpenInitChannel(ctx, msg.PortId, channelID, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.Channel.Counterparty, version) return &channeltypes.MsgChannelOpenInitResponse{ ChannelId: channelID, - Version: msg.Channel.Version, + Version: version, }, nil } diff --git a/testing/endpoint.go b/testing/endpoint.go index 02c4e9aac39..94fa14f8b0d 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -279,6 +279,10 @@ func (endpoint *Endpoint) ChanOpenInit() error { endpoint.ChannelID, err = ParseChannelIDFromEvents(res.GetEvents()) require.NoError(endpoint.Chain.T, err) + // update version to selected app version + // NOTE: this update must be performed after SendMsgs() + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + return nil } diff --git a/testing/mock/ibc_app.go b/testing/mock/ibc_app.go index 77eb17b8c6f..0504c2df0de 100644 --- a/testing/mock/ibc_app.go +++ b/testing/mock/ibc_app.go @@ -23,7 +23,7 @@ type MockIBCApp struct { channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, - ) error + ) (string, error) OnChanOpenTry func( ctx sdk.Context, diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index e58f6ae7156..69f3c388a8a 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "strconv" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" @@ -32,18 +33,21 @@ func NewIBCModule(appModule *AppModule, app *MockIBCApp) IBCModule { func (im IBCModule) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { +) (string, error) { + if strings.TrimSpace(version) == "" { + version = Version + } + if im.IBCApp.OnChanOpenInit != nil { return im.IBCApp.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) - } // Claim channel capability passed back by IBC module if err := im.IBCApp.ScopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err + return "", err } - return nil + return version, nil } // OnChanOpenTry implements the IBCModule interface. From ab8ab42f45cf6ade6e08c44321aec82613344bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 11 May 2022 12:28:19 +0200 Subject: [PATCH 103/275] fix: emit ics29 events on cacheCtx write after refunding on closed channel (#1344) ## Description closes: #1323 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- modules/apps/29-fee/keeper/escrow.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 0ca84684440..2c5b570320e 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -225,6 +225,9 @@ func (k Keeper) RefundFeesOnChannelClosure(ctx sdk.Context, portID, channelID st k.DeleteFeesInEscrow(cacheCtx, identifiedPacketFee.PacketId) } + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + // write the cache writeFn() From 23e7e7dcfbe6303e83fe1f6e3d984ade97fcbbd9 Mon Sep 17 00:00:00 2001 From: khanh <50263489+catShaark@users.noreply.github.com> Date: Thu, 12 May 2022 14:17:15 +0700 Subject: [PATCH 104/275] chore: improve DenomTrace grpc (#1342) * change DenomTrace grpc * update CHANGELOG.md * minor * minor * minor * minor * minor * minor * Update modules/apps/transfer/keeper/grpc_query_test.go Co-authored-by: Carlos Rodriguez * Update modules/apps/transfer/keeper/grpc_query_test.go Co-authored-by: Carlos Rodriguez * Update CHANGELOG.md Co-authored-by: Damian Nolan * use TrimPrefix() in DenomTrace() * update migration doc Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan --- CHANGELOG.md | 1 + docs/client/swagger-ui/swagger.yaml | 4 ++- docs/ibc/proto-docs.md | 2 +- docs/migrations/v3-to-v4.md | 3 +- modules/apps/transfer/client/cli/query.go | 10 +++--- modules/apps/transfer/keeper/grpc_query.go | 6 ++-- .../apps/transfer/keeper/grpc_query_test.go | 31 +++++++++++++------ modules/apps/transfer/types/query.pb.go | 2 +- .../ibc/applications/transfer/v1/query.proto | 2 +- 9 files changed, 40 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7968f31ea84..ee528da9e80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. * (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. * (middleware) [\#1022](https://github.com/cosmos/ibc-go/pull/1022) Add `GetAppVersion` to the ICS4Wrapper interface. This function should be used by IBC applications to obtain their own version since the version set in the channel structure may be wrapped many times by middleware. * (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml index 5feb43dd2a5..46ed1f188b8 100644 --- a/docs/client/swagger-ui/swagger.yaml +++ b/docs/client/swagger-ui/swagger.yaml @@ -235,7 +235,9 @@ paths: format: byte parameters: - name: hash - description: hash (in hex format) of the denomination trace information. + description: >- + hash (in hex format) or denom (full denom with ibc prefix) of the + denomination trace information. in: path required: true type: string diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 799ad8243ec..41b20e7abe1 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -1863,7 +1863,7 @@ method | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `hash` | [string](#string) | | hash (in hex format) of the denomination trace information. | +| `hash` | [string](#string) | | hash (in hex format) or denom (full denom with ibc prefix) of the denomination trace information. | diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 5a3d61deaae..5f684581ab2 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -26,5 +26,6 @@ This is an API breaking change and as such IBC application developers will have The `OnChanOpenInit` application callback has been modified. The return signature now includes the application version as detailed in the latest IBC [spec changes](https://github.com/cosmos/ibc/pull/629). +## Relayers - +When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. diff --git a/modules/apps/transfer/client/cli/query.go b/modules/apps/transfer/client/cli/query.go index 3239b154377..5eb1a1a0c9b 100644 --- a/modules/apps/transfer/client/cli/query.go +++ b/modules/apps/transfer/client/cli/query.go @@ -11,13 +11,13 @@ import ( "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" ) -// GetCmdQueryDenomTrace defines the command to query a a denomination trace from a given hash. +// GetCmdQueryDenomTrace defines the command to query a a denomination trace from a given trace hash or ibc denom. func GetCmdQueryDenomTrace() *cobra.Command { cmd := &cobra.Command{ - Use: "denom-trace [hash]", - Short: "Query the denom trace info from a given trace hash", - Long: "Query the denom trace info from a given trace hash", - Example: fmt.Sprintf("%s query ibc-transfer denom-trace [hash]", version.AppName), + Use: "denom-trace [hash/denom]", + Short: "Query the denom trace info from a given trace hash or ibc denom", + Long: "Query the denom trace info from a given trace hash or ibc denom", + Example: fmt.Sprintf("%s query ibc-transfer denom-trace [hash/denom]", version.AppName), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) diff --git a/modules/apps/transfer/keeper/grpc_query.go b/modules/apps/transfer/keeper/grpc_query.go index e0b16c6a761..5e7c5e7d295 100644 --- a/modules/apps/transfer/keeper/grpc_query.go +++ b/modules/apps/transfer/keeper/grpc_query.go @@ -3,6 +3,7 @@ package keeper import ( "context" "fmt" + "strings" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -22,9 +23,10 @@ func (q Keeper) DenomTrace(c context.Context, req *types.QueryDenomTraceRequest) return nil, status.Error(codes.InvalidArgument, "empty request") } - hash, err := types.ParseHexHash(req.Hash) + hash, err := types.ParseHexHash(strings.TrimPrefix(req.Hash, "ibc/")) + if err != nil { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid denom trace hash %s, %s", req.Hash, err)) + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid denom trace hash: %s, error: %s", hash.String(), err)) } ctx := sdk.UnwrapSDKContext(c) diff --git a/modules/apps/transfer/keeper/grpc_query_test.go b/modules/apps/transfer/keeper/grpc_query_test.go index 34563447b5f..963abd21577 100644 --- a/modules/apps/transfer/keeper/grpc_query_test.go +++ b/modules/apps/transfer/keeper/grpc_query_test.go @@ -21,37 +21,50 @@ func (suite *KeeperTestSuite) TestQueryDenomTrace() { expPass bool }{ { - "invalid hex hash", + "success: correct ibc denom", func() { + expTrace.Path = "transfer/channelToA/transfer/channelToB" + expTrace.BaseDenom = "uatom" + suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), expTrace) + req = &types.QueryDenomTraceRequest{ - Hash: "!@#!@#!", + Hash: expTrace.IBCDenom(), } }, - false, + true, }, { - "not found denom trace", + "success: correct hex hash", func() { expTrace.Path = "transfer/channelToA/transfer/channelToB" expTrace.BaseDenom = "uatom" + suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), expTrace) + req = &types.QueryDenomTraceRequest{ Hash: expTrace.Hash().String(), } }, + true, + }, + { + "failure: invalid hash", + func() { + req = &types.QueryDenomTraceRequest{ + Hash: "!@#!@#!", + } + }, false, }, { - "success", + "failure: not found denom trace", func() { expTrace.Path = "transfer/channelToA/transfer/channelToB" expTrace.BaseDenom = "uatom" - suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), expTrace) - req = &types.QueryDenomTraceRequest{ - Hash: expTrace.Hash().String(), + Hash: expTrace.IBCDenom(), } }, - true, + false, }, } diff --git a/modules/apps/transfer/types/query.pb.go b/modules/apps/transfer/types/query.pb.go index 024da758162..e1206ab0e30 100644 --- a/modules/apps/transfer/types/query.pb.go +++ b/modules/apps/transfer/types/query.pb.go @@ -33,7 +33,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC // method type QueryDenomTraceRequest struct { - // hash (in hex format) of the denomination trace information. + // hash (in hex format) or denom (full denom with ibc prefix) of the denomination trace information. Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` } diff --git a/proto/ibc/applications/transfer/v1/query.proto b/proto/ibc/applications/transfer/v1/query.proto index 2ed28049fd7..8491c52139b 100644 --- a/proto/ibc/applications/transfer/v1/query.proto +++ b/proto/ibc/applications/transfer/v1/query.proto @@ -35,7 +35,7 @@ service Query { // QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC // method message QueryDenomTraceRequest { - // hash (in hex format) of the denomination trace information. + // hash (in hex format) or denom (full denom with ibc prefix) of the denomination trace information. string hash = 1; } From 10dc9297e250c857ac8617b7ad3ec5afca2a2358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 12 May 2022 12:05:32 +0200 Subject: [PATCH 105/275] fix: disallow incentivizing packets which have not been sent or have been already relayed (#1347) ## Description closes: #1318 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [x] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [x] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [x] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [x] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [x] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [x] Review `Codecov Report` in the comment section below once CI passes --- modules/apps/29-fee/keeper/keeper.go | 5 ++ modules/apps/29-fee/keeper/msg_server.go | 19 ++++++- modules/apps/29-fee/keeper/msg_server_test.go | 56 ++++++++++++++++++- modules/apps/29-fee/types/expected_keepers.go | 1 + modules/core/04-channel/types/errors.go | 1 + 5 files changed, 80 insertions(+), 2 deletions(-) diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index da24e5a2772..c7e31ad3d1a 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -64,6 +64,11 @@ func (k Keeper) GetChannel(ctx sdk.Context, portID, channelID string) (channelty return k.channelKeeper.GetChannel(ctx, portID, channelID) } +// GetPacketCommitment wraps IBC ChannelKeeper's GetPacketCommitment function +func (k Keeper) GetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) []byte { + return k.channelKeeper.GetPacketCommitment(ctx, portID, channelID, sequence) +} + // GetNextSequenceSend wraps IBC ChannelKeeper's GetNextSequenceSend function func (k Keeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) { return k.channelKeeper.GetNextSequenceSend(ctx, portID, channelID) diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index 69f6520c759..033fb67439a 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -4,6 +4,7 @@ import ( "context" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -58,7 +59,8 @@ func (k Keeper) PayPacketFee(goCtx context.Context, msg *types.MsgPayPacketFee) // PayPacketFee defines a rpc handler method for MsgPayPacketFee // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to -// incentivize the relaying of a known packet +// incentivize the relaying of a known packet. Only packets which have been sent and have not gone through the +// packet life cycle may be incentivized. func (k Keeper) PayPacketFeeAsync(goCtx context.Context, msg *types.MsgPayPacketFeeAsync) (*types.MsgPayPacketFeeAsyncResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -71,6 +73,21 @@ func (k Keeper) PayPacketFeeAsync(goCtx context.Context, msg *types.MsgPayPacket return nil, types.ErrFeeModuleLocked } + nextSeqSend, found := k.GetNextSequenceSend(ctx, msg.PacketId.PortId, msg.PacketId.ChannelId) + if !found { + return nil, sdkerrors.Wrapf(channeltypes.ErrSequenceSendNotFound, "channel does not exist, portID: %s, channelID: %s", msg.PacketId.PortId, msg.PacketId.ChannelId) + } + + // only allow incentivizing of packets which have been sent + if msg.PacketId.Sequence >= nextSeqSend { + return nil, channeltypes.ErrPacketNotSent + } + + // only allow incentivizng of packets which have not completed the packet life cycle + if bz := k.GetPacketCommitment(ctx, msg.PacketId.PortId, msg.PacketId.ChannelId, msg.PacketId.Sequence); len(bz) == 0 { + return nil, sdkerrors.Wrapf(channeltypes.ErrPacketCommitmentNotFound, "packet has already been acknowledged or timed out") + } + if err := k.escrowPacketFee(ctx, msg.PacketId, msg.PacketFee); err != nil { return nil, err } diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 8a927559a51..9de87d64121 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" ) @@ -186,6 +187,7 @@ func (suite *KeeperTestSuite) TestPayPacketFee() { func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { var ( + packet channeltypes.Packet expEscrowBalance sdk.Coins expFeesInEscrow []types.PacketFee msg *types.MsgPayPacketFeeAsync @@ -234,6 +236,53 @@ func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { }, false, }, + { + "channel does not exist", + func() { + msg.PacketId.ChannelId = "channel-100" + + // to test this functionality, we must set the fee to enabled for this non existent channel + // NOTE: the channel doesn't exist in 04-channel keeper, but we will add a mapping within ics29 anyways + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeeEnabled(suite.chainA.GetContext(), msg.PacketId.PortId, msg.PacketId.ChannelId) + }, + false, + }, + { + "packet not sent", + func() { + msg.PacketId.Sequence = msg.PacketId.Sequence + 1 + }, + false, + }, + { + "packet already acknowledged", + func() { + err := suite.path.RelayPacket(packet) + suite.Require().NoError(err) + }, + false, + }, + { + "packet already timed out", + func() { + // try to incentivze a packet which is timed out + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, msg.PacketId.Sequence+1) + packet = channeltypes.NewPacket(ibctesting.MockPacketData, packetID.Sequence, packetID.PortId, packetID.ChannelId, suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), 0) + + err := suite.path.EndpointA.SendPacket(packet) + suite.Require().NoError(err) + + // need to update chainA's client representing chainB to prove missing ack + err = suite.path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + err = suite.path.EndpointA.TimeoutPacket(packet) + suite.Require().NoError(err) + + msg.PacketId = packetID + }, + false, + }, { "invalid refund address", func() { @@ -278,7 +327,12 @@ func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { suite.SetupTest() suite.coordinator.Setup(suite.path) // setup channel + // send a packet to incentivize packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + packet = channeltypes.NewPacket(ibctesting.MockPacketData, packetID.Sequence, packetID.PortId, packetID.ChannelId, suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, clienttypes.NewHeight(clienttypes.ParseChainID(suite.chainB.ChainID), 100), 0) + err := suite.path.EndpointA.SendPacket(packet) + suite.Require().NoError(err) + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, suite.chainA.SenderAccount.GetAddress().String(), nil) @@ -288,7 +342,7 @@ func (suite *KeeperTestSuite) TestPayPacketFeeAsync() { tc.malleate() - _, err := suite.chainA.GetSimApp().IBCFeeKeeper.PayPacketFeeAsync(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) + _, err = suite.chainA.GetSimApp().IBCFeeKeeper.PayPacketFeeAsync(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) if tc.expPass { suite.Require().NoError(err) // message committed diff --git a/modules/apps/29-fee/types/expected_keepers.go b/modules/apps/29-fee/types/expected_keepers.go index 1d9d3439b07..f725ff764b3 100644 --- a/modules/apps/29-fee/types/expected_keepers.go +++ b/modules/apps/29-fee/types/expected_keepers.go @@ -24,6 +24,7 @@ type ICS4Wrapper interface { // ChannelKeeper defines the expected IBC channel keeper type ChannelKeeper interface { GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) + GetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) []byte GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) } diff --git a/modules/core/04-channel/types/errors.go b/modules/core/04-channel/types/errors.go index 8c31cfbae18..efe90f165c0 100644 --- a/modules/core/04-channel/types/errors.go +++ b/modules/core/04-channel/types/errors.go @@ -38,4 +38,5 @@ var ( ErrNoOpMsg = sdkerrors.Register(SubModuleName, 23, "message is redundant, no-op will be performed") ErrInvalidChannelVersion = sdkerrors.Register(SubModuleName, 24, "invalid channel version") + ErrPacketNotSent = sdkerrors.Register(SubModuleName, 25, "packet has not been sent") ) From 9f70a070d773f8bfdb62d4205d8878f3149f351a Mon Sep 17 00:00:00 2001 From: Sean King Date: Thu, 12 May 2022 13:50:53 +0200 Subject: [PATCH 106/275] refactor: adding check if channel exists before register counterparty (#1339) * refactor: adding check if channel exists before register. updating msg to contain PortID * chore: changelog * refactor: add types test and check for is fee enabled + fix test --- docs/ibc/proto-docs.md | 1 + modules/apps/29-fee/client/cli/tx.go | 8 +- modules/apps/29-fee/keeper/msg_server.go | 9 ++ modules/apps/29-fee/keeper/msg_server_test.go | 23 +++- modules/apps/29-fee/transfer_test.go | 2 +- modules/apps/29-fee/types/msgs.go | 8 +- modules/apps/29-fee/types/msgs_test.go | 11 +- modules/apps/29-fee/types/tx.pb.go | 130 ++++++++++++------ proto/ibc/applications/fee/v1/tx.proto | 4 +- 9 files changed, 142 insertions(+), 54 deletions(-) diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 41b20e7abe1..db7c27316c4 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -1293,6 +1293,7 @@ MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterp | ----- | ---- | ----- | ----------- | | `address` | [string](#string) | | the relayer address | | `counterparty_address` | [string](#string) | | the counterparty relayer address | +| `port_id` | [string](#string) | | unique port identifier | | `channel_id` | [string](#string) | | unique channel identifier | diff --git a/modules/apps/29-fee/client/cli/tx.go b/modules/apps/29-fee/client/cli/tx.go index f1f858b60cd..81a8192d950 100644 --- a/modules/apps/29-fee/client/cli/tx.go +++ b/modules/apps/29-fee/client/cli/tx.go @@ -101,18 +101,18 @@ func NewPayPacketFeeAsyncTxCmd() *cobra.Command { // NewRegisterCounterpartyAddress returns the command to create a MsgRegisterCounterpartyAddress func NewRegisterCounterpartyAddress() *cobra.Command { cmd := &cobra.Command{ - Use: "register-counterparty [address] [counterparty-address] [channel-id]", + Use: "register-counterparty [address] [counterparty-address] [channel-id] [port-id]", Short: "Register a counterparty relayer address on a given channel.", Long: strings.TrimSpace(`Register a counterparty relayer address on a given channel.`), - Example: fmt.Sprintf("%s tx ibc-fee register-counterparty cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 channel-0", version.AppName), - Args: cobra.ExactArgs(3), + Example: fmt.Sprintf("%s tx ibc-fee register-counterparty cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 channel-0 transfer", version.AppName), + Args: cobra.ExactArgs(4), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { return err } - msg := types.NewMsgRegisterCounterpartyAddress(args[0], args[1], args[2]) + msg := types.NewMsgRegisterCounterpartyAddress(args[0], args[1], args[2], args[3]) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index 033fb67439a..154a4150f54 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -18,6 +18,15 @@ var _ types.MsgServer = Keeper{} func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.MsgRegisterCounterpartyAddress) (*types.MsgRegisterCounterpartyAddressResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + // only register counterparty address if the channel exists and is fee enabled + if _, found := k.channelKeeper.GetChannel(ctx, msg.PortId, msg.ChannelId); !found { + return nil, channeltypes.ErrChannelNotFound + } + + if !k.IsFeeEnabled(ctx, msg.PortId, msg.ChannelId) { + return nil, types.ErrFeeNotEnabled + } + k.SetCounterpartyAddress( ctx, msg.Address, msg.CounterpartyAddress, msg.ChannelId, ) diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 9de87d64121..84c7588a6b2 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -13,6 +13,8 @@ func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() { var ( sender string counterparty string + channelID string + ctx sdk.Context ) testCases := []struct { @@ -30,18 +32,33 @@ func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() { true, func() { counterparty = "arbitrary-string" }, }, + { + "channel does not exist", + false, + func() { channelID = "channel-22" }, + }, + { + "channel is not fee enabled", + false, + func() { + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(ctx, suite.path.EndpointA.ChannelConfig.PortID, channelID) + }, + }, } for _, tc := range testCases { suite.SetupTest() - ctx := suite.chainA.GetContext() + ctx = suite.chainA.GetContext() + suite.coordinator.Setup(suite.path) // setup channel sender = suite.chainA.SenderAccount.GetAddress().String() counterparty = suite.chainB.SenderAccount.GetAddress().String() + channelID = suite.path.EndpointA.ChannelID + tc.malleate() - msg := types.NewMsgRegisterCounterpartyAddress(sender, counterparty, ibctesting.FirstChannelID) - _, err := suite.chainA.SendMsgs(msg) + msg := types.NewMsgRegisterCounterpartyAddress(sender, counterparty, suite.path.EndpointA.ChannelConfig.PortID, channelID) + _, err := suite.chainA.GetSimApp().IBCFeeKeeper.RegisterCounterpartyAddress(sdk.WrapSDKContext(ctx), msg) if tc.expPass { suite.Require().NoError(err) // message committed diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index ba1f505d9c0..2bfaff2f097 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -46,7 +46,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() { // to differentiate from the chainA.SenderAccount for checking successful relay payouts relayerAddress := suite.chainB.SenderAccount.GetAddress() - msgRegister := types.NewMsgRegisterCounterpartyAddress(suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String(), ibctesting.FirstChannelID) + msgRegister := types.NewMsgRegisterCounterpartyAddress(suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) _, err = suite.chainB.SendMsgs(msgRegister) suite.Require().NoError(err) // message committed diff --git a/modules/apps/29-fee/types/msgs.go b/modules/apps/29-fee/types/msgs.go index d2fec3e542f..594f8d81251 100644 --- a/modules/apps/29-fee/types/msgs.go +++ b/modules/apps/29-fee/types/msgs.go @@ -17,10 +17,11 @@ const ( ) // NewMsgRegisterCounterpartyAddress creates a new instance of MsgRegisterCounterpartyAddress -func NewMsgRegisterCounterpartyAddress(address, counterpartyAddress, channelID string) *MsgRegisterCounterpartyAddress { +func NewMsgRegisterCounterpartyAddress(address, counterpartyAddress, portID, channelID string) *MsgRegisterCounterpartyAddress { return &MsgRegisterCounterpartyAddress{ Address: address, CounterpartyAddress: counterpartyAddress, + PortId: portID, ChannelId: channelID, } } @@ -36,6 +37,11 @@ func (msg MsgRegisterCounterpartyAddress) ValidateBasic() error { return ErrCounterpartyAddressEmpty } + // validate portId + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return err + } + // validate channelId if err := host.ChannelIdentifierValidator(msg.ChannelId); err != nil { return err diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go index d314a4f4193..7b224b5a66c 100644 --- a/modules/apps/29-fee/types/msgs_test.go +++ b/modules/apps/29-fee/types/msgs_test.go @@ -55,10 +55,17 @@ func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { }, false, }, + { + "invalid portID", + func() { + msg.PortId = "" + }, + false, + }, } for i, tc := range testCases { - msg = types.NewMsgRegisterCounterpartyAddress(defaultAccAddress, defaultAccAddress, ibctesting.FirstChannelID) + msg = types.NewMsgRegisterCounterpartyAddress(defaultAccAddress, defaultAccAddress, ibctesting.MockPort, ibctesting.FirstChannelID) tc.malleate() @@ -74,7 +81,7 @@ func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { func TestRegisterCountepartyAddressGetSigners(t *testing.T) { accAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - msg := types.NewMsgRegisterCounterpartyAddress(accAddress.String(), defaultAccAddress, ibctesting.FirstChannelID) + msg := types.NewMsgRegisterCounterpartyAddress(accAddress.String(), defaultAccAddress, ibctesting.MockPort, ibctesting.FirstChannelID) require.Equal(t, []sdk.AccAddress{sdk.AccAddress(accAddress)}, msg.GetSigners()) } diff --git a/modules/apps/29-fee/types/tx.pb.go b/modules/apps/29-fee/types/tx.pb.go index 1cecc607dc9..66827e58cc6 100644 --- a/modules/apps/29-fee/types/tx.pb.go +++ b/modules/apps/29-fee/types/tx.pb.go @@ -35,8 +35,10 @@ type MsgRegisterCounterpartyAddress struct { Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // the counterparty relayer address CounterpartyAddress string `protobuf:"bytes,2,opt,name=counterparty_address,json=counterpartyAddress,proto3" json:"counterparty_address,omitempty" yaml:"counterparty_address"` + // unique port identifier + PortId string `protobuf:"bytes,3,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` // unique channel identifier - ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + ChannelId string `protobuf:"bytes,4,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` } func (m *MsgRegisterCounterpartyAddress) Reset() { *m = MsgRegisterCounterpartyAddress{} } @@ -288,47 +290,48 @@ func init() { func init() { proto.RegisterFile("ibc/applications/fee/v1/tx.proto", fileDescriptor_05c93128649f1b96) } var fileDescriptor_05c93128649f1b96 = []byte{ - // 630 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4d, 0x4f, 0xdb, 0x40, - 0x10, 0x8d, 0x09, 0xa5, 0x64, 0x8b, 0x4a, 0xb3, 0x85, 0x62, 0x0c, 0xb5, 0xa9, 0x0f, 0x55, 0x2e, - 0xd8, 0xe5, 0x4b, 0x55, 0xb9, 0x20, 0x82, 0x84, 0xca, 0x01, 0x15, 0x59, 0x3d, 0x55, 0x95, 0x90, - 0xb3, 0x9e, 0x18, 0xb7, 0x89, 0xd7, 0xda, 0x75, 0xa2, 0xfa, 0x0f, 0x54, 0x3d, 0x72, 0xeb, 0x95, - 0x9f, 0xc3, 0xa9, 0xe2, 0xd0, 0x43, 0x4f, 0x56, 0x05, 0x97, 0x9e, 0xf3, 0x0b, 0xaa, 0xf5, 0x97, - 0x1c, 0x48, 0x22, 0xda, 0x9b, 0x77, 0xe6, 0xcd, 0xdb, 0x37, 0x6f, 0xc6, 0x8b, 0xd6, 0xbc, 0x16, - 0x31, 0xed, 0x20, 0xe8, 0x78, 0xc4, 0x0e, 0x3d, 0xea, 0x73, 0xb3, 0x0d, 0x60, 0xf6, 0x37, 0xcc, - 0xf0, 0x8b, 0x11, 0x30, 0x1a, 0x52, 0xbc, 0xe4, 0xb5, 0x88, 0x51, 0x46, 0x18, 0x6d, 0x00, 0xa3, - 0xbf, 0xa1, 0x2c, 0xb8, 0xd4, 0xa5, 0x09, 0xc6, 0x14, 0x5f, 0x29, 0x5c, 0x79, 0x31, 0x8e, 0x50, - 0x54, 0x95, 0x20, 0x84, 0x32, 0x30, 0xc9, 0x99, 0xed, 0xfb, 0xd0, 0x11, 0xe9, 0xec, 0x33, 0x85, - 0xe8, 0x3f, 0x24, 0xa4, 0x1e, 0x73, 0xd7, 0x02, 0xd7, 0xe3, 0x21, 0xb0, 0x03, 0xda, 0xf3, 0x43, - 0x60, 0x81, 0xcd, 0xc2, 0x68, 0xdf, 0x71, 0x18, 0x70, 0x8e, 0x65, 0xf4, 0xd0, 0x4e, 0x3f, 0x65, - 0x69, 0x4d, 0x6a, 0xd4, 0xac, 0xfc, 0x88, 0x2d, 0xb4, 0x40, 0x4a, 0x05, 0xa7, 0x39, 0x6c, 0x4a, - 0xc0, 0x9a, 0xda, 0x20, 0xd6, 0x56, 0x22, 0xbb, 0xdb, 0xd9, 0xd5, 0x47, 0xa1, 0x74, 0xeb, 0x29, - 0x19, 0x71, 0xdb, 0x36, 0x42, 0x99, 0xc2, 0x53, 0xcf, 0x91, 0xab, 0x09, 0xd3, 0xe2, 0x20, 0xd6, - 0xea, 0x19, 0x53, 0x91, 0xd3, 0xad, 0x5a, 0x76, 0x38, 0x72, 0x76, 0x67, 0xbf, 0x5d, 0x68, 0x95, - 0x3f, 0x17, 0x5a, 0x45, 0x6f, 0xa0, 0x97, 0x93, 0xfb, 0xb1, 0x80, 0x07, 0xd4, 0xe7, 0xa0, 0x9f, - 0x4f, 0xa1, 0xf9, 0x63, 0xee, 0x9e, 0xd8, 0xd1, 0x89, 0x4d, 0x3e, 0x43, 0x78, 0x08, 0x80, 0xb7, - 0x51, 0xb5, 0x0d, 0x90, 0xf4, 0xf9, 0x68, 0x73, 0xd5, 0x18, 0x33, 0x11, 0xe3, 0x10, 0xa0, 0x39, - 0x7d, 0x19, 0x6b, 0x15, 0x4b, 0xc0, 0xf1, 0x1e, 0x7a, 0xcc, 0x69, 0x8f, 0x11, 0x38, 0x0d, 0x28, - 0x0b, 0x85, 0xee, 0xd4, 0x81, 0xe5, 0x41, 0xac, 0x2d, 0xa6, 0xba, 0x87, 0xf3, 0xba, 0x35, 0x97, - 0x06, 0x4e, 0x28, 0x0b, 0x8f, 0x1c, 0xfc, 0x16, 0xd5, 0x33, 0xc0, 0x9d, 0xde, 0x57, 0x07, 0xb1, - 0x26, 0x0f, 0x71, 0x94, 0x2d, 0x98, 0x4f, 0x63, 0x07, 0xb9, 0x11, 0xf8, 0x19, 0x9a, 0xe1, 0x9e, - 0xeb, 0x03, 0x93, 0xa7, 0x93, 0x59, 0x65, 0x27, 0xac, 0xa0, 0x59, 0x06, 0x1d, 0x3b, 0x02, 0xc6, - 0xe5, 0x07, 0x6b, 0xd5, 0x46, 0xcd, 0x2a, 0xce, 0x25, 0xf3, 0x96, 0xd1, 0xd2, 0x2d, 0x47, 0x0a, - 0xb7, 0x7e, 0x4a, 0x68, 0xe1, 0x56, 0x6e, 0x9f, 0x47, 0x3e, 0xc1, 0xef, 0x51, 0x2d, 0x48, 0x22, - 0x42, 0x73, 0x6a, 0xdc, 0xf3, 0xc4, 0x38, 0xb1, 0x78, 0x46, 0xbe, 0x6d, 0xfd, 0x0d, 0x23, 0xad, - 0x3b, 0x72, 0x9a, 0xb2, 0x70, 0x6e, 0x10, 0x6b, 0x4f, 0xd2, 0xb6, 0x8a, 0x6a, 0xdd, 0x9a, 0x0d, - 0x32, 0x0c, 0xfe, 0x88, 0x50, 0x16, 0x17, 0xf3, 0x98, 0x4a, 0x68, 0xf5, 0xb1, 0xf3, 0x28, 0x24, - 0x35, 0x97, 0x33, 0xee, 0xfa, 0x10, 0x77, 0x1b, 0x40, 0xb7, 0x32, 0x99, 0x87, 0x00, 0xa5, 0x8e, - 0x55, 0xb4, 0x3a, 0xaa, 0xab, 0xbc, 0xed, 0xcd, 0xaf, 0x55, 0x54, 0x3d, 0xe6, 0x2e, 0xfe, 0x2e, - 0xa1, 0x95, 0x49, 0x3f, 0xc9, 0xeb, 0xb1, 0xda, 0x26, 0x6f, 0xa3, 0xb2, 0xf7, 0x9f, 0x85, 0xb9, - 0x42, 0xfc, 0x09, 0xcd, 0x0d, 0xad, 0x70, 0x63, 0x12, 0x61, 0x19, 0xa9, 0xbc, 0xba, 0x2f, 0xb2, - 0xb8, 0x2b, 0x42, 0xf5, 0xbb, 0x0b, 0xb0, 0x7e, 0x5f, 0x9a, 0x04, 0xae, 0xec, 0xfc, 0x13, 0x3c, - 0xbf, 0xba, 0xf9, 0xee, 0xf2, 0x5a, 0x95, 0xae, 0xae, 0x55, 0xe9, 0xf7, 0xb5, 0x2a, 0x9d, 0xdf, - 0xa8, 0x95, 0xab, 0x1b, 0xb5, 0xf2, 0xeb, 0x46, 0xad, 0x7c, 0xd8, 0x71, 0xbd, 0xf0, 0xac, 0xd7, - 0x32, 0x08, 0xed, 0x9a, 0x84, 0xf2, 0x2e, 0xe5, 0xa6, 0xd7, 0x22, 0xeb, 0x2e, 0x35, 0xfb, 0x5b, - 0x66, 0x97, 0x3a, 0xbd, 0x0e, 0x70, 0xf1, 0x50, 0x72, 0x73, 0xf3, 0xcd, 0xba, 0x78, 0x23, 0xc3, - 0x28, 0x00, 0xde, 0x9a, 0x49, 0x1e, 0xc0, 0xad, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xf7, - 0x58, 0xab, 0x99, 0x05, 0x00, 0x00, + // 650 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xbf, 0x4f, 0xdb, 0x40, + 0x14, 0xc7, 0x63, 0x42, 0x81, 0x5c, 0x11, 0x34, 0x57, 0x28, 0x21, 0x50, 0x9b, 0x7a, 0xa8, 0x22, + 0x55, 0xd8, 0xe5, 0x97, 0xaa, 0xb2, 0x20, 0x82, 0x84, 0xca, 0x80, 0x8a, 0x4e, 0x9d, 0xaa, 0x4a, + 0xc8, 0x39, 0xbf, 0x18, 0xb7, 0x89, 0xcf, 0xf2, 0x39, 0x51, 0xfd, 0x0f, 0x54, 0x1d, 0xd9, 0xba, + 0xf2, 0xe7, 0x30, 0x32, 0x74, 0xe8, 0x64, 0x55, 0xb0, 0x74, 0xf6, 0xda, 0xa5, 0x3a, 0x9f, 0x1d, + 0x39, 0x94, 0x44, 0xb4, 0xdb, 0xdd, 0xbd, 0xcf, 0xfb, 0xde, 0x7b, 0x5f, 0x3f, 0x1f, 0x5a, 0x73, + 0x5b, 0xd4, 0xb4, 0x7c, 0xbf, 0xe3, 0x52, 0x2b, 0x74, 0x99, 0xc7, 0xcd, 0x36, 0x80, 0xd9, 0xdf, + 0x30, 0xc3, 0xcf, 0x86, 0x1f, 0xb0, 0x90, 0xe1, 0x25, 0xb7, 0x45, 0x8d, 0x22, 0x61, 0xb4, 0x01, + 0x8c, 0xfe, 0x46, 0x7d, 0xc1, 0x61, 0x0e, 0x4b, 0x19, 0x53, 0xac, 0x24, 0x5e, 0x7f, 0x36, 0x4a, + 0x50, 0x64, 0x15, 0x10, 0xca, 0x02, 0x30, 0xe9, 0x99, 0xe5, 0x79, 0xd0, 0x11, 0xe1, 0x6c, 0x29, + 0x11, 0xfd, 0xb7, 0x82, 0xd4, 0x63, 0xee, 0x10, 0x70, 0x5c, 0x1e, 0x42, 0x70, 0xc0, 0x7a, 0x5e, + 0x08, 0x81, 0x6f, 0x05, 0x61, 0xb4, 0x6f, 0xdb, 0x01, 0x70, 0x8e, 0x6b, 0x68, 0xda, 0x92, 0xcb, + 0x9a, 0xb2, 0xa6, 0x34, 0x2a, 0x24, 0xdf, 0x62, 0x82, 0x16, 0x68, 0x21, 0xe1, 0x34, 0xc7, 0x26, + 0x04, 0xd6, 0xd4, 0x92, 0x58, 0x5b, 0x89, 0xac, 0x6e, 0x67, 0x57, 0xbf, 0x8b, 0xd2, 0xc9, 0x63, + 0x7a, 0xc7, 0x6d, 0x2f, 0xd0, 0xb4, 0xcf, 0x82, 0xf0, 0xd4, 0xb5, 0x6b, 0xe5, 0x54, 0x06, 0x27, + 0xb1, 0x36, 0x27, 0x65, 0xb2, 0x80, 0x4e, 0xa6, 0xc4, 0xea, 0xc8, 0xc6, 0xdb, 0x08, 0x65, 0xed, + 0x08, 0x7e, 0x32, 0xe5, 0x17, 0x93, 0x58, 0xab, 0x66, 0xd7, 0x0e, 0x62, 0x3a, 0xa9, 0x64, 0x9b, + 0x23, 0x7b, 0x77, 0xe6, 0xeb, 0x85, 0x56, 0xfa, 0x75, 0xa1, 0x95, 0xf4, 0x06, 0x7a, 0x3e, 0xbe, + 0x79, 0x02, 0xdc, 0x67, 0x1e, 0x07, 0xfd, 0x7c, 0x02, 0xcd, 0x1f, 0x73, 0xe7, 0xc4, 0x8a, 0x4e, + 0x2c, 0xfa, 0x09, 0xc2, 0x43, 0x00, 0xbc, 0x8d, 0xca, 0x6d, 0x80, 0xd4, 0x94, 0x87, 0x9b, 0xab, + 0xc6, 0x88, 0xcf, 0x67, 0x1c, 0x02, 0x34, 0x27, 0x2f, 0x63, 0xad, 0x44, 0x04, 0x8e, 0xf7, 0xd0, + 0x1c, 0x67, 0xbd, 0x80, 0xc2, 0x69, 0xde, 0xa7, 0xb4, 0x6b, 0x39, 0x89, 0xb5, 0x45, 0x59, 0xf7, + 0x70, 0x5c, 0x27, 0xb3, 0xf2, 0xe0, 0x44, 0x36, 0xfd, 0x06, 0x55, 0x33, 0xa0, 0xd0, 0xbb, 0xf4, + 0x6a, 0x35, 0x89, 0xb5, 0xda, 0x90, 0x46, 0xd1, 0x82, 0x79, 0x79, 0x76, 0x90, 0x1b, 0x81, 0x9f, + 0xa0, 0x29, 0xee, 0x3a, 0x1e, 0x04, 0xd2, 0x3a, 0x92, 0xed, 0x70, 0x1d, 0xcd, 0x04, 0xd0, 0xb1, + 0x22, 0x08, 0x78, 0xed, 0xc1, 0x5a, 0xb9, 0x51, 0x21, 0x83, 0x7d, 0xc1, 0xbc, 0x65, 0xb4, 0x74, + 0xcb, 0x91, 0x81, 0x5b, 0xdf, 0x15, 0xb4, 0x70, 0x2b, 0xb6, 0xcf, 0x23, 0x8f, 0xe2, 0x77, 0xa8, + 0xe2, 0xa7, 0x27, 0xa2, 0x66, 0x69, 0xdc, 0xd3, 0xd4, 0x38, 0x31, 0xa5, 0x46, 0x3e, 0x9a, 0xfd, + 0x0d, 0x43, 0xe6, 0x1d, 0xd9, 0xcd, 0x9a, 0x70, 0x2e, 0x89, 0xb5, 0x47, 0xd9, 0x08, 0xe4, 0xd9, + 0x3a, 0x99, 0xf1, 0x33, 0x06, 0x7f, 0x40, 0x28, 0x3b, 0x17, 0xdf, 0x63, 0x22, 0x95, 0xd5, 0x47, + 0x7e, 0x8f, 0x41, 0x49, 0xcd, 0xe5, 0x4c, 0xbb, 0x3a, 0xa4, 0xdd, 0x06, 0xd0, 0x49, 0x56, 0xe6, + 0x21, 0x40, 0xa1, 0x63, 0x15, 0xad, 0xde, 0xd5, 0x55, 0xde, 0xf6, 0xe6, 0x97, 0x32, 0x2a, 0x1f, + 0x73, 0x07, 0x7f, 0x53, 0xd0, 0xca, 0xb8, 0x3f, 0xea, 0xd5, 0xc8, 0xda, 0xc6, 0x4f, 0x63, 0x7d, + 0xef, 0x3f, 0x13, 0xf3, 0x0a, 0xf1, 0x47, 0x34, 0x3b, 0x34, 0xc2, 0x8d, 0x71, 0x82, 0x45, 0xb2, + 0xfe, 0xf2, 0xbe, 0xe4, 0xe0, 0xae, 0x08, 0x55, 0xff, 0x1e, 0x80, 0xf5, 0xfb, 0xca, 0xa4, 0x78, + 0x7d, 0xe7, 0x9f, 0xf0, 0xfc, 0xea, 0xe6, 0xdb, 0xcb, 0x6b, 0x55, 0xb9, 0xba, 0x56, 0x95, 0x9f, + 0xd7, 0xaa, 0x72, 0x7e, 0xa3, 0x96, 0xae, 0x6e, 0xd4, 0xd2, 0x8f, 0x1b, 0xb5, 0xf4, 0x7e, 0xc7, + 0x71, 0xc3, 0xb3, 0x5e, 0xcb, 0xa0, 0xac, 0x6b, 0x52, 0xc6, 0xbb, 0x8c, 0x9b, 0x6e, 0x8b, 0xae, + 0x3b, 0xcc, 0xec, 0x6f, 0x99, 0x5d, 0x66, 0xf7, 0x3a, 0xc0, 0xc5, 0xab, 0xca, 0xcd, 0xcd, 0xd7, + 0xeb, 0xe2, 0x41, 0x0d, 0x23, 0x1f, 0x78, 0x6b, 0x2a, 0x7d, 0x2d, 0xb7, 0xfe, 0x04, 0x00, 0x00, + 0xff, 0xff, 0xcb, 0x30, 0xa1, 0x30, 0xc6, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -534,6 +537,13 @@ func (m *MsgRegisterCounterpartyAddress) MarshalToSizedBuffer(dAtA []byte) (int, copy(dAtA[i:], m.ChannelId) i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) i-- + dAtA[i] = 0x22 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- dAtA[i] = 0x1a } if len(m.CounterpartyAddress) > 0 { @@ -753,6 +763,10 @@ func (m *MsgRegisterCounterpartyAddress) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } l = len(m.ChannelId) if l > 0 { n += 1 + l + sovTx(uint64(l)) @@ -929,6 +943,38 @@ func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { m.CounterpartyAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) } diff --git a/proto/ibc/applications/fee/v1/tx.proto b/proto/ibc/applications/fee/v1/tx.proto index 7a0044cd363..ca8397e74fd 100644 --- a/proto/ibc/applications/fee/v1/tx.proto +++ b/proto/ibc/applications/fee/v1/tx.proto @@ -39,8 +39,10 @@ message MsgRegisterCounterpartyAddress { string address = 1; // the counterparty relayer address string counterparty_address = 2 [(gogoproto.moretags) = "yaml:\"counterparty_address\""]; + // unique port identifier + string port_id = 3 [(gogoproto.moretags) = "yaml:\"port_id\""]; // unique channel identifier - string channel_id = 3 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 4 [(gogoproto.moretags) = "yaml:\"channel_id\""]; } // MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc From 5d834214f767c3706dd8a83ae6fbc654622deb85 Mon Sep 17 00:00:00 2001 From: vuong <56973102+vuong177@users.noreply.github.com> Date: Mon, 16 May 2022 17:58:00 +0700 Subject: [PATCH 107/275] check fee module locked and enable fee before refunding all fees (#1341) ## Description - Add check locked fee module and fee is enabled before refunding all fees closes: #1321 --- --- CHANGELOG.md | 1 + modules/apps/29-fee/ibc_middleware.go | 16 +++++++++++++++ modules/apps/29-fee/ibc_middleware_test.go | 24 ++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee528da9e80..d6e695b9799 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. * (modules/core/04-channel) [\#1279](https://github.com/cosmos/ibc-go/pull/1279) Add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse. Emit channel version during OpenInit/OpenTry * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` +* (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees ### Features diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 3e6e7afb26d..bc1933486bb 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -171,6 +171,14 @@ func (im IBCMiddleware) OnChanCloseInit( return err } + if !im.keeper.IsFeeEnabled(ctx, portID, channelID) { + return nil + } + + if im.keeper.IsLocked(ctx) { + return types.ErrFeeModuleLocked + } + if err := im.keeper.RefundFeesOnChannelClosure(ctx, portID, channelID); err != nil { return err } @@ -188,6 +196,14 @@ func (im IBCMiddleware) OnChanCloseConfirm( return err } + if !im.keeper.IsFeeEnabled(ctx, portID, channelID) { + return nil + } + + if im.keeper.IsLocked(ctx) { + return types.ErrFeeModuleLocked + } + if err := im.keeper.RefundFeesOnChannelClosure(ctx, portID, channelID); err != nil { return err } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 4b6d7f98959..5abda336e47 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -355,6 +355,18 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { }, false, }, + { + "fee module locked", func() { + lockFeeModule(suite.chainA) + }, + false, + }, + { + "fee module is not enabled", func() { + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + }, + true, + }, } for _, tc := range testCases { @@ -432,6 +444,18 @@ func (suite *FeeTestSuite) TestOnChanCloseConfirm() { }, false, }, + { + "fee module locked", func() { + lockFeeModule(suite.chainA) + }, + false, + }, + { + "fee module is not enabled", func() { + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + }, + true, + }, } for _, tc := range testCases { From 3b31a4b7b6ba0c7a49151013f887bb2be7fd4c42 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 16:15:24 +0200 Subject: [PATCH 108/275] build(deps): bump github.com/spf13/cast from 1.4.1 to 1.5.0 (#1350) Bumps [github.com/spf13/cast](https://github.com/spf13/cast) from 1.4.1 to 1.5.0. - [Release notes](https://github.com/spf13/cast/releases) - [Commits](https://github.com/spf13/cast/compare/v1.4.1...v1.5.0) --- updated-dependencies: - dependency-name: github.com/spf13/cast dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez --- go.mod | 2 +- go.sum | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index a75781504d2..441e47a23eb 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.3.1 - github.com/spf13/cast v1.4.1 + github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.11.0 github.com/stretchr/testify v1.7.1 diff --git a/go.sum b/go.sum index a33e5366c6d..e8829208d80 100644 --- a/go.sum +++ b/go.sum @@ -324,6 +324,8 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= @@ -625,6 +627,8 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -870,6 +874,8 @@ github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRr github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= @@ -913,8 +919,9 @@ github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= From 21021d00d271c724375036e28fb322b5c2938c67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 17:56:51 +0200 Subject: [PATCH 109/275] build(deps): bump google.golang.org/grpc from 1.46.0 to 1.46.2 (#1358) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.46.0 to 1.46.2. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.46.0...v1.46.2) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 441e47a23eb..e595ea97f26 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac - google.golang.org/grpc v1.46.0 + google.golang.org/grpc v1.46.2 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index e8829208d80..0b1381b5098 100644 --- a/go.sum +++ b/go.sum @@ -1597,8 +1597,8 @@ google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 2709c241b0412ee2e6887bc818f24418cdef469f Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 16 May 2022 18:01:13 +0200 Subject: [PATCH 110/275] override default docsBranch (#1355) ## Description closes: #1354 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [x] Review `Codecov Report` in the comment section below once CI passes --- docs/.vuepress/config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index bdd58cd8d72..43bd93590cd 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -20,6 +20,7 @@ module.exports = { themeConfig: { repo: "cosmos/ibc-go", docsRepo: "cosmos/ibc-go", + docsBranch: "main", docsDir: "docs", editLinks: true, label: "ibc", From b7b44000ea3f1cc7c894548835d1db11ed539853 Mon Sep 17 00:00:00 2001 From: vuong <56973102+vuong177@users.noreply.github.com> Date: Mon, 16 May 2022 23:45:15 +0700 Subject: [PATCH 111/275] Return error if fee module is locked before distributing fees on acknowledgement and timeout (#1340) ## Description - Return error if fee module is locked - Move `DeleteFeesInEscrow` into `DistributePacketFees` func closes: #1320 --- --- modules/apps/29-fee/ibc_middleware.go | 10 +--- modules/apps/29-fee/ibc_middleware_test.go | 66 +++++++++++++++++++++- modules/apps/29-fee/keeper/escrow.go | 20 ++++--- modules/apps/29-fee/keeper/escrow_test.go | 15 ++++- 4 files changed, 89 insertions(+), 22 deletions(-) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index bc1933486bb..7178c14ab4b 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -268,10 +268,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( packetID := channeltypes.NewPacketId(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) if found { - im.keeper.DistributePacketFeesOnAcknowledgement(ctx, ack.ForwardRelayerAddress, relayer, feesInEscrow.PacketFees) - - // removes the fees from the store as fees are now paid - im.keeper.DeleteFeesInEscrow(ctx, packetID) + im.keeper.DistributePacketFeesOnAcknowledgement(ctx, ack.ForwardRelayerAddress, relayer, feesInEscrow.PacketFees, packetID) } // call underlying callback @@ -297,10 +294,7 @@ func (im IBCMiddleware) OnTimeoutPacket( packetID := channeltypes.NewPacketId(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) if found { - im.keeper.DistributePacketFeesOnTimeout(ctx, relayer, feesInEscrow.PacketFees) - - // removes the fee from the store as fee is now paid - im.keeper.DeleteFeesInEscrow(ctx, packetID) + im.keeper.DistributePacketFeesOnTimeout(ctx, relayer, feesInEscrow.PacketFees, packetID) } // call underlying callback diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 5abda336e47..da58e1ae627 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -20,6 +20,7 @@ var ( defaultRecvFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}} defaultAckFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}} defaultTimeoutFee = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(300)}} + smallAmount = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(50)}} ) // Tests OnChanOpenInit on ChainA @@ -615,12 +616,14 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { originalBalance sdk.Coins expectedBalance sdk.Coins expectedRelayerBalance sdk.Coins + expLocked bool ) testCases := []struct { - name string - malleate func() - expPass bool + name string + malleate func() + expFeesDistributed bool + expPass bool }{ { "success", @@ -628,6 +631,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { expectedRelayerBalance = packetFee.Fee.RecvFee.Add(packetFee.Fee.AckFee[0]) }, true, + true, }, { "no op success without a packet fee", @@ -643,6 +647,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { expectedBalance = originalBalance }, true, + true, }, { "ack wrong format", @@ -652,6 +657,7 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { expectedBalance = originalBalance }, false, + false, }, { "channel is not fee not enabled, success", @@ -661,15 +667,18 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { expectedBalance = originalBalance }, + false, true, }, { "success: fee module is disabled, skip fee logic", func() { lockFeeModule(suite.chainA) + expLocked = true expectedBalance = originalBalance }, + false, true, }, { @@ -685,6 +694,25 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { expectedRelayerBalance = packetFee.Fee.AckFee expectedBalance = expectedBalance.Add(packetFee.Fee.RecvFee...) }, + false, + true, + }, + { + "fail on no distribution by escrow account out of balance", + func() { + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetSequence()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, suite.chainA.SenderAccount.GetAddress(), smallAmount) + suite.Require().NoError(err) + + // expectedBalance and expectedRelayerBalance don't change + expectedBalance = originalBalance.Add(smallAmount...) + expectedRelayerBalance = sdk.NewCoins() + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) + + expLocked = true + }, + false, true, }, } @@ -693,6 +721,8 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { tc := tc suite.Run(tc.name, func() { suite.SetupTest() + expLocked = false + suite.coordinator.Setup(suite.path) packet := suite.CreateMockPacket() @@ -747,12 +777,20 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { suite.Require().Error(err) } + suite.Require().Equal(expLocked, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + suite.Require().Equal( expectedBalance, sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), ) relayerBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, ibctesting.TestCoin.Denom)) + if tc.expFeesDistributed { + // there should no longer be a fee in escrow for this packet + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + } + suite.Require().Equal( expectedRelayerBalance, relayerBalance, @@ -767,6 +805,7 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { packetFee types.PacketFee originalBalance sdk.Coins expectedBalance sdk.Coins + expLocked bool ) testCases := []struct { name string @@ -791,6 +830,7 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { "fee module is disabled, skip fee logic", func() { lockFeeModule(suite.chainA) + expLocked = true expectedBalance = originalBalance }, @@ -819,12 +859,30 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { }, false, }, + { + "fail on no distribution by escrow account out of balance", + func() { + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetSequence()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, suite.chainA.SenderAccount.GetAddress(), smallAmount) + suite.Require().NoError(err) + + // expectedBalance don't change + expectedBalance = originalBalance.Add(smallAmount...) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) + + expLocked = true + }, + false, + }, } for _, tc := range testCases { tc := tc suite.Run(tc.name, func() { suite.SetupTest() + expLocked = false + suite.coordinator.Setup(suite.path) packet := suite.CreateMockPacket() @@ -869,6 +927,8 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, relayerAddr) suite.Require().NoError(err) + suite.Require().Equal(expLocked, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + suite.Require().Equal( expectedBalance, sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 2c5b570320e..7333b36353d 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -45,7 +45,7 @@ func (k Keeper) escrowPacketFee(ctx sdk.Context, packetID channeltypes.PacketId, } // DistributePacketFeesOnAcknowledgement pays all the acknowledgement & receive fees for a given packetID while refunding the timeout fees to the refund account. -func (k Keeper) DistributePacketFeesOnAcknowledgement(ctx sdk.Context, forwardRelayer string, reverseRelayer sdk.AccAddress, packetFees []types.PacketFee) { +func (k Keeper) DistributePacketFeesOnAcknowledgement(ctx sdk.Context, forwardRelayer string, reverseRelayer sdk.AccAddress, packetFees []types.PacketFee, packetID channeltypes.PacketId) { // cache context before trying to distribute fees // if the escrow account has insufficient balance then we want to avoid partially distributing fees cacheCtx, writeFn := ctx.CacheContext() @@ -61,7 +61,6 @@ func (k Keeper) DistributePacketFeesOnAcknowledgement(ctx sdk.Context, forwardRe // NOTE: we use the uncached context to lock the fee module so that the state changes from // locking the fee module are persisted k.lockFeeModule(ctx) - return } @@ -74,11 +73,14 @@ func (k Keeper) DistributePacketFeesOnAcknowledgement(ctx sdk.Context, forwardRe k.distributePacketFeeOnAcknowledgement(cacheCtx, refundAddr, forwardAddr, reverseRelayer, packetFee) } + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + // write the cache writeFn() - // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. - ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + // removes the fees from the store as fees are now paid + k.DeleteFeesInEscrow(ctx, packetID) } // distributePacketFeeOnAcknowledgement pays the receive fee for a given packetID while refunding the timeout fee to the refund account associated with the Fee. @@ -102,7 +104,7 @@ func (k Keeper) distributePacketFeeOnAcknowledgement(ctx sdk.Context, refundAddr } // DistributePacketsFeesOnTimeout pays all the timeout fees for a given packetID while refunding the acknowledgement & receive fees to the refund account. -func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sdk.AccAddress, packetFees []types.PacketFee) { +func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sdk.AccAddress, packetFees []types.PacketFee, packetID channeltypes.PacketId) { // cache context before trying to distribute fees // if the escrow account has insufficient balance then we want to avoid partially distributing fees cacheCtx, writeFn := ctx.CacheContext() @@ -116,7 +118,6 @@ func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sd // NOTE: we use the uncached context to lock the fee module so that the state changes from // locking the fee module are persisted k.lockFeeModule(ctx) - return } @@ -129,11 +130,14 @@ func (k Keeper) DistributePacketFeesOnTimeout(ctx sdk.Context, timeoutRelayer sd k.distributePacketFeeOnTimeout(cacheCtx, refundAddr, timeoutRelayer, packetFee) } + // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. + ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + // write the cache writeFn() - // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. - ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) + // removing the fee from the store as the fee is now paid + k.DeleteFeesInEscrow(ctx, packetID) } // distributePacketFeeOnTimeout pays the timeout fee to the timeout relayer and refunds the acknowledgement & receive fee. diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index e2a43afe586..4ac6e2ed03f 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -30,6 +30,10 @@ func (suite *KeeperTestSuite) TestDistributeFee() { "success", func() {}, func() { + // check if fees has been deleted + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID)) + // check if the reverse relayer is paid expectedReverseAccBal := reverseRelayerBal.Add(defaultAckFee[0]).Add(defaultAckFee[0]) balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), reverseRelayer, sdk.DefaultBondDenom) @@ -59,7 +63,10 @@ func (suite *KeeperTestSuite) TestDistributeFee() { packetFees = append(packetFees, packetFee) }, func() { + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID)) // check if the module acc contains all the fees expectedModuleAccBal := packetFee.Fee.Total().Add(packetFee.Fee.Total()...) @@ -149,8 +156,7 @@ func (suite *KeeperTestSuite) TestDistributeFee() { reverseRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), reverseRelayer, sdk.DefaultBondDenom) refundAccBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) - suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnAcknowledgement(suite.chainA.GetContext(), forwardRelayer, reverseRelayer, packetFees) - + suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnAcknowledgement(suite.chainA.GetContext(), forwardRelayer, reverseRelayer, packetFees, packetID) tc.expResult() }) } @@ -196,7 +202,10 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { packetFees = append(packetFees, packetFee) }, func() { + packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID)) // check if the module acc contains all the fees expectedModuleAccBal := packetFee.Fee.Total().Add(packetFee.Fee.Total()...) @@ -259,7 +268,7 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { timeoutRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), timeoutRelayer, sdk.DefaultBondDenom) refundAccBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) - suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnTimeout(suite.chainA.GetContext(), timeoutRelayer, packetFees) + suite.chainA.GetSimApp().IBCFeeKeeper.DistributePacketFeesOnTimeout(suite.chainA.GetContext(), timeoutRelayer, packetFees, packetID) tc.expResult() }) From 2ae4f10143e233ab69d408c12fe48a9ff58f24c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 18 May 2022 13:14:14 +0200 Subject: [PATCH 112/275] refactor: emit cumulative fees when incentivizing a packet multiple times (#1391) * emit cumulative fees * test: add test for emission of cumulative incentivized fees * add check for nil relayer * reassign sdk.Coins, fix bug --- modules/apps/29-fee/keeper/escrow.go | 2 +- modules/apps/29-fee/keeper/events.go | 26 +++++-- modules/apps/29-fee/keeper/events_test.go | 83 +++++++++++++++++++++++ 3 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 modules/apps/29-fee/keeper/events_test.go diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 7333b36353d..f5b786bbd9a 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -39,7 +39,7 @@ func (k Keeper) escrowPacketFee(ctx sdk.Context, packetID channeltypes.PacketId, packetFees := types.NewPacketFees(fees) k.SetFeesInEscrow(ctx, packetID, packetFees) - EmitIncentivizedPacket(ctx, packetID, packetFee) + EmitIncentivizedPacketEvent(ctx, packetID, packetFees) return nil } diff --git a/modules/apps/29-fee/keeper/events.go b/modules/apps/29-fee/keeper/events.go index 9ff6f320ffc..d60866e21d2 100644 --- a/modules/apps/29-fee/keeper/events.go +++ b/modules/apps/29-fee/keeper/events.go @@ -9,17 +9,33 @@ import ( channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ) -// EmitIncentivizedPacket emits an event so that relayers know an incentivized packet is ready to be relayed -func EmitIncentivizedPacket(ctx sdk.Context, packetID channeltypes.PacketId, packetFee types.PacketFee) { +// EmitIncentivizedPacketEvent emits an event containing information on the total amount of fees incentivizing +// a specific packet. It should be emitted on every fee escrowed for the given packetID. +func EmitIncentivizedPacketEvent(ctx sdk.Context, packetID channeltypes.PacketId, packetFees types.PacketFees) { + var ( + totalRecvFees sdk.Coins + totalAckFees sdk.Coins + totalTimeoutFees sdk.Coins + ) + + for _, fee := range packetFees.PacketFees { + // only emit total fees for packet fees which allow any relayer to relay + if fee.Relayers == nil { + totalRecvFees = totalRecvFees.Add(fee.Fee.RecvFee...) + totalAckFees = totalAckFees.Add(fee.Fee.AckFee...) + totalTimeoutFees = totalTimeoutFees.Add(fee.Fee.TimeoutFee...) + } + } + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeIncentivizedPacket, sdk.NewAttribute(channeltypes.AttributeKeyPortID, packetID.PortId), sdk.NewAttribute(channeltypes.AttributeKeyChannelID, packetID.ChannelId), sdk.NewAttribute(channeltypes.AttributeKeySequence, fmt.Sprint(packetID.Sequence)), - sdk.NewAttribute(types.AttributeKeyRecvFee, packetFee.Fee.RecvFee.String()), - sdk.NewAttribute(types.AttributeKeyAckFee, packetFee.Fee.AckFee.String()), - sdk.NewAttribute(types.AttributeKeyTimeoutFee, packetFee.Fee.TimeoutFee.String()), + sdk.NewAttribute(types.AttributeKeyRecvFee, totalRecvFees.String()), + sdk.NewAttribute(types.AttributeKeyAckFee, totalAckFees.String()), + sdk.NewAttribute(types.AttributeKeyTimeoutFee, totalTimeoutFees.String()), ), ) } diff --git a/modules/apps/29-fee/keeper/events_test.go b/modules/apps/29-fee/keeper/events_test.go new file mode 100644 index 00000000000..8ab52295e73 --- /dev/null +++ b/modules/apps/29-fee/keeper/events_test.go @@ -0,0 +1,83 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + abcitypes "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" +) + +func (suite *KeeperTestSuite) TestIncentivizePacketEvent() { + var ( + expRecvFees sdk.Coins + expAckFees sdk.Coins + expTimeoutFees sdk.Coins + ) + + suite.coordinator.Setup(suite.path) + + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + msg := types.NewMsgPayPacketFee( + fee, + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.chainA.SenderAccount.GetAddress().String(), + nil, + ) + + expRecvFees = expRecvFees.Add(fee.RecvFee...) + expAckFees = expAckFees.Add(fee.AckFee...) + expTimeoutFees = expTimeoutFees.Add(fee.TimeoutFee...) + + result, err := suite.chainA.SendMsgs(msg) + suite.Require().NoError(err) + + var incentivizedPacketEvent abcitypes.Event + for _, event := range result.Events { + if event.Type == types.EventTypeIncentivizedPacket { + incentivizedPacketEvent = event + } + } + + for _, attr := range incentivizedPacketEvent.Attributes { + switch string(attr.Key) { + case types.AttributeKeyRecvFee: + suite.Require().Equal(expRecvFees.String(), string(attr.Value)) + + case types.AttributeKeyAckFee: + suite.Require().Equal(expAckFees.String(), string(attr.Value)) + + case types.AttributeKeyTimeoutFee: + suite.Require().Equal(expTimeoutFees.String(), string(attr.Value)) + } + } + + // send the same messages again a few times + for i := 0; i < 3; i++ { + expRecvFees = expRecvFees.Add(fee.RecvFee...) + expAckFees = expAckFees.Add(fee.AckFee...) + expTimeoutFees = expTimeoutFees.Add(fee.TimeoutFee...) + + result, err = suite.chainA.SendMsgs(msg) + suite.Require().NoError(err) + } + + for _, event := range result.Events { + if event.Type == types.EventTypeIncentivizedPacket { + incentivizedPacketEvent = event + } + } + + for _, attr := range incentivizedPacketEvent.Attributes { + switch string(attr.Key) { + case types.AttributeKeyRecvFee: + suite.Require().Equal(expRecvFees.String(), string(attr.Value)) + + case types.AttributeKeyAckFee: + suite.Require().Equal(expAckFees.String(), string(attr.Value)) + + case types.AttributeKeyTimeoutFee: + suite.Require().Equal(expTimeoutFees.String(), string(attr.Value)) + } + } +} From bf444a6f68c0c5ddfb446360e536a71ccc3ff83a Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 23 May 2022 10:00:13 +0200 Subject: [PATCH 113/275] add swagger for interchain accounts (#1402) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- docs/client/config.json | 16 +++ docs/client/swagger-ui/swagger.yaml | 157 ++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) diff --git a/docs/client/config.json b/docs/client/config.json index cfc6dc7b9c4..210674dcc7c 100644 --- a/docs/client/config.json +++ b/docs/client/config.json @@ -14,6 +14,22 @@ } } }, + { + "url": "./tmp-swagger-gen/ibc/applications/interchain_accounts/controller/v1/query.swagger.json", + "operationIds": { + "rename": { + "Params": "InterchainAccountsControllerParams" + } + } + }, + { + "url": "./tmp-swagger-gen/ibc/applications/interchain_accounts/host/v1/query.swagger.json", + "operationIds": { + "rename": { + "Params": "InterchainAccountsHostParams" + } + } + }, { "url": "./tmp-swagger-gen/ibc/core/client/v1/query.swagger.json", "operationIds": { diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml index 46ed1f188b8..74f6ee85a9e 100644 --- a/docs/client/swagger-ui/swagger.yaml +++ b/docs/client/swagger-ui/swagger.yaml @@ -300,6 +300,105 @@ paths: format: byte tags: - Query + /ibc/apps/interchain_accounts/controller/v1/params: + get: + summary: Params queries all parameters of the ICA controller submodule. + operationId: InterchainAccountsControllerParams + responses: + '200': + description: A successful response. + schema: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + controller_enabled: + type: boolean + format: boolean + description: >- + controller_enabled enables or disables the controller + submodule. + description: >- + QueryParamsResponse is the response type for the Query/Params RPC + method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + tags: + - Query + /ibc/apps/interchain_accounts/host/v1/params: + get: + summary: Params queries all parameters of the ICA host submodule. + operationId: InterchainAccountsHostParams + responses: + '200': + description: A successful response. + schema: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + host_enabled: + type: boolean + format: boolean + description: host_enabled enables or disables the host submodule. + allow_messages: + type: array + items: + type: string + description: >- + allow_messages defines a list of sdk message typeURLs + allowed to be executed on a host chain. + description: >- + QueryParamsResponse is the response type for the Query/Params RPC + method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + tags: + - Query /ibc/client/v1/params: get: summary: ClientParams queries all parameters of the ibc client. @@ -10002,6 +10101,64 @@ definitions: chain. description: QueryParamsResponse is the response type for the Query/Params RPC method. + ibc.applications.interchain_accounts.controller.v1.Params: + type: object + properties: + controller_enabled: + type: boolean + format: boolean + description: controller_enabled enables or disables the controller submodule. + description: |- + Params defines the set of on-chain interchain accounts parameters. + The following parameters may be used to disable the controller submodule. + ibc.applications.interchain_accounts.controller.v1.QueryParamsResponse: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + controller_enabled: + type: boolean + format: boolean + description: controller_enabled enables or disables the controller submodule. + description: QueryParamsResponse is the response type for the Query/Params RPC method. + ibc.applications.interchain_accounts.host.v1.Params: + type: object + properties: + host_enabled: + type: boolean + format: boolean + description: host_enabled enables or disables the host submodule. + allow_messages: + type: array + items: + type: string + description: >- + allow_messages defines a list of sdk message typeURLs allowed to be + executed on a host chain. + description: |- + Params defines the set of on-chain interchain accounts parameters. + The following parameters may be used to disable the host submodule. + ibc.applications.interchain_accounts.host.v1.QueryParamsResponse: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + host_enabled: + type: boolean + format: boolean + description: host_enabled enables or disables the host submodule. + allow_messages: + type: array + items: + type: string + description: >- + allow_messages defines a list of sdk message typeURLs allowed to + be executed on a host chain. + description: QueryParamsResponse is the response type for the Query/Params RPC method. ibc.core.client.v1.ConsensusStateWithHeight: type: object properties: From f05a7cf8840ead622e7b5628466e1f9a311a717d Mon Sep 17 00:00:00 2001 From: chatton Date: Mon, 23 May 2022 13:38:46 +0100 Subject: [PATCH 114/275] Add Sender to funginble_token_packet events --- modules/apps/transfer/ibc_module.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index b9bfc2be189..07469622bfc 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -195,6 +195,7 @@ func (im IBCModule) OnRecvPacket( sdk.NewEvent( types.EventTypePacket, sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), @@ -230,6 +231,7 @@ func (im IBCModule) OnAcknowledgementPacket( sdk.NewEvent( types.EventTypePacket, sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), From c809c518423de21c576b8a80fec7fb5f5e07fca8 Mon Sep 17 00:00:00 2001 From: chatton Date: Mon, 23 May 2022 14:11:37 +0100 Subject: [PATCH 115/275] chore: Updated CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6e695b9799..8cff720b0c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1279](https://github.com/cosmos/ibc-go/pull/1279) Add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse. Emit channel version during OpenInit/OpenTry * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees +* (transfer) [\#996](https://github.com/cosmos/ibc-go/pull/1342) Emitting Sender address from `fungible_token_packet` events in `OnReceivePacket` and `OnAcknowledgementPacket`. ### Features From d8be3d0ce674c004d7543413cbeba3455d7028e2 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Mon, 23 May 2022 14:19:10 +0100 Subject: [PATCH 116/275] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cff720b0c9..2f88dcdd5d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,7 +59,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1279](https://github.com/cosmos/ibc-go/pull/1279) Add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse. Emit channel version during OpenInit/OpenTry * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees -* (transfer) [\#996](https://github.com/cosmos/ibc-go/pull/1342) Emitting Sender address from `fungible_token_packet` events in `OnReceivePacket` and `OnAcknowledgementPacket`. +* (transfer) [\#996](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnReceivePacket` and `OnAcknowledgementPacket`. ### Features From 46d73a09352d7db7b01d006f64627d519919f44e Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Mon, 23 May 2022 14:31:32 +0100 Subject: [PATCH 117/275] Update CHANGELOG.md Co-authored-by: Damian Nolan --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f88dcdd5d7..d81c95d029a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,7 +59,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1279](https://github.com/cosmos/ibc-go/pull/1279) Add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse. Emit channel version during OpenInit/OpenTry * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees -* (transfer) [\#996](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnReceivePacket` and `OnAcknowledgementPacket`. +* (transfer) [\#996](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. ### Features From 79ddb9de9e5d9e9565bf362c2d07cab9b3349e19 Mon Sep 17 00:00:00 2001 From: Sean King Date: Mon, 23 May 2022 17:37:39 +0200 Subject: [PATCH 118/275] chore: mini nits from ics29 audit (#1348) * chore: nits from ics29 audit * Update modules/apps/29-fee/keeper/escrow.go Co-authored-by: Carlos Rodriguez * Update modules/apps/29-fee/keeper/msg_server.go Co-authored-by: Carlos Rodriguez * nits: more nits Co-authored-by: Carlos Rodriguez --- modules/apps/29-fee/ibc_middleware.go | 2 +- modules/apps/29-fee/keeper/escrow.go | 3 +++ modules/apps/29-fee/keeper/msg_server.go | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 7178c14ab4b..d5cc6f4cfca 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -248,7 +248,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) } - ack := new(types.IncentivizedAcknowledgement) + var ack = &types.IncentivizedAcknowledgement{} if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, ack); err != nil { return sdkerrors.Wrapf(err, "cannot unmarshal ICS-29 incentivized packet acknowledgement: %v", ack) } diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index f5b786bbd9a..d698d84e795 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -50,6 +50,7 @@ func (k Keeper) DistributePacketFeesOnAcknowledgement(ctx sdk.Context, forwardRe // if the escrow account has insufficient balance then we want to avoid partially distributing fees cacheCtx, writeFn := ctx.CacheContext() + // forward relayer address will be empty if conversion fails forwardAddr, _ := sdk.AccAddressFromBech32(forwardRelayer) for _, packetFee := range packetFees { @@ -162,6 +163,7 @@ func (k Keeper) distributeFee(ctx sdk.Context, receiver, refundAccAddress sdk.Ac err := k.bankKeeper.SendCoinsFromModuleToAccount(cacheCtx, types.ModuleName, receiver, fee) if err != nil { if bytes.Equal(receiver, refundAccAddress) { + k.Logger(ctx).Error("error distributing fee", "receiver address", receiver, "fee", fee) return // if sending to the refund address already failed, then return (no-op) } @@ -169,6 +171,7 @@ func (k Keeper) distributeFee(ctx sdk.Context, receiver, refundAccAddress sdk.Ac // then attempt to refund the fee to the original sender err := k.bankKeeper.SendCoinsFromModuleToAccount(cacheCtx, types.ModuleName, refundAccAddress, fee) if err != nil { + k.Logger(ctx).Error("error refunding fee to the original sender", "refund address", refundAccAddress, "fee", fee) return // if sending to the refund address fails, no-op } } diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index 154a4150f54..e0c78028ea8 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -31,7 +31,7 @@ func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.Ms ctx, msg.Address, msg.CounterpartyAddress, msg.ChannelId, ) - k.Logger(ctx).Info("Registering counterparty address for relayer.", "Address:", msg.Address, "Counterparty Address:", msg.CounterpartyAddress) + k.Logger(ctx).Info("registering counterparty address for relayer", "address", msg.Address, "counterparty address", msg.CounterpartyAddress, "channel", msg.ChannelId) return &types.MsgRegisterCounterpartyAddressResponse{}, nil } From abd577e7bc534e9a78f7f992b1bd61a3bffa4e7b Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Tue, 24 May 2022 12:48:40 +0700 Subject: [PATCH 119/275] fumpt (#1335) * fumpt * merge main * changelog Co-authored-by: vuong <56973102+vuong177@users.noreply.github.com> --- CHANGELOG.md | 2 +- .../controller/ibc_middleware_test.go | 26 ++---- .../controller/keeper/account.go | 2 +- .../controller/keeper/genesis_test.go | 1 - .../controller/keeper/handshake.go | 1 - .../controller/keeper/handshake_test.go | 8 +- .../controller/keeper/keeper.go | 1 - .../controller/keeper/relay_test.go | 4 +- .../controller/types/params.go | 6 +- .../host/ibc_module_test.go | 22 +---- .../host/keeper/account_test.go | 2 +- .../host/keeper/events.go | 4 +- .../host/keeper/handshake.go | 1 - .../host/keeper/handshake_test.go | 13 +-- .../host/keeper/keeper.go | 1 - .../host/types/ack_test.go | 1 - .../27-interchain-accounts/module_test.go | 2 - .../27-interchain-accounts/types/account.go | 2 - .../27-interchain-accounts/types/codec.go | 14 ++-- .../types/codec_test.go | 1 - .../types/genesis_test.go | 12 +-- .../types/metadata_test.go | 3 - .../types/packet_test.go | 2 +- modules/apps/29-fee/client/cli/query.go | 2 +- modules/apps/29-fee/ibc_middleware_test.go | 1 - modules/apps/29-fee/keeper/escrow.go | 1 - modules/apps/29-fee/keeper/escrow_test.go | 1 - modules/apps/29-fee/keeper/grpc_query.go | 4 - modules/apps/29-fee/keeper/grpc_query_test.go | 24 ++---- modules/apps/29-fee/keeper/keeper.go | 1 - modules/apps/29-fee/types/fee_test.go | 4 +- modules/apps/29-fee/types/keys_test.go | 10 +-- modules/apps/29-fee/types/msgs_test.go | 12 +-- modules/apps/transfer/ibc_module_test.go | 6 -- modules/apps/transfer/keeper/grpc_query.go | 2 - .../apps/transfer/keeper/grpc_query_test.go | 1 - modules/apps/transfer/keeper/keeper.go | 1 - .../apps/transfer/keeper/mbt_relay_test.go | 2 +- modules/apps/transfer/keeper/relay.go | 1 - modules/apps/transfer/keeper/relay_test.go | 84 ++++++++++++------- .../apps/transfer/simulation/genesis_test.go | 1 - modules/apps/transfer/types/ack_test.go | 1 - modules/apps/transfer/types/coin.go | 1 - modules/core/02-client/keeper/client.go | 3 +- modules/core/02-client/keeper/client_test.go | 3 - modules/core/02-client/keeper/grpc_query.go | 2 - .../core/02-client/keeper/grpc_query_test.go | 31 ++++--- .../core/02-client/keeper/proposal_test.go | 4 +- modules/core/02-client/legacy/v100/genesis.go | 2 - .../02-client/legacy/v100/genesis_test.go | 3 - .../core/02-client/proposal_handler_test.go | 1 - modules/core/02-client/types/client_test.go | 4 +- modules/core/02-client/types/codec_test.go | 1 - modules/core/02-client/types/encoding_test.go | 2 - modules/core/02-client/types/genesis.go | 1 - modules/core/02-client/types/height_test.go | 1 - modules/core/02-client/types/msgs.go | 4 +- modules/core/02-client/types/msgs_test.go | 2 - modules/core/02-client/types/proposal_test.go | 2 - .../core/03-connection/client/utils/utils.go | 2 - modules/core/03-connection/keeper/events.go | 2 +- .../core/03-connection/keeper/grpc_query.go | 2 - .../03-connection/keeper/grpc_query_test.go | 12 ++- .../03-connection/keeper/handshake_test.go | 2 - .../core/03-connection/keeper/keeper_test.go | 1 - modules/core/03-connection/types/codec.go | 14 ++-- .../core/03-connection/types/genesis_test.go | 1 - modules/core/03-connection/types/msgs_test.go | 9 +- .../core/03-connection/types/version_test.go | 1 - modules/core/04-channel/client/utils/utils.go | 2 - modules/core/04-channel/keeper/grpc_query.go | 8 +- .../core/04-channel/keeper/grpc_query_test.go | 21 +++-- modules/core/04-channel/keeper/packet_test.go | 2 - .../core/04-channel/keeper/timeout_test.go | 1 - .../core/23-commitment/types/merkle_test.go | 2 - modules/core/keeper/keeper.go | 8 +- modules/core/keeper/keeper_test.go | 5 -- modules/core/keeper/msg_server.go | 8 +- modules/core/keeper/msg_server_test.go | 3 - .../06-solomachine/types/client_state_test.go | 3 - .../06-solomachine/types/codec_test.go | 4 - .../types/consensus_state_test.go | 1 - .../types/misbehaviour_handle.go | 3 - .../types/misbehaviour_handle_test.go | 1 - .../06-solomachine/types/misbehaviour_test.go | 1 - .../06-solomachine/types/proof.go | 3 +- .../06-solomachine/types/proposal_handle.go | 1 - .../06-solomachine/types/update_test.go | 1 - .../07-tendermint/types/client_state_test.go | 5 +- .../types/consensus_state_test.go | 36 +++++--- .../07-tendermint/types/header_test.go | 4 +- .../types/misbehaviour_handle.go | 1 - .../types/proposal_handle_test.go | 8 +- .../07-tendermint/types/store.go | 1 - .../07-tendermint/types/upgrade_test.go | 4 +- .../09-localhost/types/client_state_test.go | 3 - .../09-localhost/types/localhost_test.go | 4 +- testing/coordinator.go | 1 - testing/events.go | 1 - testing/mock/ibc_module_test.go | 2 +- testing/simapp/ante_handler.go | 2 +- testing/simapp/app.go | 2 +- testing/simapp/params/amino.go | 1 + testing/simapp/params/proto.go | 1 + testing/simapp/sim_test.go | 6 +- testing/simapp/simd/cmd/genaccounts_test.go | 3 +- testing/simapp/simd/cmd/root.go | 4 +- testing/simapp/simd/cmd/testnet.go | 9 +- testing/simapp/state.go | 1 - testing/simapp/test_helpers.go | 1 - testing/simapp/utils.go | 4 +- 111 files changed, 216 insertions(+), 369 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d81c95d029a..ebf85888868 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking ### Improvements - +* (cleanup) [\#1335](https://github.com/cosmos/ibc-go/pull/1335/) `gofumpt -w -l .` to standardize the code layout more strictly than `go fmt ./...` * (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. * (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. * (middleware) [\#1022](https://github.com/cosmos/ibc-go/pull/1022) Add `GetAppVersion` to the ICS4Wrapper interface. This function should be used by IBC applications to obtain their own version since the version set in the channel structure may be wrapped many times by middleware. diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index dd7849efca9..adaffcb83f9 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -120,9 +120,7 @@ func SetupICAPath(path *ibctesting.Path, owner string) error { } func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { - var ( - channel *channeltypes.Channel - ) + var channel *channeltypes.Channel testCases := []struct { name string @@ -273,9 +271,7 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenTry() { } func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { - var ( - path *ibctesting.Path - ) + var path *ibctesting.Path testCases := []struct { name string @@ -336,10 +332,8 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { } else { suite.Require().Error(err) } - }) } - } // Test initiating a ChanOpenConfirm using the controller chain instead of the host chain @@ -389,7 +383,6 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenConfirm() { suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ) suite.Require().Error(err) - } // OnChanCloseInit on controller (chainA) @@ -414,16 +407,13 @@ func (suite *InterchainAccountsTestSuite) TestOnChanCloseInit() { } func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { - var ( - path *ibctesting.Path - ) + var path *ibctesting.Path testCases := []struct { name string malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -454,13 +444,11 @@ func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { } else { suite.Require().Error(err) } - }) } } func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { - testCases := []struct { name string malleate func() @@ -509,9 +497,7 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { } func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { - var ( - path *ibctesting.Path - ) + var path *ibctesting.Path testCases := []struct { msg string @@ -580,9 +566,7 @@ func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { } func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { - var ( - path *ibctesting.Path - ) + var path *ibctesting.Path testCases := []struct { msg string diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account.go b/modules/apps/27-interchain-accounts/controller/keeper/account.go index 03eeef69f1f..282b6e2e77a 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account.go @@ -10,7 +10,7 @@ import ( ) // RegisterInterchainAccount is the entry point to registering an interchain account. -// It generates a new port identifier using the owner address. It will bind to the +// It generates a new port identifier using the owner address. It will bind to the // port identifier and call 04-channel 'ChanOpenInit'. An error is returned if the port // identifier is already in use. Gaining access to interchain accounts whose channels // have closed cannot be done with this function. A regular MsgChanOpenInit must be used. diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go index 7a41608d38f..1c34e2efbf1 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go @@ -41,7 +41,6 @@ func (suite *KeeperTestSuite) TestInitGenesis() { expParams := types.NewParams(false) params := suite.chainA.GetSimApp().ICAControllerKeeper.GetParams(suite.chainA.GetContext()) suite.Require().Equal(expParams, params) - } func (suite *KeeperTestSuite) TestExportGenesis() { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go index 26a90878abf..6b84fb554ca 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -119,6 +119,5 @@ func (k Keeper) OnChanCloseConfirm( portID, channelID string, ) error { - return nil } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go index 61c8a092a81..f2104e2032d 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -22,7 +22,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { malleate func() expPass bool }{ - { "success", func() { @@ -242,7 +241,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { } else { suite.Require().Error(err) } - }) } } @@ -402,16 +400,13 @@ func (suite *KeeperTestSuite) TestOnChanOpenAck() { } func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { - var ( - path *ibctesting.Path - ) + var path *ibctesting.Path testCases := []struct { name string malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -441,7 +436,6 @@ func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { } else { suite.Require().Error(err) } - }) } } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index 86099b954bd..5973d2abcd3 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -39,7 +39,6 @@ func NewKeeper( ics4Wrapper icatypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, ) Keeper { - // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go index bb4d17b8232..2a1f9894087 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go @@ -183,9 +183,7 @@ func (suite *KeeperTestSuite) TestSendTx() { } func (suite *KeeperTestSuite) TestOnTimeoutPacket() { - var ( - path *ibctesting.Path - ) + var path *ibctesting.Path testCases := []struct { msg string diff --git a/modules/apps/27-interchain-accounts/controller/types/params.go b/modules/apps/27-interchain-accounts/controller/types/params.go index eb9c413bec0..d7b9cc83874 100644 --- a/modules/apps/27-interchain-accounts/controller/types/params.go +++ b/modules/apps/27-interchain-accounts/controller/types/params.go @@ -11,10 +11,8 @@ const ( DefaultControllerEnabled = true ) -var ( - // KeyControllerEnabled is the store key for ControllerEnabled Params - KeyControllerEnabled = []byte("ControllerEnabled") -) +// KeyControllerEnabled is the store key for ControllerEnabled Params +var KeyControllerEnabled = []byte("ControllerEnabled") // ParamKeyTable type declaration for parameters func ParamKeyTable() paramtypes.KeyTable { diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 3fa45384104..db220f86026 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -147,7 +147,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -165,7 +164,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { ) (string, error) { return "", fmt.Errorf("mock ica auth fails") } - }, true, }, { @@ -222,10 +220,8 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { suite.Require().Error(err) suite.Require().Equal("", version) } - }) } - } // Test initiating a ChanOpenAck using the host chain instead of the controller chain @@ -268,7 +264,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -285,7 +280,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { ) error { return fmt.Errorf("mock ica auth fails") } - }, true, }, } @@ -322,10 +316,8 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { } else { suite.Require().Error(err) } - }) } - } // OnChanCloseInit on host (chainB) @@ -350,16 +342,13 @@ func (suite *InterchainAccountsTestSuite) TestOnChanCloseInit() { } func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { - var ( - path *ibctesting.Path - ) + var path *ibctesting.Path testCases := []struct { name string malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -390,15 +379,12 @@ func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { } else { suite.Require().Error(err) } - }) } } func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { - var ( - packetData []byte - ) + var packetData []byte testCases := []struct { name string malleate func() @@ -502,14 +488,11 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { } else { suite.Require().False(ack.Success()) } - }) } - } func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { - testCases := []struct { name string malleate func() @@ -563,7 +546,6 @@ func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { } func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { - testCases := []struct { name string malleate func() diff --git a/modules/apps/27-interchain-accounts/host/keeper/account_test.go b/modules/apps/27-interchain-accounts/host/keeper/account_test.go index df1966277e4..5e64189058e 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/account_test.go @@ -13,7 +13,7 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount() { path := NewICAPath(suite.chainA, suite.chainB) suite.coordinator.SetupConnections(path) - //RegisterInterchainAccount + // RegisterInterchainAccount err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) diff --git a/modules/apps/27-interchain-accounts/host/keeper/events.go b/modules/apps/27-interchain-accounts/host/keeper/events.go index 5926781d5c2..65c75f02618 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/events.go +++ b/modules/apps/27-interchain-accounts/host/keeper/events.go @@ -2,9 +2,9 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/cosmos/ibc-go/v3/modules/core/exported" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v3/modules/core/exported" ) // EmitWriteErrorAcknowledgementEvent emits an event signalling an error acknowledgement and including the error details diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake.go b/modules/apps/27-interchain-accounts/host/keeper/handshake.go index 11a7c7a378e..6d15bb0568c 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake.go @@ -110,6 +110,5 @@ func (k Keeper) OnChanCloseConfirm( portID, channelID string, ) error { - return nil } diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go index 0cac2912ccb..ee0ca72f14b 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go @@ -22,7 +22,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { malleate func() expPass bool }{ - { "success", func() { @@ -228,16 +227,13 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { } func (suite *KeeperTestSuite) TestOnChanOpenConfirm() { - var ( - path *ibctesting.Path - ) + var path *ibctesting.Path testCases := []struct { name string malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -279,22 +275,18 @@ func (suite *KeeperTestSuite) TestOnChanOpenConfirm() { } else { suite.Require().Error(err) } - }) } } func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { - var ( - path *ibctesting.Path - ) + var path *ibctesting.Path testCases := []struct { name string malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -320,7 +312,6 @@ func (suite *KeeperTestSuite) TestOnChanCloseConfirm() { } else { suite.Require().Error(err) } - }) } } diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index ea3f8205c87..8f2f345da1b 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -39,7 +39,6 @@ func NewKeeper( channelKeeper icatypes.ChannelKeeper, portKeeper icatypes.PortKeeper, accountKeeper icatypes.AccountKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, msgRouter *baseapp.MsgServiceRouter, ) Keeper { - // ensure ibc interchain accounts module account is set if addr := accountKeeper.GetModuleAddress(icatypes.ModuleName); addr == nil { panic("the Interchain Accounts module account has not been set") diff --git a/modules/apps/27-interchain-accounts/host/types/ack_test.go b/modules/apps/27-interchain-accounts/host/types/ack_test.go index bc4e2d07afc..6d2e6d1a95a 100644 --- a/modules/apps/27-interchain-accounts/host/types/ack_test.go +++ b/modules/apps/27-interchain-accounts/host/types/ack_test.go @@ -97,5 +97,4 @@ func (suite *TypesTestSuite) TestAcknowledgementError() { suite.Require().Equal(ack, ackSameABCICode) suite.Require().NotEqual(ack, ackDifferentABCICode) - } diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go index 59517ab40e4..ff44eed4ff0 100644 --- a/modules/apps/27-interchain-accounts/module_test.go +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -125,8 +125,6 @@ func (suite *InterchainAccountsTestSuite) TestInitModule() { suite.Require().True(app.IBCKeeper.PortKeeper.IsBound(ctx, types.PortID)) } - }) } - } diff --git a/modules/apps/27-interchain-accounts/types/account.go b/modules/apps/27-interchain-accounts/types/account.go index 9cd3fe4d327..38d7c4c5fe5 100644 --- a/modules/apps/27-interchain-accounts/types/account.go +++ b/modules/apps/27-interchain-accounts/types/account.go @@ -106,7 +106,6 @@ func (ia InterchainAccount) MarshalYAML() ([]byte, error) { Sequence: ia.Sequence, AccountOwner: ia.AccountOwner, }) - if err != nil { return nil, err } @@ -128,7 +127,6 @@ func (ia InterchainAccount) MarshalJSON() ([]byte, error) { Sequence: ia.Sequence, AccountOwner: ia.AccountOwner, }) - if err != nil { return nil, err } diff --git a/modules/apps/27-interchain-accounts/types/codec.go b/modules/apps/27-interchain-accounts/types/codec.go index a5a0922cabd..033c264f9e7 100644 --- a/modules/apps/27-interchain-accounts/types/codec.go +++ b/modules/apps/27-interchain-accounts/types/codec.go @@ -8,14 +8,12 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) -var ( - // ModuleCdc references the global interchain accounts module codec. Note, the codec - // should ONLY be used in certain instances of tests and for JSON encoding. - // - // The actual codec used for serialization should be provided to interchain accounts and - // defined at the application level. - ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) -) +// ModuleCdc references the global interchain accounts module codec. Note, the codec +// should ONLY be used in certain instances of tests and for JSON encoding. +// +// The actual codec used for serialization should be provided to interchain accounts and +// defined at the application level. +var ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) // RegisterInterfaces registers the concrete InterchainAccount implementation against the associated // x/auth AccountI and GenesisAccount interfaces diff --git a/modules/apps/27-interchain-accounts/types/codec_test.go b/modules/apps/27-interchain-accounts/types/codec_test.go index e027fda9346..b18b018332a 100644 --- a/modules/apps/27-interchain-accounts/types/codec_test.go +++ b/modules/apps/27-interchain-accounts/types/codec_test.go @@ -148,5 +148,4 @@ func (suite *TypesTestSuite) TestDeserializeAndSerializeCosmosTxWithAmino() { bz, err := types.DeserializeCosmosTx(marshaler, []byte{0x10, 0}) suite.Require().Error(err) suite.Require().Empty(bz) - } diff --git a/modules/apps/27-interchain-accounts/types/genesis_test.go b/modules/apps/27-interchain-accounts/types/genesis_test.go index 7e6ffdc280b..bbdbc8d14d5 100644 --- a/modules/apps/27-interchain-accounts/types/genesis_test.go +++ b/modules/apps/27-interchain-accounts/types/genesis_test.go @@ -8,9 +8,7 @@ import ( ) func (suite *TypesTestSuite) TestValidateGenesisState() { - var ( - genesisState types.GenesisState - ) + var genesisState types.GenesisState testCases := []struct { name string @@ -63,9 +61,7 @@ func (suite *TypesTestSuite) TestValidateGenesisState() { } func (suite *TypesTestSuite) TestValidateControllerGenesisState() { - var ( - genesisState types.ControllerGenesisState - ) + var genesisState types.ControllerGenesisState testCases := []struct { name string @@ -188,9 +184,7 @@ func (suite *TypesTestSuite) TestValidateControllerGenesisState() { } func (suite *TypesTestSuite) TestValidateHostGenesisState() { - var ( - genesisState types.HostGenesisState - ) + var genesisState types.HostGenesisState testCases := []struct { name string diff --git a/modules/apps/27-interchain-accounts/types/metadata_test.go b/modules/apps/27-interchain-accounts/types/metadata_test.go index 05a1b457c38..3bda2549c07 100644 --- a/modules/apps/27-interchain-accounts/types/metadata_test.go +++ b/modules/apps/27-interchain-accounts/types/metadata_test.go @@ -7,7 +7,6 @@ import ( // use TestVersion as metadata being compared against func (suite *TypesTestSuite) TestIsPreviousMetadataEqual() { - var ( metadata types.Metadata previousVersion string @@ -127,7 +126,6 @@ func (suite *TypesTestSuite) TestIsPreviousMetadataEqual() { } func (suite *TypesTestSuite) TestValidateControllerMetadata() { - var metadata types.Metadata testCases := []struct { @@ -269,7 +267,6 @@ func (suite *TypesTestSuite) TestValidateControllerMetadata() { } func (suite *TypesTestSuite) TestValidateHostMetadata() { - var metadata types.Metadata testCases := []struct { diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 840ca529851..52e7797d987 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -33,7 +33,7 @@ func (suite *TypesTestSuite) TestValidateBasic() { "type unspecified", types.InterchainAccountPacketData{ Type: types.UNSPECIFIED, - Data: []byte("data"), + Data: []byte("data"), Memo: "memo", }, false, diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index 092b7441453..ccf05b61b23 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -274,7 +274,7 @@ func GetCmdCounterpartyAddress() *cobra.Command { } flags.AddQueryFlagsToCmd(cmd) - + return cmd } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index da58e1ae627..17a961d0074 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -495,7 +495,6 @@ func (suite *FeeTestSuite) TestOnChanCloseConfirm() { } else { suite.Require().Error(err) } - }) } } diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index d698d84e795..130ac18e1b3 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -101,7 +101,6 @@ func (k Keeper) distributePacketFeeOnAcknowledgement(ctx sdk.Context, refundAddr // refund timeout fee for unused timeout k.distributeFee(ctx, refundAddr, refundAddr, packetFee.Fee.TimeoutFee) - } // DistributePacketsFeesOnTimeout pays all the timeout fees for a given packetID while refunding the acknowledgement & receive fees to the refund account. diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 4ac6e2ed03f..9b67934c647 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -467,7 +467,6 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { // all fees in escrow should be deleted for this channel suite.Require().Empty(suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) } - }) } } diff --git a/modules/apps/29-fee/keeper/grpc_query.go b/modules/apps/29-fee/keeper/grpc_query.go index 10da5bc5595..9b95753f25c 100644 --- a/modules/apps/29-fee/keeper/grpc_query.go +++ b/modules/apps/29-fee/keeper/grpc_query.go @@ -35,7 +35,6 @@ func (k Keeper) IncentivizedPackets(goCtx context.Context, req *types.QueryIncen identifiedPackets = append(identifiedPackets, types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees)) return nil }) - if err != nil { return nil, status.Error(codes.NotFound, err.Error()) } @@ -89,7 +88,6 @@ func (k Keeper) IncentivizedPacketsForChannel(goCtx context.Context, req *types. return nil }) - if err != nil { return nil, status.Error(codes.NotFound, err.Error()) } @@ -101,7 +99,6 @@ func (k Keeper) IncentivizedPacketsForChannel(goCtx context.Context, req *types. // TotalRecvFees implements the Query/TotalRecvFees gRPC method func (k Keeper) TotalRecvFees(goCtx context.Context, req *types.QueryTotalRecvFeesRequest) (*types.QueryTotalRecvFeesResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) feesInEscrow, found := k.GetFeesInEscrow(ctx, req.PacketId) @@ -217,7 +214,6 @@ func (k Keeper) FeeEnabledChannels(goCtx context.Context, req *types.QueryFeeEna return nil }) - if err != nil { return nil, status.Error(codes.NotFound, err.Error()) } diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index d665c655ccf..5850a3be3ba 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -80,9 +80,7 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPackets() { } func (suite *KeeperTestSuite) TestQueryIncentivizedPacket() { - var ( - req *types.QueryIncentivizedPacketRequest - ) + var req *types.QueryIncentivizedPacketRequest testCases := []struct { name string @@ -235,9 +233,7 @@ func (suite *KeeperTestSuite) TestQueryIncentivizedPacketsForChannel() { } func (suite *KeeperTestSuite) TestQueryTotalRecvFees() { - var ( - req *types.QueryTotalRecvFeesRequest - ) + var req *types.QueryTotalRecvFeesRequest testCases := []struct { name string @@ -296,9 +292,7 @@ func (suite *KeeperTestSuite) TestQueryTotalRecvFees() { } func (suite *KeeperTestSuite) TestQueryTotalAckFees() { - var ( - req *types.QueryTotalAckFeesRequest - ) + var req *types.QueryTotalAckFeesRequest testCases := []struct { name string @@ -357,9 +351,7 @@ func (suite *KeeperTestSuite) TestQueryTotalAckFees() { } func (suite *KeeperTestSuite) TestQueryTotalTimeoutFees() { - var ( - req *types.QueryTotalTimeoutFeesRequest - ) + var req *types.QueryTotalTimeoutFeesRequest testCases := []struct { name string @@ -418,9 +410,7 @@ func (suite *KeeperTestSuite) TestQueryTotalTimeoutFees() { } func (suite *KeeperTestSuite) TestQueryCounterpartyAddress() { - var ( - req *types.QueryCounterpartyAddressRequest - ) + var req *types.QueryCounterpartyAddressRequest testCases := []struct { name string @@ -590,9 +580,7 @@ func (suite *KeeperTestSuite) TestQueryFeeEnabledChannels() { } func (suite *KeeperTestSuite) TestQueryFeeEnabledChannel() { - var ( - req *types.QueryFeeEnabledChannelRequest - ) + var req *types.QueryFeeEnabledChannelRequest testCases := []struct { name string diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index c7e31ad3d1a..a4b5a153c33 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -36,7 +36,6 @@ func NewKeeper( cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, ) Keeper { - return Keeper{ cdc: cdc, storeKey: key, diff --git a/modules/apps/29-fee/types/fee_test.go b/modules/apps/29-fee/types/fee_test.go index 2b02e5b857b..4be71154a6b 100644 --- a/modules/apps/29-fee/types/fee_test.go +++ b/modules/apps/29-fee/types/fee_test.go @@ -35,9 +35,7 @@ func TestFeeTotal(t *testing.T) { } func TestPacketFeeValidation(t *testing.T) { - var ( - packetFee types.PacketFee - ) + var packetFee types.PacketFee testCases := []struct { name string diff --git a/modules/apps/29-fee/types/keys_test.go b/modules/apps/29-fee/types/keys_test.go index 1bd229b57a3..7cc0b4c9543 100644 --- a/modules/apps/29-fee/types/keys_test.go +++ b/modules/apps/29-fee/types/keys_test.go @@ -11,9 +11,7 @@ import ( ibctesting "github.com/cosmos/ibc-go/v3/testing" ) -var ( - validPacketID = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) -) +var validPacketID = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) func TestKeyCounterpartyRelayer(t *testing.T) { var ( @@ -69,7 +67,6 @@ func TestParseKeyFeeEnabled(t *testing.T) { } func TestParseKeyFeesInEscrow(t *testing.T) { - testCases := []struct { name string key string @@ -105,7 +102,6 @@ func TestParseKeyFeesInEscrow(t *testing.T) { } func TestParseKeyForwardRelayerAddress(t *testing.T) { - testCases := []struct { name string key string @@ -141,9 +137,7 @@ func TestParseKeyForwardRelayerAddress(t *testing.T) { } func TestParseKeyCounterpartyRelayer(t *testing.T) { - var ( - relayerAddress = "relayer_address" - ) + relayerAddress := "relayer_address" testCases := []struct { name string diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go index 7b224b5a66c..185e66dd758 100644 --- a/modules/apps/29-fee/types/msgs_test.go +++ b/modules/apps/29-fee/types/msgs_test.go @@ -13,9 +13,7 @@ import ( ) func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { - var ( - msg *types.MsgRegisterCounterpartyAddress - ) + var msg *types.MsgRegisterCounterpartyAddress testCases := []struct { name string @@ -86,9 +84,7 @@ func TestRegisterCountepartyAddressGetSigners(t *testing.T) { } func TestMsgPayPacketFeeValidation(t *testing.T) { - var ( - msg *types.MsgPayPacketFee - ) + var msg *types.MsgPayPacketFee testCases := []struct { name string @@ -174,9 +170,7 @@ func TestMsgPayPacketFeeGetSignBytes(t *testing.T) { } func TestMsgPayPacketFeeAsyncValidation(t *testing.T) { - var ( - msg *types.MsgPayPacketFeeAsync - ) + var msg *types.MsgPayPacketFeeAsync testCases := []struct { name string diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 95779ad2e8e..b11444b945e 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -25,7 +25,6 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -98,7 +97,6 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { suite.Require().Error(err) suite.Require().Equal(version, "") } - }) } } @@ -117,7 +115,6 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -191,7 +188,6 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { suite.Require().Error(err) suite.Require().Equal("", version) } - }) } } @@ -204,7 +200,6 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { malleate func() expPass bool }{ - { "success", func() {}, true, }, @@ -241,7 +236,6 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { } else { suite.Require().Error(err) } - }) } } diff --git a/modules/apps/transfer/keeper/grpc_query.go b/modules/apps/transfer/keeper/grpc_query.go index 5e7c5e7d295..25bbbe3d75b 100644 --- a/modules/apps/transfer/keeper/grpc_query.go +++ b/modules/apps/transfer/keeper/grpc_query.go @@ -24,7 +24,6 @@ func (q Keeper) DenomTrace(c context.Context, req *types.QueryDenomTraceRequest) } hash, err := types.ParseHexHash(strings.TrimPrefix(req.Hash, "ibc/")) - if err != nil { return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid denom trace hash: %s, error: %s", hash.String(), err)) } @@ -63,7 +62,6 @@ func (q Keeper) DenomTraces(c context.Context, req *types.QueryDenomTracesReques traces = append(traces, result) return nil }) - if err != nil { return nil, err } diff --git a/modules/apps/transfer/keeper/grpc_query_test.go b/modules/apps/transfer/keeper/grpc_query_test.go index 963abd21577..085891e265b 100644 --- a/modules/apps/transfer/keeper/grpc_query_test.go +++ b/modules/apps/transfer/keeper/grpc_query_test.go @@ -156,7 +156,6 @@ func (suite *KeeperTestSuite) TestQueryParams() { } func (suite *KeeperTestSuite) TestQueryDenomHash() { - reqTrace := types.DenomTrace{ Path: "transfer/channelToA/transfer/channelToB", BaseDenom: "uatom", diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index d3f32d95df7..b8681baa47b 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -34,7 +34,6 @@ func NewKeeper( ics4Wrapper types.ICS4Wrapper, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, ) Keeper { - // ensure ibc transfer module account is set if addr := authKeeper.GetModuleAddress(types.ModuleName); addr == nil { panic("the IBC transfer module account has not been set") diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index d4d338bf73a..59e4869e54e 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -280,7 +280,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { panic(fmt.Errorf("Failed to read model-based test files: %w", err)) } for _, file_info := range files { - var tlaTestCases = []TlaOnRecvPacketTestCase{} + tlaTestCases := []TlaOnRecvPacketTestCase{} if !strings.HasSuffix(file_info.Name(), ".json") { continue } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 3c3a5aa6690..cb4b8c59fd5 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -58,7 +58,6 @@ func (k Keeper) SendTransfer( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, ) error { - if !k.GetSendEnabled(ctx) { return types.ErrSendDisabled } diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index ce34f316669..3ad851b587e 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -28,25 +28,32 @@ func (suite *KeeperTestSuite) TestSendTransfer() { sendFromSource bool expPass bool }{ - {"successful transfer from source chain", + { + "successful transfer from source chain", func() { suite.coordinator.CreateTransferChannels(path) amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) - }, true, true}, - {"successful transfer with coin from counterparty chain", + }, true, true, + }, + { + "successful transfer with coin from counterparty chain", func() { // send coin from chainA back to chainB suite.coordinator.CreateTransferChannels(path) amount = types.GetTransferCoin(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom, sdk.NewInt(100)) - }, false, true}, - {"source channel not found", + }, false, true, + }, + { + "source channel not found", func() { // channel references wrong ID suite.coordinator.CreateTransferChannels(path) path.EndpointA.ChannelID = ibctesting.InvalidID amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) - }, true, false}, - {"next seq send not found", + }, true, false, + }, + { + "next seq send not found", func() { path.EndpointA.ChannelID = "channel-0" path.EndpointB.ChannelID = "channel-0" @@ -58,22 +65,28 @@ func (suite *KeeperTestSuite) TestSendTransfer() { ) suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) - }, true, false}, + }, true, false, + }, // createOutgoingPacket tests // - source chain - {"send coin failed", + { + "send coin failed", func() { suite.coordinator.CreateTransferChannels(path) amount = sdk.NewCoin("randomdenom", sdk.NewInt(100)) - }, true, false}, + }, true, false, + }, // - receiving chain - {"send from module account failed", + { + "send from module account failed", func() { suite.coordinator.CreateTransferChannels(path) amount = types.GetTransferCoin(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, " randomdenom", sdk.NewInt(100)) - }, false, false}, - {"channel capability not found", + }, false, false, + }, + { + "channel capability not found", func() { suite.coordinator.CreateTransferChannels(path) cap := suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) @@ -81,7 +94,8 @@ func (suite *KeeperTestSuite) TestSendTransfer() { // Release channel capability suite.chainA.GetSimApp().ScopedTransferKeeper.ReleaseCapability(suite.chainA.GetContext(), cap) amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) - }, true, false}, + }, true, false, + }, } for _, tc := range testCases { @@ -264,18 +278,22 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { suite.Require().NoError(simapp.FundAccount(suite.chainA.GetSimApp(), suite.chainA.GetContext(), escrow, sdk.NewCoins(coin))) }, false, true}, - {"unsuccessful refund from source", failedAck, + { + "unsuccessful refund from source", failedAck, func() { trace = types.ParseDenomTrace(sdk.DefaultBondDenom) - }, false, false}, - {"successful refund from with coin from external chain", failedAck, + }, false, false, + }, + { + "successful refund from with coin from external chain", failedAck, func() { escrow := types.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) trace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) coin := sdk.NewCoin(trace.IBCDenom(), amount) suite.Require().NoError(simapp.FundAccount(suite.chainA.GetSimApp(), suite.chainA.GetContext(), escrow, sdk.NewCoins(coin))) - }, false, true}, + }, false, true, + }, } for _, tc := range testCases { @@ -330,36 +348,46 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { malleate func() expPass bool }{ - {"successful timeout from sender as source chain", + { + "successful timeout from sender as source chain", func() { escrow := types.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) trace = types.ParseDenomTrace(sdk.DefaultBondDenom) coin := sdk.NewCoin(trace.IBCDenom(), amount) suite.Require().NoError(simapp.FundAccount(suite.chainA.GetSimApp(), suite.chainA.GetContext(), escrow, sdk.NewCoins(coin))) - }, true}, - {"successful timeout from external chain", + }, true, + }, + { + "successful timeout from external chain", func() { escrow := types.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) trace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) coin := sdk.NewCoin(trace.IBCDenom(), amount) suite.Require().NoError(simapp.FundAccount(suite.chainA.GetSimApp(), suite.chainA.GetContext(), escrow, sdk.NewCoins(coin))) - }, true}, - {"no balance for coin denom", + }, true, + }, + { + "no balance for coin denom", func() { trace = types.ParseDenomTrace("bitcoin") - }, false}, - {"unescrow failed", + }, false, + }, + { + "unescrow failed", func() { trace = types.ParseDenomTrace(sdk.DefaultBondDenom) - }, false}, - {"mint failed", + }, false, + }, + { + "mint failed", func() { trace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) amount = sdk.OneInt() sender = "invalid address" - }, false}, + }, false, + }, } for _, tc := range testCases { diff --git a/modules/apps/transfer/simulation/genesis_test.go b/modules/apps/transfer/simulation/genesis_test.go index c869d1c7b25..f2aa439b3ae 100644 --- a/modules/apps/transfer/simulation/genesis_test.go +++ b/modules/apps/transfer/simulation/genesis_test.go @@ -43,7 +43,6 @@ func TestRandomizedGenState(t *testing.T) { require.True(t, ibcTransferGenesis.Params.SendEnabled) require.True(t, ibcTransferGenesis.Params.ReceiveEnabled) require.Len(t, ibcTransferGenesis.DenomTraces, 0) - } // TestRandomizedGenState tests abnormal scenarios of applying RandomizedGenState. diff --git a/modules/apps/transfer/types/ack_test.go b/modules/apps/transfer/types/ack_test.go index 4f4c3a874d7..ffc09da981e 100644 --- a/modules/apps/transfer/types/ack_test.go +++ b/modules/apps/transfer/types/ack_test.go @@ -97,5 +97,4 @@ func (suite *TypesTestSuite) TestAcknowledgementError() { suite.Require().Equal(ack, ackSameABCICode) suite.Require().NotEqual(ack, ackDifferentABCICode) - } diff --git a/modules/apps/transfer/types/coin.go b/modules/apps/transfer/types/coin.go index a3491e2bf09..d6329541103 100644 --- a/modules/apps/transfer/types/coin.go +++ b/modules/apps/transfer/types/coin.go @@ -27,7 +27,6 @@ func ReceiverChainIsSource(sourcePort, sourceChannel, denom string) bool { voucherPrefix := GetDenomPrefix(sourcePort, sourceChannel) return strings.HasPrefix(denom, voucherPrefix) - } // GetDenomPrefix returns the receiving denomination prefix diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index d8085ac719f..0360952e75a 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -146,7 +146,8 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H // UpgradeClient upgrades the client to a new client state if this new client was committed to // by the old client at the specified upgrade height func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState, - proofUpgradeClient, proofUpgradeConsState []byte) error { + proofUpgradeClient, proofUpgradeConsState []byte, +) error { clientState, found := k.GetClientState(ctx, clientID) if !found { return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID) diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index cc36b8a4edb..cde30cbb0fe 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -418,7 +418,6 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name) } } - } func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { @@ -698,8 +697,6 @@ func (suite *KeeperTestSuite) TestUpdateClientEventEmission() { suite.Require().NoError(err) suite.Require().Equal(header, emittedHeader) } - } suite.Require().True(contains) - } diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index d4a2eca5a4f..555994e0a88 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -83,7 +83,6 @@ func (q Keeper) ClientStates(c context.Context, req *types.QueryClientStatesRequ clientStates = append(clientStates, identifiedClient) return nil }) - if err != nil { return nil, err } @@ -177,7 +176,6 @@ func (q Keeper) ConsensusStates(c context.Context, req *types.QueryConsensusStat consensusStates = append(consensusStates, types.NewConsensusStateWithHeight(height, consensusState)) return true, nil }) - if err != nil { return nil, err } diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index 5e393c33a97..7506291f4ae 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -28,19 +28,22 @@ func (suite *KeeperTestSuite) TestQueryClientState() { malleate func() expPass bool }{ - {"req is nil", + { + "req is nil", func() { req = nil }, false, }, - {"invalid clientID", + { + "invalid clientID", func() { req = &types.QueryClientStateRequest{} }, false, }, - {"client not found", + { + "client not found", func() { req = &types.QueryClientStateRequest{ ClientId: testClientID, @@ -100,7 +103,8 @@ func (suite *KeeperTestSuite) TestQueryClientStates() { malleate func() expPass bool }{ - {"req is nil", + { + "req is nil", func() { req = nil }, @@ -190,7 +194,8 @@ func (suite *KeeperTestSuite) TestQueryConsensusState() { malleate func() expPass bool }{ - {"req is nil", + { + "req is nil", func() { req = nil }, @@ -396,9 +401,7 @@ func (suite *KeeperTestSuite) TestQueryConsensusStates() { } func (suite *KeeperTestSuite) TestQueryClientStatus() { - var ( - req *types.QueryClientStatusRequest - ) + var req *types.QueryClientStatusRequest testCases := []struct { msg string @@ -406,19 +409,22 @@ func (suite *KeeperTestSuite) TestQueryClientStatus() { expPass bool expStatus string }{ - {"req is nil", + { + "req is nil", func() { req = nil }, false, "", }, - {"invalid clientID", + { + "invalid clientID", func() { req = &types.QueryClientStatusRequest{} }, false, "", }, - {"client not found", + { + "client not found", func() { req = &types.QueryClientStatusRequest{ ClientId: ibctesting.InvalidID, @@ -503,7 +509,8 @@ func (suite *KeeperTestSuite) TestQueryUpgradedConsensusStates() { malleate func() expPass bool }{ - {"req is nil", + { + "req is nil", func() { req = nil }, diff --git a/modules/core/02-client/keeper/proposal_test.go b/modules/core/02-client/keeper/proposal_test.go index bec5aa0a78a..277354f9e9b 100644 --- a/modules/core/02-client/keeper/proposal_test.go +++ b/modules/core/02-client/keeper/proposal_test.go @@ -154,7 +154,6 @@ func (suite *KeeperTestSuite) TestClientUpdateProposal() { } }) } - } func (suite *KeeperTestSuite) TestHandleUpgradeProposal() { @@ -206,7 +205,7 @@ func (suite *KeeperTestSuite) TestHandleUpgradeProposal() { suite.Run(tc.name, func() { suite.SetupTest() // reset - oldPlan.Height = 0 //reset + oldPlan.Height = 0 // reset path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) @@ -276,5 +275,4 @@ func (suite *KeeperTestSuite) TestHandleUpgradeProposal() { } }) } - } diff --git a/modules/core/02-client/legacy/v100/genesis.go b/modules/core/02-client/legacy/v100/genesis.go index fa052ade3f8..014dd3870c0 100644 --- a/modules/core/02-client/legacy/v100/genesis.go +++ b/modules/core/02-client/legacy/v100/genesis.go @@ -123,13 +123,11 @@ func MigrateGenesis(cdc codec.BinaryCodec, clientGenState *types.GenesisState, g Key: ibctmtypes.IterationKey(height), Value: host.ConsensusStateKey(height), }) - } } } } - } // if we have metadata for unexipred consensus states, add it to consensusMetadata diff --git a/modules/core/02-client/legacy/v100/genesis_test.go b/modules/core/02-client/legacy/v100/genesis_test.go index 4835ce98213..c4daa6c9bfc 100644 --- a/modules/core/02-client/legacy/v100/genesis_test.go +++ b/modules/core/02-client/legacy/v100/genesis_test.go @@ -254,7 +254,6 @@ func (suite *LegacyTestSuite) TestMigrateGenesisTendermint() { suite.Require().NotEqual(height, consensusState.Height) } } - } for _, client := range migrated.ClientsMetadata { if client.ClientId == path1.EndpointA.ClientID { @@ -275,7 +274,6 @@ func (suite *LegacyTestSuite) TestMigrateGenesisTendermint() { suite.Require().NotEqual(height, consensusState.Height) } } - } for _, client := range migrated.ClientsMetadata { if client.ClientId == path2.EndpointA.ClientID { @@ -285,7 +283,6 @@ func (suite *LegacyTestSuite) TestMigrateGenesisTendermint() { suite.Require().NotEqual(ibctmtypes.IterationKey(height), metadata.Key) } } - } } bz, err := clientCtx.JSONCodec.MarshalJSON(&expectedClientGenState) diff --git a/modules/core/02-client/proposal_handler_test.go b/modules/core/02-client/proposal_handler_test.go index 4ef2798d633..b83455b39c2 100644 --- a/modules/core/02-client/proposal_handler_test.go +++ b/modules/core/02-client/proposal_handler_test.go @@ -84,5 +84,4 @@ func (suite *ClientTestSuite) TestNewClientUpdateProposalHandler() { } }) } - } diff --git a/modules/core/02-client/types/client_test.go b/modules/core/02-client/types/client_test.go index 9f41843c064..cefe567619c 100644 --- a/modules/core/02-client/types/client_test.go +++ b/modules/core/02-client/types/client_test.go @@ -10,9 +10,7 @@ import ( ) func (suite *TypesTestSuite) TestMarshalConsensusStateWithHeight() { - var ( - cswh types.ConsensusStateWithHeight - ) + var cswh types.ConsensusStateWithHeight testCases := []struct { name string diff --git a/modules/core/02-client/types/codec_test.go b/modules/core/02-client/types/codec_test.go index 85b53e5ad84..bb706d87fd1 100644 --- a/modules/core/02-client/types/codec_test.go +++ b/modules/core/02-client/types/codec_test.go @@ -18,7 +18,6 @@ type caseAny struct { } func (suite *TypesTestSuite) TestPackClientState() { - testCases := []struct { name string clientState exported.ClientState diff --git a/modules/core/02-client/types/encoding_test.go b/modules/core/02-client/types/encoding_test.go index 9bd619260ea..75ee99e6c85 100644 --- a/modules/core/02-client/types/encoding_test.go +++ b/modules/core/02-client/types/encoding_test.go @@ -6,7 +6,6 @@ import ( ) func (suite *TypesTestSuite) TestMarshalHeader() { - cdc := suite.chainA.App.AppCodec() h := &ibctmtypes.Header{ TrustedHeight: types.NewHeight(4, 100), @@ -26,5 +25,4 @@ func (suite *TypesTestSuite) TestMarshalHeader() { invalidHeader, err := types.UnmarshalHeader(cdc, []byte("invalid bytes")) suite.Require().Error(err) suite.Require().Nil(invalidHeader) - } diff --git a/modules/core/02-client/types/genesis.go b/modules/core/02-client/types/genesis.go index a272404054f..ccf797e0d49 100644 --- a/modules/core/02-client/types/genesis.go +++ b/modules/core/02-client/types/genesis.go @@ -196,7 +196,6 @@ func (gs GenesisState) Validate() error { if err := gm.Validate(); err != nil { return fmt.Errorf("invalid client metadata %v clientID %s index %d: %w", gm, clientMetadata.ClientId, i, err) } - } } diff --git a/modules/core/02-client/types/height_test.go b/modules/core/02-client/types/height_test.go index c31bbaabf21..16415c3d61e 100644 --- a/modules/core/02-client/types/height_test.go +++ b/modules/core/02-client/types/height_test.go @@ -126,7 +126,6 @@ func TestParseChainID(t *testing.T) { revision := types.ParseChainID(tc.chainID) require.Equal(t, tc.revision, revision, "chainID %s returns incorrect revision", tc.chainID) } - } func TestSetRevisionNumber(t *testing.T) { diff --git a/modules/core/02-client/types/msgs.go b/modules/core/02-client/types/msgs.go index d80fe8b0592..e329a58ab49 100644 --- a/modules/core/02-client/types/msgs.go +++ b/modules/core/02-client/types/msgs.go @@ -34,7 +34,6 @@ var ( func NewMsgCreateClient( clientState exported.ClientState, consensusState exported.ConsensusState, signer string, ) (*MsgCreateClient, error) { - anyClientState, err := PackClientState(clientState) if err != nil { return nil, err @@ -154,7 +153,8 @@ func (msg MsgUpdateClient) UnpackInterfaces(unpacker codectypes.AnyUnpacker) err // NewMsgUpgradeClient creates a new MsgUpgradeClient instance // nolint: interfacer func NewMsgUpgradeClient(clientID string, clientState exported.ClientState, consState exported.ConsensusState, - proofUpgradeClient, proofUpgradeConsState []byte, signer string) (*MsgUpgradeClient, error) { + proofUpgradeClient, proofUpgradeConsState []byte, signer string, +) (*MsgUpgradeClient, error) { anyClient, err := PackClientState(clientState) if err != nil { return nil, err diff --git a/modules/core/02-client/types/msgs_test.go b/modules/core/02-client/types/msgs_test.go index ce5ecd159cb..ec0b87ac0bb 100644 --- a/modules/core/02-client/types/msgs_test.go +++ b/modules/core/02-client/types/msgs_test.go @@ -211,7 +211,6 @@ func (suite *TypesTestSuite) TestMarshalMsgUpdateClient() { "tendermint client", func() { msg, err = types.NewMsgUpdateClient("tendermint", suite.chainA.CurrentTMClientHeader(), suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) - }, }, } @@ -496,7 +495,6 @@ func (suite *TypesTestSuite) TestMarshalMsgSubmitMisbehaviour() { misbehaviour := ibctmtypes.NewMisbehaviour("tendermint", header1, header2) msg, err = types.NewMsgSubmitMisbehaviour("tendermint", misbehaviour, suite.chainA.SenderAccount.GetAddress().String()) suite.Require().NoError(err) - }, }, } diff --git a/modules/core/02-client/types/proposal_test.go b/modules/core/02-client/types/proposal_test.go index a32dcdac4e8..d1a6f52cf71 100644 --- a/modules/core/02-client/types/proposal_test.go +++ b/modules/core/02-client/types/proposal_test.go @@ -117,7 +117,6 @@ func (suite *TypesTestSuite) TestUpgradeProposalValidateBasic() { "fails validate abstract - empty title", func() { proposal, err = types.NewUpgradeProposal("", ibctesting.Description, plan, cs) suite.Require().NoError(err) - }, false, }, { @@ -199,7 +198,6 @@ func (suite *TypesTestSuite) TestMarshalUpgradeProposal() { // unpack client state _, err = types.UnpackClientState(newUp.UpgradedClientState) suite.Require().NoError(err) - } func (suite *TypesTestSuite) TestUpgradeString() { diff --git a/modules/core/03-connection/client/utils/utils.go b/modules/core/03-connection/client/utils/utils.go index 3bd54a44541..aaadcf9feae 100644 --- a/modules/core/03-connection/client/utils/utils.go +++ b/modules/core/03-connection/client/utils/utils.go @@ -105,7 +105,6 @@ func queryClientConnectionsABCI(clientCtx client.Context, clientID string) (*typ func QueryConnectionClientState( clientCtx client.Context, connectionID string, prove bool, ) (*types.QueryConnectionClientStateResponse, error) { - queryClient := types.NewQueryClient(clientCtx) req := &types.QueryConnectionClientStateRequest{ ConnectionId: connectionID, @@ -140,7 +139,6 @@ func QueryConnectionClientState( func QueryConnectionConsensusState( clientCtx client.Context, connectionID string, height clienttypes.Height, prove bool, ) (*types.QueryConnectionConsensusStateResponse, error) { - queryClient := types.NewQueryClient(clientCtx) req := &types.QueryConnectionConsensusStateRequest{ ConnectionId: connectionID, diff --git a/modules/core/03-connection/keeper/events.go b/modules/core/03-connection/keeper/events.go index 6b1636ea71e..a8dcd1251a7 100644 --- a/modules/core/03-connection/keeper/events.go +++ b/modules/core/03-connection/keeper/events.go @@ -2,7 +2,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - + "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" ) diff --git a/modules/core/03-connection/keeper/grpc_query.go b/modules/core/03-connection/keeper/grpc_query.go index 77d8bc98c84..89e9b978e0b 100644 --- a/modules/core/03-connection/keeper/grpc_query.go +++ b/modules/core/03-connection/keeper/grpc_query.go @@ -68,7 +68,6 @@ func (q Keeper) Connections(c context.Context, req *types.QueryConnectionsReques connections = append(connections, &identifiedConnection) return nil }) - if err != nil { return nil, err } @@ -137,7 +136,6 @@ func (q Keeper) ConnectionClientState(c context.Context, req *types.QueryConnect height := clienttypes.GetSelfHeight(ctx) return types.NewQueryConnectionClientStateResponse(identifiedClientState, nil, height), nil - } // ConnectionConsensusState implements the Query/ConnectionConsensusState gRPC method diff --git a/modules/core/03-connection/keeper/grpc_query_test.go b/modules/core/03-connection/keeper/grpc_query_test.go index a2542fe62b2..fe97dd09b85 100644 --- a/modules/core/03-connection/keeper/grpc_query_test.go +++ b/modules/core/03-connection/keeper/grpc_query_test.go @@ -30,13 +30,15 @@ func (suite *KeeperTestSuite) TestQueryConnection() { }, false, }, - {"invalid connectionID", + { + "invalid connectionID", func() { req = &types.QueryConnectionRequest{} }, false, }, - {"connection not found", + { + "connection not found", func() { req = &types.QueryConnectionRequest{ ConnectionId: ibctesting.InvalidID, @@ -186,13 +188,15 @@ func (suite *KeeperTestSuite) TestQueryClientConnections() { }, false, }, - {"invalid connectionID", + { + "invalid connectionID", func() { req = &types.QueryClientConnectionsRequest{} }, false, }, - {"connection not found", + { + "connection not found", func() { req = &types.QueryClientConnectionsRequest{ ClientId: ibctesting.InvalidID, diff --git a/modules/core/03-connection/keeper/handshake_test.go b/modules/core/03-connection/keeper/handshake_test.go index 6f5dfbce1d9..8707b72d401 100644 --- a/modules/core/03-connection/keeper/handshake_test.go +++ b/modules/core/03-connection/keeper/handshake_test.go @@ -370,7 +370,6 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { tmClient.ChainId = "wrongchainid" suite.chainB.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainB.GetContext(), path.EndpointB.ClientID, tmClient) - }, false}, {"consensus height >= latest height", func() { err := path.EndpointA.ConnOpenInit() @@ -554,7 +553,6 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { err = path.EndpointB.ConnOpenTry() suite.Require().NoError(err) - }, false}, } diff --git a/modules/core/03-connection/keeper/keeper_test.go b/modules/core/03-connection/keeper/keeper_test.go index b4dfa839028..3d63ed468ba 100644 --- a/modules/core/03-connection/keeper/keeper_test.go +++ b/modules/core/03-connection/keeper/keeper_test.go @@ -45,7 +45,6 @@ func (suite *KeeperTestSuite) TestSetAndGetConnection() { } func (suite *KeeperTestSuite) TestSetAndGetClientConnectionPaths() { - path := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) diff --git a/modules/core/03-connection/types/codec.go b/modules/core/03-connection/types/codec.go index 8f65884aadf..96ae3cba865 100644 --- a/modules/core/03-connection/types/codec.go +++ b/modules/core/03-connection/types/codec.go @@ -38,11 +38,9 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } -var ( - // SubModuleCdc references the global x/ibc/core/03-connection module codec. Note, the codec should - // ONLY be used in certain instances of tests and for JSON encoding. - // - // The actual codec used for serialization should be provided to x/ibc/core/03-connection and - // defined at the application level. - SubModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) -) +// SubModuleCdc references the global x/ibc/core/03-connection module codec. Note, the codec should +// ONLY be used in certain instances of tests and for JSON encoding. +// +// The actual codec used for serialization should be provided to x/ibc/core/03-connection and +// defined at the application level. +var SubModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) diff --git a/modules/core/03-connection/types/genesis_test.go b/modules/core/03-connection/types/genesis_test.go index db2192385b7..31906350531 100644 --- a/modules/core/03-connection/types/genesis_test.go +++ b/modules/core/03-connection/types/genesis_test.go @@ -11,7 +11,6 @@ import ( ) func TestValidateGenesis(t *testing.T) { - testCases := []struct { name string genState types.GenesisState diff --git a/modules/core/03-connection/types/msgs_test.go b/modules/core/03-connection/types/msgs_test.go index 9cf741bb2c0..b6f4544b98f 100644 --- a/modules/core/03-connection/types/msgs_test.go +++ b/modules/core/03-connection/types/msgs_test.go @@ -68,7 +68,6 @@ func (suite *MsgTestSuite) SetupTest() { suite.Require().NoError(err) suite.proof = proof - } func TestMsgTestSuite(t *testing.T) { @@ -81,7 +80,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenInit() { // will be used in protocol. var version *types.Version - var testCases = []struct { + testCases := []struct { name string msg *types.MsgConnectionOpenInit expPass bool @@ -124,7 +123,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() { chainID, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod, ibctesting.MaxClockDrift, clienttypes.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, ) - var testCases = []struct { + testCases := []struct { name string msg *types.MsgConnectionOpenTry expPass bool @@ -176,7 +175,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenAck() { ) connectionID := "connection-0" - var testCases = []struct { + testCases := []struct { name string msg *types.MsgConnectionOpenAck expPass bool @@ -215,7 +214,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenConfirm() { types.NewMsgConnectionOpenConfirm(connectionID, suite.proof, clientHeight, signer), } - var testCases = []struct { + testCases := []struct { msg *types.MsgConnectionOpenConfirm expPass bool errMsg string diff --git a/modules/core/03-connection/types/version_test.go b/modules/core/03-connection/types/version_test.go index 3fa637cc4de..404f4f8ca56 100644 --- a/modules/core/03-connection/types/version_test.go +++ b/modules/core/03-connection/types/version_test.go @@ -141,7 +141,6 @@ func TestVerifyProposedVersion(t *testing.T) { require.Error(t, err, "test case %d: %s", i, tc.name) } } - } func TestVerifySupportedFeature(t *testing.T) { diff --git a/modules/core/04-channel/client/utils/utils.go b/modules/core/04-channel/client/utils/utils.go index de40903e6fb..4124fe9b2b4 100644 --- a/modules/core/04-channel/client/utils/utils.go +++ b/modules/core/04-channel/client/utils/utils.go @@ -64,7 +64,6 @@ func queryChannelABCI(clientCtx client.Context, portID, channelID string) (*type func QueryChannelClientState( clientCtx client.Context, portID, channelID string, prove bool, ) (*types.QueryChannelClientStateResponse, error) { - queryClient := types.NewQueryClient(clientCtx) req := &types.QueryChannelClientStateRequest{ PortId: portID, @@ -99,7 +98,6 @@ func QueryChannelClientState( func QueryChannelConsensusState( clientCtx client.Context, portID, channelID string, height clienttypes.Height, prove bool, ) (*types.QueryChannelConsensusStateResponse, error) { - queryClient := types.NewQueryClient(clientCtx) req := &types.QueryChannelConsensusStateRequest{ PortId: portID, diff --git a/modules/core/04-channel/keeper/grpc_query.go b/modules/core/04-channel/keeper/grpc_query.go index 6bd8418a564..6d4b150ada9 100644 --- a/modules/core/04-channel/keeper/grpc_query.go +++ b/modules/core/04-channel/keeper/grpc_query.go @@ -69,7 +69,6 @@ func (q Keeper) Channels(c context.Context, req *types.QueryChannelsRequest) (*t channels = append(channels, &identifiedChannel) return nil }) - if err != nil { return nil, err } @@ -118,7 +117,6 @@ func (q Keeper) ConnectionChannels(c context.Context, req *types.QueryConnection channels = append(channels, &identifiedChannel) return nil }) - if err != nil { return nil, err } @@ -252,7 +250,6 @@ func (q Keeper) PacketCommitments(c context.Context, req *types.QueryPacketCommi commitments = append(commitments, &commitment) return nil }) - if err != nil { return nil, err } @@ -361,7 +358,6 @@ func (q Keeper) PacketAcknowledgements(c context.Context, req *types.QueryPacket return nil }) - if err != nil { return nil, err } @@ -401,7 +397,7 @@ func (q Keeper) UnreceivedPackets(c context.Context, req *types.QueryUnreceivedP ctx := sdk.UnwrapSDKContext(c) - var unreceivedSequences = []uint64{} + unreceivedSequences := []uint64{} for i, seq := range req.PacketCommitmentSequences { if seq == 0 { @@ -450,7 +446,7 @@ func (q Keeper) UnreceivedAcks(c context.Context, req *types.QueryUnreceivedAcks ctx := sdk.UnwrapSDKContext(c) - var unreceivedSequences = []uint64{} + unreceivedSequences := []uint64{} for i, seq := range req.PacketAckSequences { if seq == 0 { diff --git a/modules/core/04-channel/keeper/grpc_query_test.go b/modules/core/04-channel/keeper/grpc_query_test.go index cc899e99444..64c81f2105d 100644 --- a/modules/core/04-channel/keeper/grpc_query_test.go +++ b/modules/core/04-channel/keeper/grpc_query_test.go @@ -51,7 +51,8 @@ func (suite *KeeperTestSuite) TestQueryChannel() { }, false, }, - {"channel not found", + { + "channel not found", func() { req = &types.QueryChannelRequest{ PortId: "test-port-id", @@ -628,7 +629,8 @@ func (suite *KeeperTestSuite) TestQueryPacketCommitment() { }, false, }, - {"invalid sequence", + { + "invalid sequence", func() { req = &types.QueryPacketCommitmentRequest{ PortId: "test-port-id", @@ -638,7 +640,8 @@ func (suite *KeeperTestSuite) TestQueryPacketCommitment() { }, false, }, - {"channel not found", + { + "channel not found", func() { req = &types.QueryPacketCommitmentRequest{ PortId: "test-port-id", @@ -819,7 +822,8 @@ func (suite *KeeperTestSuite) TestQueryPacketReceipt() { }, false, }, - {"invalid sequence", + { + "invalid sequence", func() { req = &types.QueryPacketReceiptRequest{ PortId: "test-port-id", @@ -923,7 +927,8 @@ func (suite *KeeperTestSuite) TestQueryPacketAcknowledgement() { }, false, }, - {"invalid sequence", + { + "invalid sequence", func() { req = &types.QueryPacketAcknowledgementRequest{ PortId: "test-port-id", @@ -933,7 +938,8 @@ func (suite *KeeperTestSuite) TestQueryPacketAcknowledgement() { }, false, }, - {"channel not found", + { + "channel not found", func() { req = &types.QueryPacketAcknowledgementRequest{ PortId: "test-port-id", @@ -1400,7 +1406,8 @@ func (suite *KeeperTestSuite) TestQueryNextSequenceReceive() { }, false, }, - {"channel not found", + { + "channel not found", func() { req = &types.QueryNextSequenceReceiveRequest{ PortId: "test-port-id", diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index db6cce545c9..4d05df46533 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -220,7 +220,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { } }) } - } // TestRecvPacket test RecvPacket on chainB. Since packet commitment verification will always @@ -487,7 +486,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { } }) } - } func (suite *KeeperTestSuite) TestWriteAcknowledgement() { diff --git a/modules/core/04-channel/keeper/timeout_test.go b/modules/core/04-channel/keeper/timeout_test.go index a7151c4c0ff..ae3a816ef16 100644 --- a/modules/core/04-channel/keeper/timeout_test.go +++ b/modules/core/04-channel/keeper/timeout_test.go @@ -430,5 +430,4 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { } }) } - } diff --git a/modules/core/23-commitment/types/merkle_test.go b/modules/core/23-commitment/types/merkle_test.go index 28b8b3cd0dd..68a96c9b0c3 100644 --- a/modules/core/23-commitment/types/merkle_test.go +++ b/modules/core/23-commitment/types/merkle_test.go @@ -72,7 +72,6 @@ func (suite *MerkleTestSuite) TestVerifyMembership() { } }) } - } func (suite *MerkleTestSuite) TestVerifyNonMembership() { @@ -136,7 +135,6 @@ func (suite *MerkleTestSuite) TestVerifyNonMembership() { } }) } - } func TestApplyPrefix(t *testing.T) { diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 3a6cc5cb23b..12b259498ea 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -52,12 +52,12 @@ func NewKeeper( // panic if any of the keepers passed in is empty if reflect.ValueOf(stakingKeeper).IsZero() { panic(fmt.Errorf("cannot initialize IBC keeper: empty staking keeper")) - } - + } + if reflect.ValueOf(upgradeKeeper).IsZero() { panic(fmt.Errorf("cannot initialize IBC keeper: empty upgrade keeper")) - } - + } + if reflect.DeepEqual(capabilitykeeper.ScopedKeeper{}, scopedKeeper) { panic(fmt.Errorf("cannot initialize IBC keeper: empty scoped keeper")) } diff --git a/modules/core/keeper/keeper_test.go b/modules/core/keeper/keeper_test.go index d40d1ab34c5..8e8c1138374 100644 --- a/modules/core/keeper/keeper_test.go +++ b/modules/core/keeper/keeper_test.go @@ -83,20 +83,17 @@ func (suite *KeeperTestSuite) TestNewKeeper() { emptyStakingKeeper := stakingkeeper.Keeper{} stakingKeeper = emptyStakingKeeper - }, false}, {"failure: empty mock staking keeper", func() { // use a different implementation of clienttypes.StakingKeeper emptyMockStakingKeeper := MockStakingKeeper{} stakingKeeper = emptyMockStakingKeeper - }, false}, {"failure: empty upgrade keeper", func() { emptyUpgradeKeeper := upgradekeeper.Keeper{} upgradeKeeper = emptyUpgradeKeeper - }, false}, {"failure: empty scoped keeper", func() { emptyScopedKeeper := capabilitykeeper.ScopedKeeper{} @@ -116,7 +113,6 @@ func (suite *KeeperTestSuite) TestNewKeeper() { suite.SetupTest() suite.Run(tc.name, func() { - stakingKeeper = suite.chainA.GetSimApp().StakingKeeper upgradeKeeper = suite.chainA.GetSimApp().UpgradeKeeper scopedKeeper = suite.chainA.GetSimApp().ScopedIBCKeeper @@ -132,7 +128,6 @@ func (suite *KeeperTestSuite) TestNewKeeper() { newIBCKeeper, ) } - }) } } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index a4aeb496f6f..c090d7187d7 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -16,9 +16,11 @@ import ( coretypes "github.com/cosmos/ibc-go/v3/modules/core/types" ) -var _ clienttypes.MsgServer = Keeper{} -var _ connectiontypes.MsgServer = Keeper{} -var _ channeltypes.MsgServer = Keeper{} +var ( + _ clienttypes.MsgServer = Keeper{} + _ connectiontypes.MsgServer = Keeper{} + _ channeltypes.MsgServer = Keeper{} +) // CreateClient defines a rpc handler method for MsgCreateClient. func (k Keeper) CreateClient(goCtx context.Context, msg *clienttypes.MsgCreateClient) (*clienttypes.MsgCreateClientResponse, error) { diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 7e01241be81..3cb0dc4fca0 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -415,7 +415,6 @@ func (suite *KeeperTestSuite) TestHandleTimeoutPacket() { path.EndpointA.UpdateClient() packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) - }, true}, {"channel does not exist", func() { // any non-nil value of packet is valid @@ -645,7 +644,6 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { { name: "successful upgrade", setup: func() { - upgradedClient = ibctmtypes.NewClientState(newChainId, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) // Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient upgradedClient = upgradedClient.ZeroCustomFields() @@ -686,7 +684,6 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { { name: "VerifyUpgrade fails", setup: func() { - upgradedClient = ibctmtypes.NewClientState(newChainId, ibctmtypes.DefaultTrustLevel, ibctesting.TrustingPeriod, ibctesting.UnbondingPeriod+ibctesting.TrustingPeriod, ibctesting.MaxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false) // Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient upgradedClient = upgradedClient.ZeroCustomFields() diff --git a/modules/light-clients/06-solomachine/types/client_state_test.go b/modules/light-clients/06-solomachine/types/client_state_test.go index 09ea9693119..16b62b2722b 100644 --- a/modules/light-clients/06-solomachine/types/client_state_test.go +++ b/modules/light-clients/06-solomachine/types/client_state_test.go @@ -82,7 +82,6 @@ func (suite *SoloMachineTestSuite) TestClientStateValidateBasic() { tc := tc suite.Run(tc.name, func() { - err := tc.clientState.Validate() if tc.expPass { @@ -238,7 +237,6 @@ func (suite *SoloMachineTestSuite) TestVerifyClientState() { tc := tc suite.Run(tc.name, func() { - var expSeq uint64 if tc.clientState.ConsensusState != nil { expSeq = tc.clientState.Sequence + 1 @@ -359,7 +357,6 @@ func (suite *SoloMachineTestSuite) TestVerifyClientConsensusState() { tc := tc suite.Run(tc.name, func() { - var expSeq uint64 if tc.clientState.ConsensusState != nil { expSeq = tc.clientState.Sequence + 1 diff --git a/modules/light-clients/06-solomachine/types/codec_test.go b/modules/light-clients/06-solomachine/types/codec_test.go index 1a0e3e0086f..0ed8760daa3 100644 --- a/modules/light-clients/06-solomachine/types/codec_test.go +++ b/modules/light-clients/06-solomachine/types/codec_test.go @@ -55,7 +55,6 @@ func (suite SoloMachineTestSuite) TestUnmarshalDataByType() { path := solomachine.GetConsensusStatePath(counterpartyClientIdentifier, clienttypes.NewHeight(0, 5)) data, err = types.ConsensusStateDataBytes(cdc, path, solomachine.ConsensusState()) suite.Require().NoError(err) - }, true, }, { @@ -73,7 +72,6 @@ func (suite SoloMachineTestSuite) TestUnmarshalDataByType() { data, err = types.ConnectionStateDataBytes(cdc, path, conn) suite.Require().NoError(err) - }, true, }, { @@ -104,7 +102,6 @@ func (suite SoloMachineTestSuite) TestUnmarshalDataByType() { data, err = types.ConnectionStateDataBytes(cdc, path, conn) suite.Require().NoError(err) - }, false, }, { @@ -186,5 +183,4 @@ func (suite SoloMachineTestSuite) TestUnmarshalDataByType() { }) } } - } diff --git a/modules/light-clients/06-solomachine/types/consensus_state_test.go b/modules/light-clients/06-solomachine/types/consensus_state_test.go index 33e200c5461..2bb1ab5a456 100644 --- a/modules/light-clients/06-solomachine/types/consensus_state_test.go +++ b/modules/light-clients/06-solomachine/types/consensus_state_test.go @@ -61,7 +61,6 @@ func (suite *SoloMachineTestSuite) TestConsensusStateValidateBasic() { tc := tc suite.Run(tc.name, func() { - err := tc.consensusState.ValidateBasic() if tc.expPass { diff --git a/modules/light-clients/06-solomachine/types/misbehaviour_handle.go b/modules/light-clients/06-solomachine/types/misbehaviour_handle.go index d5a1d57cb57..fb3dc573c3e 100644 --- a/modules/light-clients/06-solomachine/types/misbehaviour_handle.go +++ b/modules/light-clients/06-solomachine/types/misbehaviour_handle.go @@ -21,7 +21,6 @@ func (cs ClientState) CheckMisbehaviourAndUpdateState( clientStore sdk.KVStore, misbehaviour exported.Misbehaviour, ) (exported.ClientState, error) { - soloMisbehaviour, ok := misbehaviour.(*Misbehaviour) if !ok { return nil, sdkerrors.Wrapf( @@ -51,7 +50,6 @@ func (cs ClientState) CheckMisbehaviourAndUpdateState( // over the provided data and that the data is valid. The data is valid if it can be // unmarshaled into the specified data type. func verifySignatureAndData(cdc codec.BinaryCodec, clientState ClientState, misbehaviour *Misbehaviour, sigAndData *SignatureAndData) error { - // do not check misbehaviour timestamp since we want to allow processing of past misbehaviour // ensure data can be unmarshaled to the specified data type @@ -85,5 +83,4 @@ func verifySignatureAndData(cdc codec.BinaryCodec, clientState ClientState, misb } return nil - } diff --git a/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go b/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go index db58b710772..7aa19617a76 100644 --- a/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go +++ b/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go @@ -227,7 +227,6 @@ func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { m.SignatureTwo.Data = msg misbehaviour = m - }, false, }, diff --git a/modules/light-clients/06-solomachine/types/misbehaviour_test.go b/modules/light-clients/06-solomachine/types/misbehaviour_test.go index 813a8520ee7..c304fc576ed 100644 --- a/modules/light-clients/06-solomachine/types/misbehaviour_test.go +++ b/modules/light-clients/06-solomachine/types/misbehaviour_test.go @@ -113,7 +113,6 @@ func (suite *SoloMachineTestSuite) TestMisbehaviourValidateBasic() { tc := tc suite.Run(tc.name, func() { - misbehaviour := solomachine.CreateMisbehaviour() tc.malleateMisbehaviour(misbehaviour) diff --git a/modules/light-clients/06-solomachine/types/proof.go b/modules/light-clients/06-solomachine/types/proof.go index f884a26d745..75a58cc3101 100644 --- a/modules/light-clients/06-solomachine/types/proof.go +++ b/modules/light-clients/06-solomachine/types/proof.go @@ -55,7 +55,8 @@ func MisbehaviourSignBytes( sequence, timestamp uint64, diversifier string, dataType DataType, - data []byte) ([]byte, error) { + data []byte, +) ([]byte, error) { signBytes := &SignBytes{ Sequence: sequence, Timestamp: timestamp, diff --git a/modules/light-clients/06-solomachine/types/proposal_handle.go b/modules/light-clients/06-solomachine/types/proposal_handle.go index a28bc27c398..c7d29faedc9 100644 --- a/modules/light-clients/06-solomachine/types/proposal_handle.go +++ b/modules/light-clients/06-solomachine/types/proposal_handle.go @@ -22,7 +22,6 @@ func (cs ClientState) CheckSubstituteAndUpdateState( ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore, _ sdk.KVStore, substituteClient exported.ClientState, ) (exported.ClientState, error) { - if !cs.AllowUpdateAfterProposal { return nil, sdkerrors.Wrapf( clienttypes.ErrUpdateClientFailed, diff --git a/modules/light-clients/06-solomachine/types/update_test.go b/modules/light-clients/06-solomachine/types/update_test.go index f13d5f198d1..ae3caa44a5c 100644 --- a/modules/light-clients/06-solomachine/types/update_test.go +++ b/modules/light-clients/06-solomachine/types/update_test.go @@ -122,7 +122,6 @@ func (suite *SoloMachineTestSuite) TestCheckHeaderAndUpdateState() { clientState = cs header = h - }, false, }, diff --git a/modules/light-clients/07-tendermint/types/client_state_test.go b/modules/light-clients/07-tendermint/types/client_state_test.go index cf52d2996b5..f45bd2fc6d6 100644 --- a/modules/light-clients/07-tendermint/types/client_state_test.go +++ b/modules/light-clients/07-tendermint/types/client_state_test.go @@ -27,9 +27,7 @@ const ( fiftyOneCharChainID = "123456789012345678901234567890123456789012345678901" ) -var ( - invalidProof = []byte("invalid proof") -) +var invalidProof = []byte("invalid proof") func (suite *TendermintTestSuite) TestStatus() { var ( @@ -166,7 +164,6 @@ func (suite *TendermintTestSuite) TestValidate() { } func (suite *TendermintTestSuite) TestInitialize() { - testCases := []struct { name string consensusState exported.ConsensusState diff --git a/modules/light-clients/07-tendermint/types/consensus_state_test.go b/modules/light-clients/07-tendermint/types/consensus_state_test.go index f45a4a5d24d..2d3be714799 100644 --- a/modules/light-clients/07-tendermint/types/consensus_state_test.go +++ b/modules/light-clients/07-tendermint/types/consensus_state_test.go @@ -14,49 +14,61 @@ func (suite *TendermintTestSuite) TestConsensusStateValidateBasic() { consensusState *types.ConsensusState expectPass bool }{ - {"success", + { + "success", &types.ConsensusState{ Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), NextValidatorsHash: suite.valsHash, }, - true}, - {"success with sentinel", + true, + }, + { + "success with sentinel", &types.ConsensusState{ Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot([]byte(types.SentinelRoot)), NextValidatorsHash: suite.valsHash, }, - true}, - {"root is nil", + true, + }, + { + "root is nil", &types.ConsensusState{ Timestamp: suite.now, Root: commitmenttypes.MerkleRoot{}, NextValidatorsHash: suite.valsHash, }, - false}, - {"root is empty", + false, + }, + { + "root is empty", &types.ConsensusState{ Timestamp: suite.now, Root: commitmenttypes.MerkleRoot{}, NextValidatorsHash: suite.valsHash, }, - false}, - {"nextvalshash is invalid", + false, + }, + { + "nextvalshash is invalid", &types.ConsensusState{ Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), NextValidatorsHash: []byte("hi"), }, - false}, + false, + }, - {"timestamp is zero", + { + "timestamp is zero", &types.ConsensusState{ Timestamp: time.Time{}, Root: commitmenttypes.NewMerkleRoot([]byte("app_hash")), NextValidatorsHash: suite.valsHash, }, - false}, + false, + }, } for i, tc := range testCases { diff --git a/modules/light-clients/07-tendermint/types/header_test.go b/modules/light-clients/07-tendermint/types/header_test.go index f57776c092f..8383a1a0be3 100644 --- a/modules/light-clients/07-tendermint/types/header_test.go +++ b/modules/light-clients/07-tendermint/types/header_test.go @@ -21,9 +21,7 @@ func (suite *TendermintTestSuite) TestGetTime() { } func (suite *TendermintTestSuite) TestHeaderValidateBasic() { - var ( - header *types.Header - ) + var header *types.Header testCases := []struct { name string malleate func() diff --git a/modules/light-clients/07-tendermint/types/misbehaviour_handle.go b/modules/light-clients/07-tendermint/types/misbehaviour_handle.go index 4c8224bde09..67f4fccdd98 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour_handle.go +++ b/modules/light-clients/07-tendermint/types/misbehaviour_handle.go @@ -101,7 +101,6 @@ func (cs ClientState) CheckMisbehaviourAndUpdateState( func checkMisbehaviourHeader( clientState *ClientState, consState *ConsensusState, header *Header, currentTimestamp time.Time, ) error { - tmTrustedValset, err := tmtypes.ValidatorSetFromProto(header.TrustedValidators) if err != nil { return sdkerrors.Wrap(err, "trusted validator set is not tendermint validator set type") diff --git a/modules/light-clients/07-tendermint/types/proposal_handle_test.go b/modules/light-clients/07-tendermint/types/proposal_handle_test.go index 822ec16e014..fa8bc7798de 100644 --- a/modules/light-clients/07-tendermint/types/proposal_handle_test.go +++ b/modules/light-clients/07-tendermint/types/proposal_handle_test.go @@ -9,9 +9,7 @@ import ( ibctesting "github.com/cosmos/ibc-go/v3/testing" ) -var ( - frozenHeight = clienttypes.NewHeight(0, 1) -) +var frozenHeight = clienttypes.NewHeight(0, 1) func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { var ( @@ -43,7 +41,6 @@ func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { tc := tc suite.Run(tc.name, func() { - suite.SetupTest() // reset subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) substitutePath = ibctesting.NewPath(suite.chainA, suite.chainB) @@ -217,7 +214,6 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { // a client are each tested to ensure that unexpiry headers cannot update // a client when a unfreezing header is required. suite.Run(tc.name, func() { - // start by testing unexpiring the client suite.SetupTest() // reset @@ -303,7 +299,6 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { suite.Require().Error(err) suite.Require().Nil(updatedClient) } - }) } } @@ -365,7 +360,6 @@ func (suite *TendermintTestSuite) TestIsMatchingClientState() { tc.malleate() suite.Require().Equal(tc.expPass, types.IsMatchingClientState(*subjectClientState, *substituteClientState)) - }) } } diff --git a/modules/light-clients/07-tendermint/types/store.go b/modules/light-clients/07-tendermint/types/store.go index 785ed77ba97..5cf7f5d8657 100644 --- a/modules/light-clients/07-tendermint/types/store.go +++ b/modules/light-clients/07-tendermint/types/store.go @@ -96,7 +96,6 @@ func IterateConsensusMetadata(store sdk.KVStore, cb func(key, val []byte) bool) if len(keySplit) != 3 { // ignore all consensus state keys continue - } if keySplit[2] != "processedTime" && keySplit[2] != "processedHeight" { diff --git a/modules/light-clients/07-tendermint/types/upgrade_test.go b/modules/light-clients/07-tendermint/types/upgrade_test.go index 175ce7fc358..6ad81df3520 100644 --- a/modules/light-clients/07-tendermint/types/upgrade_test.go +++ b/modules/light-clients/07-tendermint/types/upgrade_test.go @@ -10,9 +10,7 @@ import ( ibctesting "github.com/cosmos/ibc-go/v3/testing" ) -var ( - newChainId = "newChainId-1" -) +var newChainId = "newChainId-1" func (suite *TendermintTestSuite) TestVerifyUpgrade() { var ( diff --git a/modules/light-clients/09-localhost/types/client_state_test.go b/modules/light-clients/09-localhost/types/client_state_test.go index a54cc8efe9a..04b57fcbbf0 100644 --- a/modules/light-clients/09-localhost/types/client_state_test.go +++ b/modules/light-clients/09-localhost/types/client_state_test.go @@ -150,7 +150,6 @@ func (suite *LocalhostTestSuite) TestVerifyClientState() { } }) } - } func (suite *LocalhostTestSuite) TestVerifyClientConsensusState() { @@ -291,7 +290,6 @@ func (suite *LocalhostTestSuite) TestVerifyChannelState() { clientState: types.NewClientState("chainID", clientHeight), malleate: func() { suite.store.Set(host.ChannelKey(testPortID, testChannelID), []byte("channel")) - }, channel: ch1, expPass: false, @@ -303,7 +301,6 @@ func (suite *LocalhostTestSuite) TestVerifyChannelState() { bz, err := suite.cdc.Marshal(&ch2) suite.Require().NoError(err) suite.store.Set(host.ChannelKey(testPortID, testChannelID), bz) - }, channel: ch1, expPass: false, diff --git a/modules/light-clients/09-localhost/types/localhost_test.go b/modules/light-clients/09-localhost/types/localhost_test.go index ee8507c4efc..cb80d5ba424 100644 --- a/modules/light-clients/09-localhost/types/localhost_test.go +++ b/modules/light-clients/09-localhost/types/localhost_test.go @@ -17,9 +17,7 @@ const ( height = 4 ) -var ( - clientHeight = clienttypes.NewHeight(0, 10) -) +var clientHeight = clienttypes.NewHeight(0, 10) type LocalhostTestSuite struct { suite.Suite diff --git a/testing/coordinator.go b/testing/coordinator.go index 4c0ebc78463..dde3eb56b1a 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -181,7 +181,6 @@ func GetChainID(index int) string { // CONTRACT: the passed in list of indexes must not contain duplicates func (coord *Coordinator) CommitBlock(chains ...*TestChain) { for _, chain := range chains { - chain.NextBlock() } coord.IncrementTime() diff --git a/testing/events.go b/testing/events.go index 7828b42619f..8beaa0a2beb 100644 --- a/testing/events.go +++ b/testing/events.go @@ -64,7 +64,6 @@ func ParsePacketFromEvents(events sdk.Events) (channeltypes.Packet, error) { if ev.Type == channeltypes.EventTypeSendPacket { packet := channeltypes.Packet{} for _, attr := range ev.Attributes { - switch string(attr.Key) { case channeltypes.AttributeKeyData: packet.Data = attr.Value diff --git a/testing/mock/ibc_module_test.go b/testing/mock/ibc_module_test.go index d3efe9f142c..b36d58d2004 100644 --- a/testing/mock/ibc_module_test.go +++ b/testing/mock/ibc_module_test.go @@ -2,7 +2,7 @@ package mock_test import ( "testing" - + "github.com/stretchr/testify/require" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" diff --git a/testing/simapp/ante_handler.go b/testing/simapp/ante_handler.go index 04ffad13e2a..5d32e9199bb 100644 --- a/testing/simapp/ante_handler.go +++ b/testing/simapp/ante_handler.go @@ -28,7 +28,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") } - var sigGasConsumer = options.SigGasConsumer + sigGasConsumer := options.SigGasConsumer if sigGasConsumer == nil { sigGasConsumer = ante.DefaultSigVerificationGasConsumer } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index f707ba6087b..b09cf6dffb7 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -473,7 +473,7 @@ func NewSimApp( // NOTE: we may consider parsing `appOpts` inside module constructors. For the moment // we prefer to be more strict in what arguments the modules expect. - var skipGenesisInvariants = cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) + skipGenesisInvariants := cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. diff --git a/testing/simapp/params/amino.go b/testing/simapp/params/amino.go index 440c29f817e..0d43dd1eb8f 100644 --- a/testing/simapp/params/amino.go +++ b/testing/simapp/params/amino.go @@ -1,3 +1,4 @@ +//go:build test_amino // +build test_amino package params diff --git a/testing/simapp/params/proto.go b/testing/simapp/params/proto.go index 04aa524b900..a752d107907 100644 --- a/testing/simapp/params/proto.go +++ b/testing/simapp/params/proto.go @@ -1,3 +1,4 @@ +//go:build !test_amino // +build !test_amino package params diff --git a/testing/simapp/sim_test.go b/testing/simapp/sim_test.go index bbc8f4a8c0c..12c96755aca 100644 --- a/testing/simapp/sim_test.go +++ b/testing/simapp/sim_test.go @@ -163,11 +163,13 @@ func TestAppImportExport(t *testing.T) { storeKeysPrefixes := []StoreKeysPrefixes{ {app.keys[authtypes.StoreKey], newApp.keys[authtypes.StoreKey], [][]byte{}}, - {app.keys[stakingtypes.StoreKey], newApp.keys[stakingtypes.StoreKey], + { + app.keys[stakingtypes.StoreKey], newApp.keys[stakingtypes.StoreKey], [][]byte{ stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey, stakingtypes.HistoricalInfoKey, - }}, // ordering may change but it doesn't matter + }, + }, // ordering may change but it doesn't matter {app.keys[slashingtypes.StoreKey], newApp.keys[slashingtypes.StoreKey], [][]byte{}}, {app.keys[minttypes.StoreKey], newApp.keys[minttypes.StoreKey], [][]byte{}}, {app.keys[distrtypes.StoreKey], newApp.keys[distrtypes.StoreKey], [][]byte{}}, diff --git a/testing/simapp/simd/cmd/genaccounts_test.go b/testing/simapp/simd/cmd/genaccounts_test.go index 0cdf365bf93..c7c2f92682c 100644 --- a/testing/simapp/simd/cmd/genaccounts_test.go +++ b/testing/simapp/simd/cmd/genaccounts_test.go @@ -73,7 +73,8 @@ func TestAddGenesisAccountCmd(t *testing.T) { cmd.SetArgs([]string{ tc.addr, tc.denom, - fmt.Sprintf("--%s=home", flags.FlagHome)}) + fmt.Sprintf("--%s=home", flags.FlagHome), + }) if tc.expectErr { require.Error(t, cmd.ExecuteContext(ctx)) diff --git a/testing/simapp/simd/cmd/root.go b/testing/simapp/simd/cmd/root.go index e690093709e..e130cb16a32 100644 --- a/testing/simapp/simd/cmd/root.go +++ b/testing/simapp/simd/cmd/root.go @@ -279,8 +279,8 @@ func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, a // and exports state. func (a appCreator) appExport( logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, - appOpts servertypes.AppOptions) (servertypes.ExportedApp, error) { - + appOpts servertypes.AppOptions, +) (servertypes.ExportedApp, error) { var simApp *simapp.SimApp homePath, ok := appOpts.Get(flags.FlagHome).(string) if !ok || homePath == "" { diff --git a/testing/simapp/simd/cmd/testnet.go b/testing/simapp/simd/cmd/testnet.go index 019f534183b..657393fa915 100644 --- a/testing/simapp/simd/cmd/testnet.go +++ b/testing/simapp/simd/cmd/testnet.go @@ -93,7 +93,7 @@ Example: return cmd } -const nodeDirPerm = 0755 +const nodeDirPerm = 0o755 // Initialize the testnet func InitTestnet( @@ -112,7 +112,6 @@ func InitTestnet( algoStr string, numValidators int, ) error { - if chainID == "" { chainID = "chain-" + tmrand.NewRand().Str(6) } @@ -269,7 +268,6 @@ func initGenFiles( genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance, genFiles []string, numValidators int, ) error { - appGenState := mbm.DefaultGenesis(clientCtx.JSONCodec) // set the accounts in the genesis state @@ -316,7 +314,6 @@ func collectGenFiles( nodeIDs []string, valPubKeys []cryptotypes.PubKey, numValidators int, outputDir, nodeDirPrefix, nodeDaemonHome string, genBalIterator banktypes.GenesisBalancesIterator, ) error { - var appState json.RawMessage genTime := tmtime.Now() @@ -385,12 +382,12 @@ func writeFile(name string, dir string, contents []byte) error { writePath := filepath.Join(dir) file := filepath.Join(writePath, name) - err := tmos.EnsureDir(writePath, 0755) + err := tmos.EnsureDir(writePath, 0o755) if err != nil { return err } - err = tmos.WriteFile(file, contents, 0644) + err = tmos.WriteFile(file, contents, 0o644) if err != nil { return err } diff --git a/testing/simapp/state.go b/testing/simapp/state.go index 86f20e2b115..c0a9e2ea1ec 100644 --- a/testing/simapp/state.go +++ b/testing/simapp/state.go @@ -28,7 +28,6 @@ import ( func AppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simtypes.AppStateFn { return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config, ) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) { - if FlagGenesisTimeValue == 0 { genesisTimestamp = simtypes.RandTimestamp(r) } else { diff --git a/testing/simapp/test_helpers.go b/testing/simapp/test_helpers.go index 1df1714d8a7..8f76c8507ab 100644 --- a/testing/simapp/test_helpers.go +++ b/testing/simapp/test_helpers.go @@ -240,7 +240,6 @@ func SignAndDeliver( t *testing.T, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []sdk.Msg, chainID string, accNums, accSeqs []uint64, expSimPass, expPass bool, priv ...cryptotypes.PrivKey, ) (sdk.GasInfo, *sdk.Result, error) { - tx, err := helpers.GenTx( txCfg, msgs, diff --git a/testing/simapp/utils.go b/testing/simapp/utils.go index 9abfc060b94..51788f5a322 100644 --- a/testing/simapp/utils.go +++ b/testing/simapp/utils.go @@ -84,7 +84,7 @@ func CheckExportSimulation( return err } - if err := ioutil.WriteFile(config.ExportStatePath, []byte(exported.AppState), 0600); err != nil { + if err := ioutil.WriteFile(config.ExportStatePath, []byte(exported.AppState), 0o600); err != nil { return err } } @@ -96,7 +96,7 @@ func CheckExportSimulation( return err } - if err := ioutil.WriteFile(config.ExportParamsPath, paramsBz, 0600); err != nil { + if err := ioutil.WriteFile(config.ExportParamsPath, paramsBz, 0o600); err != nil { return err } } From 661b3d990c82593743cb1aef77ccac9ddff79744 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 24 May 2022 09:58:23 +0200 Subject: [PATCH 120/275] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebf85888868..465c738b2ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,7 +59,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1279](https://github.com/cosmos/ibc-go/pull/1279) Add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse. Emit channel version during OpenInit/OpenTry * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees -* (transfer) [\#996](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. ### Features From ba8c872fa7cc1dad3bb933ac6ce392fa97b59211 Mon Sep 17 00:00:00 2001 From: chatton Date: Tue, 24 May 2022 09:02:58 +0100 Subject: [PATCH 121/275] chore: Fixing github action workflows --- .github/workflows/check-docs.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-docs.yml b/.github/workflows/check-docs.yml index 0060623ba15..b14911092ce 100644 --- a/.github/workflows/check-docs.yml +++ b/.github/workflows/check-docs.yml @@ -3,7 +3,7 @@ name: Check docs build # This will check if the docs build successfully by running `npm run build` on: pull_request: - paths: + paths: - './docs' jobs: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d6f53753177..9bdb116f517 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout repository - - uses: actions/checkout@v3 + uses: actions/checkout@v3 - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | From 1ebaf3efc1ffe9f33fb3e2492739a407430fd596 Mon Sep 17 00:00:00 2001 From: chatton Date: Tue, 24 May 2022 09:29:54 +0100 Subject: [PATCH 122/275] chore: Specifying build command for the CodeQL action --- .github/workflows/codeql-analysis.yml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9bdb116f517..d6f09b1ef64 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -57,22 +57,8 @@ jobs: # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main if: env.GIT_DIFF - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release + - run: make build - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 From b57e6dd199e70b6581f481fea7a7be61985995cf Mon Sep 17 00:00:00 2001 From: Sean King Date: Tue, 24 May 2022 17:17:52 +0200 Subject: [PATCH 123/275] fix: cli params ordering ics29 (#1353) * fix: cli params * refactor: switch param ordering * fix: tests --- modules/apps/29-fee/client/cli/tx.go | 4 ++-- modules/apps/29-fee/keeper/msg_server_test.go | 2 +- modules/apps/29-fee/transfer_test.go | 2 +- modules/apps/29-fee/types/msgs.go | 2 +- modules/apps/29-fee/types/msgs_test.go | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/apps/29-fee/client/cli/tx.go b/modules/apps/29-fee/client/cli/tx.go index 81a8192d950..9c972316d91 100644 --- a/modules/apps/29-fee/client/cli/tx.go +++ b/modules/apps/29-fee/client/cli/tx.go @@ -101,10 +101,10 @@ func NewPayPacketFeeAsyncTxCmd() *cobra.Command { // NewRegisterCounterpartyAddress returns the command to create a MsgRegisterCounterpartyAddress func NewRegisterCounterpartyAddress() *cobra.Command { cmd := &cobra.Command{ - Use: "register-counterparty [address] [counterparty-address] [channel-id] [port-id]", + Use: "register-counterparty [port-id] [channel-id] [address] [counterparty-address] ", Short: "Register a counterparty relayer address on a given channel.", Long: strings.TrimSpace(`Register a counterparty relayer address on a given channel.`), - Example: fmt.Sprintf("%s tx ibc-fee register-counterparty cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 channel-0 transfer", version.AppName), + Example: fmt.Sprintf("%s tx ibc-fee register-counterparty transfer channel-0 cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2", version.AppName), Args: cobra.ExactArgs(4), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 84c7588a6b2..b4e665e56db 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -57,7 +57,7 @@ func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() { tc.malleate() - msg := types.NewMsgRegisterCounterpartyAddress(sender, counterparty, suite.path.EndpointA.ChannelConfig.PortID, channelID) + msg := types.NewMsgRegisterCounterpartyAddress(suite.path.EndpointA.ChannelConfig.PortID, channelID, sender, counterparty) _, err := suite.chainA.GetSimApp().IBCFeeKeeper.RegisterCounterpartyAddress(sdk.WrapSDKContext(ctx), msg) if tc.expPass { diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 2bfaff2f097..3f4545e9fdd 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -46,7 +46,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() { // to differentiate from the chainA.SenderAccount for checking successful relay payouts relayerAddress := suite.chainB.SenderAccount.GetAddress() - msgRegister := types.NewMsgRegisterCounterpartyAddress(suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + msgRegister := types.NewMsgRegisterCounterpartyAddress(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String()) _, err = suite.chainB.SendMsgs(msgRegister) suite.Require().NoError(err) // message committed diff --git a/modules/apps/29-fee/types/msgs.go b/modules/apps/29-fee/types/msgs.go index 594f8d81251..0e729edbd17 100644 --- a/modules/apps/29-fee/types/msgs.go +++ b/modules/apps/29-fee/types/msgs.go @@ -17,7 +17,7 @@ const ( ) // NewMsgRegisterCounterpartyAddress creates a new instance of MsgRegisterCounterpartyAddress -func NewMsgRegisterCounterpartyAddress(address, counterpartyAddress, portID, channelID string) *MsgRegisterCounterpartyAddress { +func NewMsgRegisterCounterpartyAddress(portID, channelID, address, counterpartyAddress string) *MsgRegisterCounterpartyAddress { return &MsgRegisterCounterpartyAddress{ Address: address, CounterpartyAddress: counterpartyAddress, diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go index 185e66dd758..17452a64b45 100644 --- a/modules/apps/29-fee/types/msgs_test.go +++ b/modules/apps/29-fee/types/msgs_test.go @@ -63,7 +63,7 @@ func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { } for i, tc := range testCases { - msg = types.NewMsgRegisterCounterpartyAddress(defaultAccAddress, defaultAccAddress, ibctesting.MockPort, ibctesting.FirstChannelID) + msg = types.NewMsgRegisterCounterpartyAddress(ibctesting.MockPort, ibctesting.FirstChannelID, defaultAccAddress, defaultAccAddress) tc.malleate() @@ -79,7 +79,7 @@ func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { func TestRegisterCountepartyAddressGetSigners(t *testing.T) { accAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - msg := types.NewMsgRegisterCounterpartyAddress(accAddress.String(), defaultAccAddress, ibctesting.MockPort, ibctesting.FirstChannelID) + msg := types.NewMsgRegisterCounterpartyAddress(ibctesting.MockPort, ibctesting.FirstChannelID, accAddress.String(), defaultAccAddress) require.Equal(t, []sdk.AccAddress{sdk.AccAddress(accAddress)}, msg.GetSigners()) } From 846306fe14018141f238b4e94eb8f52524b87a0c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 24 May 2022 21:30:25 +0200 Subject: [PATCH 124/275] add swagger for fee (#1403) * add swagger for fee * fix conflicts --- docs/client/config.json | 8 + docs/client/swagger-ui/swagger.yaml | 10334 +++++++++++++++++--------- 2 files changed, 6775 insertions(+), 3567 deletions(-) diff --git a/docs/client/config.json b/docs/client/config.json index 210674dcc7c..5c50905245f 100644 --- a/docs/client/config.json +++ b/docs/client/config.json @@ -30,6 +30,14 @@ } } }, + { + "url": "./tmp-swagger-gen/ibc/applications/fee/v1/query.swagger.json", + "operationIds": { + "rename": { + "Params": "FeeParams" + } + } + }, { "url": "./tmp-swagger-gen/ibc/core/client/v1/query.swagger.json", "operationIds": { diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml index 74f6ee85a9e..7e83bdcd814 100644 --- a/docs/client/swagger-ui/swagger.yaml +++ b/docs/client/swagger-ui/swagger.yaml @@ -399,32 +399,24 @@ paths: format: byte tags: - Query - /ibc/client/v1/params: + '/ibc/apps/fee/v1/counterparty_address/{relayer_address}/channel/{channel_id}': get: - summary: ClientParams queries all parameters of the ibc client. - operationId: ClientParams + summary: >- + CounterpartyAddress returns the registered counterparty address for + forward relaying + operationId: CounterpartyAddress responses: '200': description: A successful response. schema: type: object properties: - params: - description: params defines the parameters of the module. - type: object - properties: - allowed_clients: - type: array - items: - type: string - description: >- - allowed_clients defines the list of allowed client state - types. - description: >- - QueryClientParamsResponse is the response type for the - Query/ClientParams RPC - - method. + counterparty_address: + type: string + title: the counterparty address used to compensate forward relaying + title: >- + QueryCounterpartyAddressResponse defines the response type for the + CounterpartyAddress rpc default: description: An unexpected error response schema: @@ -614,243 +606,311 @@ paths: "@type": "type.googleapis.com/google.protobuf.Duration", "value": "1.212s" } + parameters: + - name: relayer_address + description: the relayer address to which the counterparty is registered + in: path + required: true + type: string + - name: channel_id + description: unique channel identifier + in: path + required: true + type: string tags: - Query - /ibc/core/client/v1/client_states: + /ibc/apps/fee/v1/fee_enabled: get: - summary: ClientStates queries all the IBC light clients of a chain. - operationId: ClientStates + summary: FeeEnabledChannels returns a list of all fee enabled channels + operationId: FeeEnabledChannels responses: '200': description: A successful response. schema: type: object properties: - client_states: + fee_enabled_channels: type: array items: type: object properties: - client_id: + port_id: type: string - title: client identifier - client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized + title: unique port identifier + channel_id: + type: string + title: unique channel identifier + title: >- + FeeEnabledChannel contains the PortID & ChannelID for a fee + enabled channel + title: list of fee enabled channels + title: >- + QueryFeeEnabledChannelsResponse defines the response type for the + FeeEnabledChannels rpc + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized - protocol buffer message. This string must contain at - least + protocol buffer message. This string must contain at + least - one "/" character. The last segment of the URL's - path must represent + one "/" character. The last segment of the URL's path + must represent - the fully qualified name of the type (as in + the fully qualified name of the type (as in - `path/google.protobuf.Duration`). The name should be - in a canonical form + `path/google.protobuf.Duration`). The name should be in + a canonical form - (e.g., leading "." is not accepted). + (e.g., leading "." is not accepted). - In practice, teams usually precompile into the - binary all types that they + In practice, teams usually precompile into the binary + all types that they - expect it to use in the context of Any. However, for - URLs which use the + expect it to use in the context of Any. However, for + URLs which use the - scheme `http`, `https`, or no scheme, one can - optionally set up a type + scheme `http`, `https`, or no scheme, one can optionally + set up a type - server that maps type URLs to message definitions as - follows: + server that maps type URLs to message definitions as + follows: - * If no scheme is provided, `https` is assumed. + * If no scheme is provided, `https` is assumed. - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results - based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - Note: this functionality is not currently available - in the official + Note: this functionality is not currently available in + the official - protobuf release, and it is not used for type URLs - beginning with + protobuf release, and it is not used for type URLs + beginning with - type.googleapis.com. + type.googleapis.com. - Schemes other than `http`, `https` (or the empty - scheme) might be + Schemes other than `http`, `https` (or the empty scheme) + might be - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the - above specified type. + used with implementation specific semantics. + value: + type: string + format: byte description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a - URL that describes the type of the serialized message. + URL that describes the type of the serialized message. - Protobuf library provides support to pack/unpack Any - values in the form + Protobuf library provides support to pack/unpack Any values + in the form - of utility functions or additional generated methods of - the Any type. + of utility functions or additional generated methods of the + Any type. - Example 1: Pack and unpack a message in C++. + Example 1: Pack and unpack a message in C++. - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - Example 2: Pack and unpack a message in Java. + Example 2: Pack and unpack a message in Java. - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - Example 3: Pack and unpack a message in Python. + Example 3: Pack and unpack a message in Python. - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - Example 4: Pack and unpack a message in Go + Example 4: Pack and unpack a message in Go - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } - The pack methods provided by protobuf library will by - default use + The pack methods provided by protobuf library will by + default use - 'type.googleapis.com/full.type.name' as the type URL and - the unpack + 'type.googleapis.com/full.type.name' as the type URL and the + unpack - methods only use the fully qualified type name after the - last '/' + methods only use the fully qualified type name after the + last '/' - in the type URL, for example "foo.bar.com/x/y.z" will - yield type + in the type URL, for example "foo.bar.com/x/y.z" will yield + type - name "y.z". + name "y.z". - JSON + JSON - ==== + ==== - The JSON representation of an `Any` value uses the - regular + The JSON representation of an `Any` value uses the regular - representation of the deserialized, embedded message, - with an + representation of the deserialized, embedded message, with + an - additional field `@type` which contains the type URL. - Example: + additional field `@type` which contains the type URL. + Example: - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - If the embedded message type is well-known and has a - custom JSON + If the embedded message type is well-known and has a custom + JSON - representation, that representation will be embedded - adding a field + representation, that representation will be embedded adding + a field - `value` which holds the custom JSON in addition to the - `@type` + `value` which holds the custom JSON in addition to the + `@type` - field. Example (for message - [google.protobuf.Duration][]): + field. Example (for message [google.protobuf.Duration][]): - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state - description: >- - IdentifiedClientState defines a client state with an - additional client + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. - identifier field. - description: list of stored ClientStates of the chain. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - title: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total + It is less efficient than using key. Only one of offset or key + should - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. - corresponding request message has used PageRequest. + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - description: >- - QueryClientStatesResponse is the response type for the - Query/ClientStates RPC + a count of the total number of items available for pagination in + UIs. - method. + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + - name: query_height + description: block height at which to query. + in: query + required: false + type: string + format: uint64 + tags: + - Query + '/ibc/apps/fee/v1/fee_enabled/port/{port_id}/channel/{channel_id}': + get: + summary: >- + FeeEnabledChannel returns true if the provided port and channel + identifiers belong to a fee enabled channel + operationId: FeeEnabledChannel + responses: + '200': + description: A successful response. + schema: + type: object + properties: + fee_enabled: + type: boolean + format: boolean + title: boolean flag representing the fee enabled channel status + title: >- + QueryFeeEnabledChannelResponse defines the response type for the + FeeEnabledChannel rpc default: description: An unexpected error response schema: @@ -1041,308 +1101,163 @@ paths: "value": "1.212s" } parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false + - name: port_id + description: unique port identifier + in: path + required: true type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false + - name: channel_id + description: unique channel identifier + in: path + required: true type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - format: boolean tags: - Query - '/ibc/core/client/v1/client_states/{client_id}': + '/ibc/apps/fee/v1/incentivized_packet/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}': get: - summary: ClientState queries an IBC light client. - operationId: ClientState + summary: >- + IncentivizedPacket returns all packet fees for a packet given its + identifier + operationId: IncentivizedPacket responses: '200': description: A successful response. schema: type: object properties: - client_state: + incentivized_packet: + title: the identified fees for the incentivized packet type: object properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized + packet_id: + title: >- + unique packet identifier comprised of the channel ID, port + ID and sequence + type: object + properties: + port_id: + type: string + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: + type: string + format: uint64 + title: packet sequence + packet_fees: + type: array + items: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees + associated with an IBC packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet timeout fee + refund_address: + type: string + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: optional list of relayers permitted to receive fees + title: >- + PacketFee contains ICS29 relayer fees, refund address + and optional list of permitted relayers + title: list of packet fees + title: >- + QueryIncentivizedPacketsResponse defines the response type for the + IncentivizedPacket rpc + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized - protocol buffer message. This string must contain at least + protocol buffer message. This string must contain at + least - one "/" character. The last segment of the URL's path must - represent + one "/" character. The last segment of the URL's path + must represent - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - - JSON - - ==== - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state associated with the request identifier - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryClientStateResponse is the response type for the - Query/ClientState RPC - - method. Besides the client state, it includes a proof and the - height from - - which the proof was retrieved. - default: - description: An unexpected error response - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in + the fully qualified name of the type (as in `path/google.protobuf.Duration`). The name should be in a canonical form @@ -1503,33 +1418,155 @@ paths: "value": "1.212s" } parameters: - - name: client_id - description: client state unique identifier + - name: packet_id.port_id + description: channel port identifier + in: path + required: true + type: string + - name: packet_id.channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: packet_id.sequence + description: packet sequence in: path required: true type: string + format: uint64 + - name: query_height + description: block height at which to query. + in: query + required: false + type: string + format: uint64 tags: - Query - '/ibc/core/client/v1/client_status/{client_id}': + /ibc/apps/fee/v1/incentivized_packets: get: - summary: Status queries the status of an IBC client. - operationId: ClientStatus + summary: >- + IncentivizedPackets returns all incentivized packets and their + associated fees + operationId: IncentivizedPackets responses: '200': description: A successful response. schema: type: object properties: - status: - type: string - description: >- - QueryClientStatusResponse is the response type for the - Query/ClientStatus RPC - - method. It returns the current status of the IBC client. - default: - description: An unexpected error response - schema: + incentivized_packets: + type: array + items: + type: object + properties: + packet_id: + title: >- + unique packet identifier comprised of the channel ID, + port ID and sequence + type: object + properties: + port_id: + type: string + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: + type: string + format: uint64 + title: packet sequence + packet_fees: + type: array + items: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees + associated with an IBC packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet timeout fee + refund_address: + type: string + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: >- + optional list of relayers permitted to receive + fees + title: >- + PacketFee contains ICS29 relayer fees, refund address + and optional list of permitted relayers + title: list of packet fees + title: >- + IdentifiedPacketFees contains a list of type PacketFee and + associated PacketId + title: list of identified fees for incentivized packets + title: >- + QueryIncentivizedPacketsResponse defines the response type for the + IncentivizedPackets rpc + default: + description: An unexpected error response + schema: type: object properties: error: @@ -1717,274 +1754,467 @@ paths: "value": "1.212s" } parameters: - - name: client_id - description: client unique identifier - in: path - required: true + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + - name: query_height + description: block height at which to query. + in: query + required: false type: string + format: uint64 tags: - Query - '/ibc/core/client/v1/consensus_states/{client_id}': + '/ibc/apps/fee/v1/incentivized_packets/port/{port_id}/channel/{channel_id}': get: - summary: |- - ConsensusStates queries all the consensus state associated with a given - client. - operationId: ConsensusStates + summary: Gets all incentivized packets for a specific channel + operationId: IncentivizedPacketsForChannel responses: '200': description: A successful response. schema: type: object properties: - consensus_states: + incentivized_packets: type: array items: type: object properties: - height: - title: consensus state height + packet_id: + title: >- + unique packet identifier comprised of the channel ID, + port ID and sequence type: object properties: - revision_number: + port_id: type: string - format: uint64 - title: the revision that the client is currently on - revision_height: + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: type: string format: uint64 - title: the height within the given revision + title: packet sequence + packet_fees: + type: array + items: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees + associated with an IBC packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet timeout fee + refund_address: + type: string + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: >- + optional list of relayers permitted to receive + fees + title: >- + PacketFee contains ICS29 relayer fees, refund address + and optional list of permitted relayers + title: list of packet fees + title: >- + IdentifiedPacketFees contains a list of type PacketFee and + associated PacketId + title: Map of all incentivized_packets + title: >- + QueryIncentivizedPacketsResponse defines the response type for the + incentivized packets RPC + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string description: >- - Normally the RevisionHeight is incremented at each - height while keeping + A URL/resource name that uniquely identifies the type of + the serialized - RevisionNumber the same. However some consensus - algorithms may choose to + protocol buffer message. This string must contain at + least - reset the height in certain conditions e.g. hard forks, - state-machine + one "/" character. The last segment of the URL's path + must represent - breaking changes In these cases, the RevisionNumber is - incremented so that + the fully qualified name of the type (as in - height continues to be monitonically increasing even as - the RevisionHeight + `path/google.protobuf.Duration`). The name should be in + a canonical form - gets reset - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized + (e.g., leading "." is not accepted). - protocol buffer message. This string must contain at - least - one "/" character. The last segment of the URL's - path must represent + In practice, teams usually precompile into the binary + all types that they - the fully qualified name of the type (as in + expect it to use in the context of Any. However, for + URLs which use the - `path/google.protobuf.Duration`). The name should be - in a canonical form + scheme `http`, `https`, or no scheme, one can optionally + set up a type - (e.g., leading "." is not accepted). + server that maps type URLs to message definitions as + follows: - In practice, teams usually precompile into the - binary all types that they + * If no scheme is provided, `https` is assumed. - expect it to use in the context of Any. However, for - URLs which use the + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - scheme `http`, `https`, or no scheme, one can - optionally set up a type + Note: this functionality is not currently available in + the official - server that maps type URLs to message definitions as - follows: + protobuf release, and it is not used for type URLs + beginning with + type.googleapis.com. - * If no scheme is provided, `https` is assumed. - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results - based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) + Schemes other than `http`, `https` (or the empty scheme) + might be - Note: this functionality is not currently available - in the official + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a - protobuf release, and it is not used for type URLs - beginning with + URL that describes the type of the serialized message. - type.googleapis.com. + Protobuf library provides support to pack/unpack Any values + in the form - Schemes other than `http`, `https` (or the empty - scheme) might be + of utility functions or additional generated methods of the + Any type. - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the - above specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - URL that describes the type of the serialized message. + Example 1: Pack and unpack a message in C++. + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - Protobuf library provides support to pack/unpack Any - values in the form + Example 2: Pack and unpack a message in Java. - of utility functions or additional generated methods of - the Any type. + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + Example 3: Pack and unpack a message in Python. - Example 1: Pack and unpack a message in C++. + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } + Example 4: Pack and unpack a message in Go - Example 2: Pack and unpack a message in Java. + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } + The pack methods provided by protobuf library will by + default use - Example 3: Pack and unpack a message in Python. + 'type.googleapis.com/full.type.name' as the type URL and the + unpack - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... + methods only use the fully qualified type name after the + last '/' - Example 4: Pack and unpack a message in Go + in the type URL, for example "foo.bar.com/x/y.z" will yield + type - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } + name "y.z". - The pack methods provided by protobuf library will by - default use - 'type.googleapis.com/full.type.name' as the type URL and - the unpack - methods only use the fully qualified type name after the - last '/' + JSON - in the type URL, for example "foo.bar.com/x/y.z" will - yield type + ==== - name "y.z". + The JSON representation of an `Any` value uses the regular + representation of the deserialized, embedded message, with + an + additional field `@type` which contains the type URL. + Example: - JSON + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - ==== + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - The JSON representation of an `Any` value uses the - regular + If the embedded message type is well-known and has a custom + JSON - representation of the deserialized, embedded message, - with an + representation, that representation will be embedded adding + a field - additional field `@type` which contains the type URL. - Example: + `value` which holds the custom JSON in addition to the + `@type` - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + field. Example (for message [google.protobuf.Duration][]): - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: port_id + in: path + required: true + type: string + - name: channel_id + in: path + required: true + type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. - If the embedded message type is well-known and has a - custom JSON + It is less efficient than using key. Only one of offset or key + should - representation, that representation will be embedded - adding a field + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. - `value` which holds the custom JSON in addition to the - `@type` + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include - field. Example (for message - [google.protobuf.Duration][]): + a count of the total number of items available for pagination in + UIs. - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state - description: >- - ConsensusStateWithHeight defines a consensus state with an - additional height + count_total is only respected when offset is used. It is ignored + when key - field. - title: consensus states associated with the identifier - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - title: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total + is set. + in: query + required: false + type: boolean + format: boolean + - name: query_height + description: Height to query at. + in: query + required: false + type: string + format: uint64 + tags: + - Query + '/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}': + get: + summary: >- + TotalAckFees returns the total acknowledgement fees for a packet given + its identifier + operationId: TotalAckFees + responses: + '200': + description: A successful response. + schema: + type: object + properties: + ack_fees: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the - corresponding request message has used PageRequest. + NOTE: The amount field is an Int which implements the custom + method - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - title: |- - QueryConsensusStatesResponse is the response type for the - Query/ConsensusStates RPC method + signatures required by gogoproto. + title: the total packet acknowledgement fees + title: >- + QueryTotalAckFeesResponse defines the response type for the + TotalAckFees rpc default: description: An unexpected error response schema: @@ -2175,286 +2405,57 @@ paths: "value": "1.212s" } parameters: - - name: client_id - description: client identifier + - name: packet_id.port_id + description: channel port identifier in: path required: true type: string - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false + - name: packet_id.channel_id + description: channel unique identifier + in: path + required: true type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false + - name: packet_id.sequence + description: packet sequence + in: path + required: true type: string format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - format: boolean tags: - Query - '/ibc/core/client/v1/consensus_states/{client_id}/revision/{revision_number}/height/{revision_height}': + '/ibc/apps/fee/v1/total_recv_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}': get: summary: >- - ConsensusState queries a consensus state associated with a client state - at - - a given height. - operationId: ConsensusState + TotalRecvFees returns the total receive fees for a packet given its + identifier + operationId: TotalRecvFees responses: '200': description: A successful response. schema: type: object properties: - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - - JSON - - ==== - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: >- - consensus state associated with the client identifier at the - given height - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine + recv_fees: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - breaking changes In these cases, the RevisionNumber is - incremented so that - height continues to be monitonically increasing even as the - RevisionHeight + NOTE: The amount field is an Int which implements the custom + method - gets reset + signatures required by gogoproto. + title: the total packet receive fees title: >- - QueryConsensusStateResponse is the response type for the - Query/ConsensusState - - RPC method + QueryTotalRecvFeesResponse defines the response type for the + TotalRecvFees rpc default: description: An unexpected error response schema: @@ -2645,220 +2646,57 @@ paths: "value": "1.212s" } parameters: - - name: client_id - description: client identifier + - name: packet_id.port_id + description: channel port identifier in: path required: true type: string - - name: revision_number - description: consensus state revision number + - name: packet_id.channel_id + description: channel unique identifier in: path required: true type: string - format: uint64 - - name: revision_height - description: consensus state revision height + - name: packet_id.sequence + description: packet sequence in: path required: true type: string format: uint64 - - name: latest_height - description: >- - latest_height overrrides the height field and queries the latest - stored - - ConsensusState. - in: query - required: false - type: boolean - format: boolean tags: - Query - /ibc/core/client/v1/upgraded_client_states: + '/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}': get: - summary: UpgradedClientState queries an Upgraded IBC light client. - operationId: UpgradedClientState + summary: >- + TotalTimeoutFees returns the total timeout fees for a packet given its + identifier + operationId: TotalTimeoutFees responses: '200': description: A successful response. schema: type: object properties: - upgraded_client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the - - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - - JSON - - ==== - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field + timeout_fees: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - `value` which holds the custom JSON in addition to the `@type` - field. Example (for message [google.protobuf.Duration][]): + NOTE: The amount field is an Int which implements the custom + method - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state associated with the request identifier - description: |- - QueryUpgradedClientStateResponse is the response type for the - Query/UpgradedClientState RPC method. + signatures required by gogoproto. + title: the total packet timeout fees + title: >- + QueryTotalTimeoutFeesResponse defines the response type for the + TotalTimeoutFees rpc default: description: An unexpected error response schema: @@ -3048,193 +2886,51 @@ paths: "@type": "type.googleapis.com/google.protobuf.Duration", "value": "1.212s" } + parameters: + - name: packet_id.port_id + description: channel port identifier + in: path + required: true + type: string + - name: packet_id.channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: packet_id.sequence + description: packet sequence + in: path + required: true + type: string + format: uint64 tags: - Query - /ibc/core/client/v1/upgraded_consensus_states: + /ibc/client/v1/params: get: - summary: UpgradedConsensusState queries an Upgraded IBC consensus state. - operationId: UpgradedConsensusState + summary: ClientParams queries all parameters of the ibc client. + operationId: ClientParams responses: '200': description: A successful response. schema: type: object properties: - upgraded_consensus_state: + params: + description: params defines the parameters of the module. type: object properties: - type_url: - type: string + allowed_clients: + type: array + items: + type: string description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they - - expect it to use in the context of Any. However, for URLs - which use the + allowed_clients defines the list of allowed client state + types. + description: >- + QueryClientParamsResponse is the response type for the + Query/ClientParams RPC - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty scheme) - might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - - JSON - - ==== - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field - - `value` which holds the custom JSON in addition to the `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: Consensus state associated with the request identifier - description: |- - QueryUpgradedConsensusStateResponse is the response type for the - Query/UpgradedConsensusState RPC method. + method. default: description: An unexpected error response schema: @@ -3426,107 +3122,289 @@ paths: } tags: - Query - '/ibc/core/connection/v1/client_connections/{client_id}': + /ibc/core/client/v1/client_states: get: - summary: |- - ClientConnections queries the connection paths associated with a client - state. - operationId: ClientConnections + summary: ClientStates queries all the IBC light clients of a chain. + operationId: ClientStates responses: '200': description: A successful response. schema: type: object properties: - connection_paths: - type: array - items: - type: string - description: slice of all the connection paths associated with a client. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was generated - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - title: |- - QueryClientConnectionsResponse is the response type for the - Query/ClientConnections RPC method - default: - description: An unexpected error response - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: + client_states: type: array items: type: object properties: - type_url: + client_id: type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized - protocol buffer message. This string must contain at - least + protocol buffer message. This string must contain at + least - one "/" character. The last segment of the URL's path - must represent + one "/" character. The last segment of the URL's + path must represent - the fully qualified name of the type (as in + the fully qualified name of the type (as in - `path/google.protobuf.Duration`). The name should be in - a canonical form + `path/google.protobuf.Duration`). The name should be + in a canonical form - (e.g., leading "." is not accepted). + (e.g., leading "." is not accepted). - In practice, teams usually precompile into the binary - all types that they + In practice, teams usually precompile into the + binary all types that they - expect it to use in the context of Any. However, for - URLs which use the + expect it to use in the context of Any. However, for + URLs which use the - scheme `http`, `https`, or no scheme, one can optionally - set up a type + scheme `http`, `https`, or no scheme, one can + optionally set up a type - server that maps type URLs to message definitions as - follows: + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results + based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available + in the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty + scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the + above specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any + values in the form + + of utility functions or additional generated methods of + the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and + the unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will + yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the + regular + + representation of the deserialized, embedded message, + with an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a + custom JSON + + representation, that representation will be embedded + adding a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message + [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: >- + IdentifiedClientState defines a client state with an + additional client + + identifier field. + description: list of stored ClientStates of the chain. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + description: >- + QueryClientStatesResponse is the response type for the + Query/ClientStates RPC + + method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: * If no scheme is provided, `https` is assumed. @@ -3669,227 +3547,333 @@ paths: "value": "1.212s" } parameters: - - name: client_id - description: client identifier associated with a connection - in: path - required: true + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false type: string - tags: - - Query - /ibc/core/connection/v1/connections: - get: - summary: Connections queries all the IBC connections of a chain. - operationId: Connections - responses: - '200': - description: A successful response. - schema: - type: object - properties: - connections: - type: array - items: - type: object - properties: - id: - type: string - description: connection identifier. - client_id: - type: string - description: client associated with this connection. - versions: - type: array - items: - type: object - properties: - identifier: - type: string - title: unique version identifier - features: - type: array - items: - type: string - title: >- - list of features compatible with the specified - identifier - description: >- - Version defines the versioning scheme used to - negotiate the IBC verison in - - the connection handshake. - title: >- - IBC version which can be utilised to determine encodings - or protocols for - - channels or packets utilising this connection - state: - description: current state of the connection end. - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - default: STATE_UNINITIALIZED_UNSPECIFIED - counterparty: - description: counterparty chain associated with this connection. - type: object - properties: - client_id: - type: string - description: >- - identifies the client on the counterparty chain - associated with a given - - connection. - connection_id: - type: string - description: >- - identifies the connection end on the counterparty - chain associated with a - - given connection. - prefix: - description: commitment merkle prefix of the counterparty chain. - type: object - properties: - key_prefix: - type: string - format: byte - title: >- - MerklePrefix is merkle path prefixed to the key. + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. - The constructed key from the Path and the key will - be append(Path.KeyPath, + It is less efficient than using key. Only one of offset or key + should - append(Path.KeyPrefix, key...)) - delay_period: - type: string - format: uint64 - description: delay period associated with this connection. - description: >- - IdentifiedConnection defines a connection with additional - connection + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. - identifier field. - description: list of stored connections of the chain. - pagination: - title: pagination response - type: object - properties: - next_key: - type: string - format: byte - title: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the + a count of the total number of items available for pagination in + UIs. - corresponding request message has used PageRequest. + count_total is only respected when offset is used. It is ignored + when key - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + '/ibc/core/client/v1/client_states/{client_id}': + get: + summary: ClientState queries an IBC light client. + operationId: ClientState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + client_state: type: object properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: + type_url: type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping + description: >- + A URL/resource name that uniquely identifies the type of + the serialized - RevisionNumber the same. However some consensus algorithms may - choose to + protocol buffer message. This string must contain at least - reset the height in certain conditions e.g. hard forks, - state-machine + one "/" character. The last segment of the URL's path must + represent - breaking changes In these cases, the RevisionNumber is - incremented so that + the fully qualified name of the type (as in - height continues to be monitonically increasing even as the - RevisionHeight + `path/google.protobuf.Duration`). The name should be in a + canonical form - gets reset - description: >- - QueryConnectionsResponse is the response type for the - Query/Connections RPC + (e.g., leading "." is not accepted). - method. - default: - description: An unexpected error response - schema: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - protocol buffer message. This string must contain at - least + In practice, teams usually precompile into the binary all + types that they - one "/" character. The last segment of the URL's path - must represent + expect it to use in the context of Any. However, for URLs + which use the - the fully qualified name of the type (as in + scheme `http`, `https`, or no scheme, one can optionally + set up a type - `path/google.protobuf.Duration`). The name should be in - a canonical form + server that maps type URLs to message definitions as + follows: - (e.g., leading "." is not accepted). + * If no scheme is provided, `https` is assumed. - In practice, teams usually precompile into the binary - all types that they + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - expect it to use in the context of Any. However, for - URLs which use the + Note: this functionality is not currently available in the + official - scheme `http`, `https`, or no scheme, one can optionally - set up a type + protobuf release, and it is not used for type URLs + beginning with - server that maps type URLs to message definitions as - follows: + type.googleapis.com. - * If no scheme is provided, `https` is assumed. + Schemes other than `http`, `https` (or the empty scheme) + might be - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state associated with the request identifier + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + description: >- + QueryClientStateResponse is the response type for the + Query/ClientState RPC + + method. Besides the client state, it includes a proof and the + height from + + which the proof was retrieved. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. * Applications are allowed to cache lookup results based on the URL, or have them precompiled into a binary to avoid any @@ -4025,199 +4009,30 @@ paths: "value": "1.212s" } parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false + - name: client_id + description: client state unique identifier + in: path + required: true type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. + tags: + - Query + '/ibc/core/client/v1/client_status/{client_id}': + get: + summary: Status queries the status of an IBC client. + operationId: ClientStatus + responses: + '200': + description: A successful response. + schema: + type: object + properties: + status: + type: string + description: >- + QueryClientStatusResponse is the response type for the + Query/ClientStatus RPC - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - format: boolean - tags: - - Query - '/ibc/core/connection/v1/connections/{connection_id}': - get: - summary: Connection queries an IBC connection end. - operationId: Connection - responses: - '200': - description: A successful response. - schema: - type: object - properties: - connection: - title: connection associated with the request identifier - type: object - properties: - client_id: - type: string - description: client associated with this connection. - versions: - type: array - items: - type: object - properties: - identifier: - type: string - title: unique version identifier - features: - type: array - items: - type: string - title: >- - list of features compatible with the specified - identifier - description: >- - Version defines the versioning scheme used to negotiate - the IBC verison in - - the connection handshake. - description: >- - IBC version which can be utilised to determine encodings - or protocols for - - channels or packets utilising this connection. - state: - description: current state of the connection end. - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - default: STATE_UNINITIALIZED_UNSPECIFIED - counterparty: - description: counterparty chain associated with this connection. - type: object - properties: - client_id: - type: string - description: >- - identifies the client on the counterparty chain - associated with a given - - connection. - connection_id: - type: string - description: >- - identifies the connection end on the counterparty - chain associated with a - - given connection. - prefix: - description: commitment merkle prefix of the counterparty chain. - type: object - properties: - key_prefix: - type: string - format: byte - title: >- - MerklePrefix is merkle path prefixed to the key. - - The constructed key from the Path and the key will be - append(Path.KeyPath, - - append(Path.KeyPrefix, key...)) - delay_period: - type: string - format: uint64 - description: >- - delay period that must pass before a consensus state can - be used for - - packet-verification NOTE: delay period logic is only - implemented by some - - clients. - description: >- - ConnectionEnd defines a stateful object on a chain connected - to another - - separate one. - - NOTE: there must only be 2 defined ConnectionEnds to establish - - a connection between two chains. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping - - RevisionNumber the same. However some consensus algorithms may - choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset - description: >- - QueryConnectionResponse is the response type for the - Query/Connection RPC - - method. Besides the connection end, it includes a proof and the - height from - - which the proof was retrieved. + method. It returns the current status of the IBC client. default: description: An unexpected error response schema: @@ -4408,249 +4223,274 @@ paths: "value": "1.212s" } parameters: - - name: connection_id - description: connection unique identifier + - name: client_id + description: client unique identifier in: path required: true type: string tags: - Query - '/ibc/core/connection/v1/connections/{connection_id}/client_state': + '/ibc/core/client/v1/consensus_states/{client_id}': get: summary: |- - ConnectionClientState queries the client state associated with the - connection. - operationId: ConnectionClientState + ConsensusStates queries all the consensus state associated with a given + client. + operationId: ConsensusStates responses: '200': description: A successful response. schema: type: object properties: - identified_client_state: - title: client state associated with the channel - type: object - properties: - client_id: - type: string - title: client identifier - client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type - of the serialized - - protocol buffer message. This string must contain at - least + consensus_states: + type: array + items: + type: object + properties: + height: + title: consensus state height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each + height while keeping - one "/" character. The last segment of the URL's path - must represent + RevisionNumber the same. However some consensus + algorithms may choose to - the fully qualified name of the type (as in + reset the height in certain conditions e.g. hard forks, + state-machine - `path/google.protobuf.Duration`). The name should be - in a canonical form + breaking changes In these cases, the RevisionNumber is + incremented so that - (e.g., leading "." is not accepted). + height continues to be monitonically increasing even as + the RevisionHeight + gets reset + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized - In practice, teams usually precompile into the binary - all types that they + protocol buffer message. This string must contain at + least - expect it to use in the context of Any. However, for - URLs which use the + one "/" character. The last segment of the URL's + path must represent - scheme `http`, `https`, or no scheme, one can - optionally set up a type + the fully qualified name of the type (as in - server that maps type URLs to message definitions as - follows: + `path/google.protobuf.Duration`). The name should be + in a canonical form + (e.g., leading "." is not accepted). - * If no scheme is provided, `https` is assumed. - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results - based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) + In practice, teams usually precompile into the + binary all types that they - Note: this functionality is not currently available in - the official + expect it to use in the context of Any. However, for + URLs which use the - protobuf release, and it is not used for type URLs - beginning with + scheme `http`, `https`, or no scheme, one can + optionally set up a type - type.googleapis.com. + server that maps type URLs to message definitions as + follows: - Schemes other than `http`, `https` (or the empty - scheme) might be + * If no scheme is provided, `https` is assumed. - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the - above specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results + based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) - URL that describes the type of the serialized message. + Note: this functionality is not currently available + in the official + protobuf release, and it is not used for type URLs + beginning with - Protobuf library provides support to pack/unpack Any - values in the form + type.googleapis.com. - of utility functions or additional generated methods of - the Any type. + Schemes other than `http`, `https` (or the empty + scheme) might be - Example 1: Pack and unpack a message in C++. + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the + above specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any + values in the form + + of utility functions or additional generated methods of + the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); ... - } + if (any.UnpackTo(&foo)) { + ... + } - Example 2: Pack and unpack a message in Java. + Example 2: Pack and unpack a message in Java. - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - Example 3: Pack and unpack a message in Python. + Example 3: Pack and unpack a message in Python. - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) + foo = Foo(...) + any = Any() + any.Pack(foo) ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - Example 4: Pack and unpack a message in Go + Example 4: Pack and unpack a message in Go - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) ... - } + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } - The pack methods provided by protobuf library will by - default use + The pack methods provided by protobuf library will by + default use - 'type.googleapis.com/full.type.name' as the type URL and - the unpack + 'type.googleapis.com/full.type.name' as the type URL and + the unpack - methods only use the fully qualified type name after the - last '/' + methods only use the fully qualified type name after the + last '/' - in the type URL, for example "foo.bar.com/x/y.z" will - yield type + in the type URL, for example "foo.bar.com/x/y.z" will + yield type - name "y.z". + name "y.z". - JSON + JSON - ==== + ==== - The JSON representation of an `Any` value uses the regular + The JSON representation of an `Any` value uses the + regular - representation of the deserialized, embedded message, with - an + representation of the deserialized, embedded message, + with an - additional field `@type` which contains the type URL. - Example: + additional field `@type` which contains the type URL. + Example: - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } - If the embedded message type is well-known and has a - custom JSON + If the embedded message type is well-known and has a + custom JSON - representation, that representation will be embedded - adding a field + representation, that representation will be embedded + adding a field - `value` which holds the custom JSON in addition to the - `@type` + `value` which holds the custom JSON in addition to the + `@type` - field. Example (for message [google.protobuf.Duration][]): + field. Example (for message + [google.protobuf.Duration][]): - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state - description: >- - IdentifiedClientState defines a client state with an - additional client + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state + description: >- + ConsensusStateWithHeight defines a consensus state with an + additional height - identifier field. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved + field. + title: consensus states associated with the identifier + pagination: + title: pagination response type: object properties: - revision_number: + next_key: type: string - format: uint64 - title: the revision that the client is currently on - revision_height: + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: type: string format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping + title: >- + total is total number of results available if + PageRequest.count_total - RevisionNumber the same. However some consensus algorithms may - choose to + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the - reset the height in certain conditions e.g. hard forks, - state-machine + corresponding request message has used PageRequest. - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as the - RevisionHeight - - gets reset + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } title: |- - QueryConnectionClientStateResponse is the response type for the - Query/ConnectionClientState RPC method + QueryConsensusStatesResponse is the response type for the + Query/ConsensusStates RPC method default: description: An unexpected error response schema: @@ -4841,19 +4681,68 @@ paths: "value": "1.212s" } parameters: - - name: connection_id - description: connection identifier + - name: client_id + description: client identifier in: path required: true type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean tags: - Query - '/ibc/core/connection/v1/connections/{connection_id}/consensus_state/revision/{revision_number}/height/{revision_height}': + '/ibc/core/client/v1/consensus_states/{client_id}/revision/{revision_number}/height/{revision_height}': get: - summary: |- - ConnectionConsensusState queries the consensus state associated with the - connection. - operationId: ConnectionConsensusState + summary: >- + ConsensusState queries a consensus state associated with a client state + at + + a given height. + operationId: ConsensusState responses: '200': description: A successful response. @@ -5031,10 +4920,9 @@ paths: "@type": "type.googleapis.com/google.protobuf.Duration", "value": "1.212s" } - title: consensus state associated with the channel - client_id: - type: string - title: client ID associated with the consensus state + title: >- + consensus state associated with the client identifier at the + given height proof: type: string format: byte @@ -5068,9 +4956,11 @@ paths: RevisionHeight gets reset - title: |- - QueryConnectionConsensusStateResponse is the response type for the - Query/ConnectionConsensusState RPC method + title: >- + QueryConsensusStateResponse is the response type for the + Query/ConsensusState + + RPC method default: description: An unexpected error response schema: @@ -5261,173 +5151,220 @@ paths: "value": "1.212s" } parameters: - - name: connection_id - description: connection identifier + - name: client_id + description: client identifier in: path required: true type: string - name: revision_number + description: consensus state revision number in: path required: true type: string format: uint64 - name: revision_height + description: consensus state revision height in: path required: true type: string format: uint64 + - name: latest_height + description: >- + latest_height overrrides the height field and queries the latest + stored + + ConsensusState. + in: query + required: false + type: boolean + format: boolean tags: - Query - /ibc/core/channel/v1/channels: + /ibc/core/client/v1/upgraded_client_states: get: - summary: Channels queries all the IBC channels of a chain. - operationId: Channels + summary: UpgradedClientState queries an Upgraded IBC light client. + operationId: UpgradedClientState responses: '200': description: A successful response. schema: type: object properties: - channels: - type: array - items: - type: object - properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - default: STATE_UNINITIALIZED_UNSPECIFIED - description: >- - State defines if a channel is in one of the following - states: - - CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: >- - - ORDER_NONE_UNSPECIFIED: zero-value for channel - ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other - end of the channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: >- - list of connection identifiers, in order, along which - packets sent on - - this channel will travel - version: - type: string - title: >- - opaque channel version, which is agreed upon during the - handshake - port_id: - type: string - title: port identifier - channel_id: - type: string - title: channel identifier - description: >- - IdentifiedChannel defines a channel with additional port and - channel - - identifier fields. - description: list of stored channels of the chain. - pagination: - title: pagination response + upgraded_client_state: type: object properties: - next_key: - type: string - format: byte - title: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently - total: + type_url: type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total + description: >- + A URL/resource name that uniquely identifies the type of + the serialized - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the + protocol buffer message. This string must contain at least - corresponding request message has used PageRequest. + one "/" character. The last segment of the URL's path must + represent - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping + the fully qualified name of the type (as in - RevisionNumber the same. However some consensus algorithms may - choose to + `path/google.protobuf.Duration`). The name should be in a + canonical form - reset the height in certain conditions e.g. hard forks, - state-machine + (e.g., leading "." is not accepted). - breaking changes In these cases, the RevisionNumber is - incremented so that - height continues to be monitonically increasing even as the - RevisionHeight + In practice, teams usually precompile into the binary all + types that they - gets reset - description: >- - QueryChannelsResponse is the response type for the Query/Channels - RPC method. + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state associated with the request identifier + description: |- + QueryUpgradedClientStateResponse is the response type for the + Query/UpgradedClientState RPC method. default: description: An unexpected error response schema: @@ -5617,181 +5554,193 @@ paths: "@type": "type.googleapis.com/google.protobuf.Duration", "value": "1.212s" } - parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - format: boolean tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}': + /ibc/core/client/v1/upgraded_consensus_states: get: - summary: Channel queries an IBC Channel. - operationId: Channel + summary: UpgradedConsensusState queries an Upgraded IBC consensus state. + operationId: UpgradedConsensusState responses: '200': description: A successful response. schema: type: object properties: - channel: - title: channel associated with the request identifiers + upgraded_consensus_state: type: object properties: - state: - title: current state of the channel end + type_url: type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - default: STATE_UNINITIALIZED_UNSPECIFIED description: >- - State defines if a channel is in one of the following - states: + A URL/resource name that uniquely identifies the type of + the serialized - CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + protocol buffer message. This string must contain at least - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: |- - - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other - end of the channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: >- - list of connection identifiers, in order, along which - packets sent on + one "/" character. The last segment of the URL's path must + represent - this channel will travel - version: - type: string - title: >- - opaque channel version, which is agreed upon during the - handshake - description: >- - Channel defines pipeline for exactly-once packet delivery - between specific + the fully qualified name of the type (as in - modules on separate blockchains, which has at least one end - capable of + `path/google.protobuf.Duration`). The name should be in a + canonical form - sending packets and one end capable of receiving packets. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: type: string - format: uint64 - title: the height within the given revision + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. description: >- - Normally the RevisionHeight is incremented at each height - while keeping + `Any` contains an arbitrary serialized protocol buffer message + along with a - RevisionNumber the same. However some consensus algorithms may - choose to + URL that describes the type of the serialized message. - reset the height in certain conditions e.g. hard forks, - state-machine - breaking changes In these cases, the RevisionNumber is - incremented so that + Protobuf library provides support to pack/unpack Any values in + the form - height continues to be monitonically increasing even as the - RevisionHeight + of utility functions or additional generated methods of the + Any type. - gets reset - description: >- - QueryChannelResponse is the response type for the Query/Channel - RPC method. - Besides the Channel end, it includes a proof and the height from - which the + Example 1: Pack and unpack a message in C++. - proof was retrieved. + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: Consensus state associated with the request identifier + description: |- + QueryUpgradedConsensusStateResponse is the response type for the + Query/UpgradedConsensusState RPC method. default: description: An unexpected error response schema: @@ -5981,230 +5930,34 @@ paths: "@type": "type.googleapis.com/google.protobuf.Duration", "value": "1.212s" } - parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/client_state': + '/ibc/core/connection/v1/client_connections/{client_id}': get: - summary: >- - ChannelClientState queries for the client state for the channel - associated - - with the provided channel identifiers. - operationId: ChannelClientState + summary: |- + ClientConnections queries the connection paths associated with a client + state. + operationId: ClientConnections responses: '200': description: A successful response. schema: type: object properties: - identified_client_state: - title: client state associated with the channel + connection_paths: + type: array + items: + type: string + description: slice of all the connection paths associated with a client. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was generated type: object properties: - client_id: - type: string - title: client identifier - client_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type - of the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's path - must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be - in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary - all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can - optionally set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results - based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in - the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty - scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the - above specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any - values in the form - - of utility functions or additional generated methods of - the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and - the unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will - yield type - - name "y.z". - - - - JSON - - ==== - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with - an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a - custom JSON - - representation, that representation will be embedded - adding a field - - `value` which holds the custom JSON in addition to the - `@type` - - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: client state - description: >- - IdentifiedClientState defines a client state with an - additional client - - identifier field. - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved - type: object - properties: - revision_number: + revision_number: type: string format: uint64 title: the revision that the client is currently on @@ -6230,8 +5983,8 @@ paths: gets reset title: |- - QueryChannelClientStateResponse is the Response type for the - Query/QueryChannelClientState RPC method + QueryClientConnectionsResponse is the response type for the + Query/ClientConnections RPC method default: description: An unexpected error response schema: @@ -6422,211 +6175,140 @@ paths: "value": "1.212s" } parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier + - name: client_id + description: client identifier associated with a connection in: path required: true type: string tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/consensus_state/revision/{revision_number}/height/{revision_height}': + /ibc/core/connection/v1/connections: get: - summary: |- - ChannelConsensusState queries for the consensus state for the channel - associated with the provided channel identifiers. - operationId: ChannelConsensusState + summary: Connections queries all the IBC connections of a chain. + operationId: Connections responses: '200': description: A successful response. schema: type: object properties: - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of - the serialized - - protocol buffer message. This string must contain at least - - one "/" character. The last segment of the URL's path must - represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be in a - canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all - types that they + connections: + type: array + items: + type: object + properties: + id: + type: string + description: connection identifier. + client_id: + type: string + description: client associated with this connection. + versions: + type: array + items: + type: object + properties: + identifier: + type: string + title: unique version identifier + features: + type: array + items: + type: string + title: >- + list of features compatible with the specified + identifier + description: >- + Version defines the versioning scheme used to + negotiate the IBC verison in - expect it to use in the context of Any. However, for URLs - which use the + the connection handshake. + title: >- + IBC version which can be utilised to determine encodings + or protocols for - scheme `http`, `https`, or no scheme, one can optionally - set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based - on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the - official + channels or packets utilising this connection + state: + description: current state of the connection end. + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + default: STATE_UNINITIALIZED_UNSPECIFIED + counterparty: + description: counterparty chain associated with this connection. + type: object + properties: + client_id: + type: string + description: >- + identifies the client on the counterparty chain + associated with a given - protobuf release, and it is not used for type URLs - beginning with + connection. + connection_id: + type: string + description: >- + identifies the connection end on the counterparty + chain associated with a - type.googleapis.com. + given connection. + prefix: + description: commitment merkle prefix of the counterparty chain. + type: object + properties: + key_prefix: + type: string + format: byte + title: >- + MerklePrefix is merkle path prefixed to the key. + The constructed key from the Path and the key will + be append(Path.KeyPath, - Schemes other than `http`, `https` (or the empty scheme) - might be + append(Path.KeyPrefix, key...)) + delay_period: + type: string + format: uint64 + description: delay period associated with this connection. + description: >- + IdentifiedConnection defines a connection with additional + connection - used with implementation specific semantics. - value: + identifier field. + description: list of stored connections of the chain. + pagination: + title: pagination response + type: object + properties: + next_key: type: string format: byte - description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message - along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any values in - the form - - of utility functions or additional generated methods of the - Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default - use - - 'type.googleapis.com/full.type.name' as the type URL and the - unpack - - methods only use the fully qualified type name after the last - '/' - - in the type URL, for example "foo.bar.com/x/y.z" will yield - type - - name "y.z". - - - - JSON - - ==== - - The JSON representation of an `Any` value uses the regular - - representation of the deserialized, embedded message, with an - - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom - JSON - - representation, that representation will be embedded adding a - field + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total - `value` which holds the custom JSON in addition to the `@type` + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the - field. Example (for message [google.protobuf.Duration][]): + corresponding request message has used PageRequest. - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state associated with the channel - client_id: - type: string - title: client ID associated with the consensus state - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height type: object properties: revision_number: @@ -6654,9 +6336,11 @@ paths: RevisionHeight gets reset - title: |- - QueryChannelClientStateResponse is the Response type for the - Query/QueryChannelClientState RPC method + description: >- + QueryConnectionsResponse is the response type for the + Query/Connections RPC + + method. default: description: An unexpected error response schema: @@ -6847,46 +6531,158 @@ paths: "value": "1.212s" } parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false type: string - - name: revision_number - description: revision number of the consensus state - in: path - required: true + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false type: string format: uint64 - - name: revision_height - description: revision height of the consensus state - in: path - required: true + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false type: string format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/next_sequence': + '/ibc/core/connection/v1/connections/{connection_id}': get: - summary: >- - NextSequenceReceive returns the next receive sequence for a given - channel. - operationId: NextSequenceReceive + summary: Connection queries an IBC connection end. + operationId: Connection responses: '200': description: A successful response. schema: type: object properties: - next_sequence_receive: - type: string - format: uint64 - title: next sequence receive number + connection: + title: connection associated with the request identifier + type: object + properties: + client_id: + type: string + description: client associated with this connection. + versions: + type: array + items: + type: object + properties: + identifier: + type: string + title: unique version identifier + features: + type: array + items: + type: string + title: >- + list of features compatible with the specified + identifier + description: >- + Version defines the versioning scheme used to negotiate + the IBC verison in + + the connection handshake. + description: >- + IBC version which can be utilised to determine encodings + or protocols for + + channels or packets utilising this connection. + state: + description: current state of the connection end. + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + default: STATE_UNINITIALIZED_UNSPECIFIED + counterparty: + description: counterparty chain associated with this connection. + type: object + properties: + client_id: + type: string + description: >- + identifies the client on the counterparty chain + associated with a given + + connection. + connection_id: + type: string + description: >- + identifies the connection end on the counterparty + chain associated with a + + given connection. + prefix: + description: commitment merkle prefix of the counterparty chain. + type: object + properties: + key_prefix: + type: string + format: byte + title: >- + MerklePrefix is merkle path prefixed to the key. + + The constructed key from the Path and the key will be + append(Path.KeyPath, + + append(Path.KeyPrefix, key...)) + delay_period: + type: string + format: uint64 + description: >- + delay period that must pass before a consensus state can + be used for + + packet-verification NOTE: delay period logic is only + implemented by some + + clients. + description: >- + ConnectionEnd defines a stateful object on a chain connected + to another + + separate one. + + NOTE: there must only be 2 defined ConnectionEnds to establish + + a connection between two chains. proof: type: string format: byte @@ -6920,9 +6716,14 @@ paths: RevisionHeight gets reset - title: |- - QuerySequenceResponse is the request type for the - Query/QueryNextSequenceReceiveResponse RPC method + description: >- + QueryConnectionResponse is the response type for the + Query/Connection RPC + + method. Besides the connection end, it includes a proof and the + height from + + which the proof was retrieved. default: description: An unexpected error response schema: @@ -7113,121 +6914,249 @@ paths: "value": "1.212s" } parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier + - name: connection_id + description: connection unique identifier in: path required: true type: string tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acknowledgements': + '/ibc/core/connection/v1/connections/{connection_id}/client_state': get: - summary: >- - PacketAcknowledgements returns all the packet acknowledgements - associated - - with a channel. - operationId: PacketAcknowledgements + summary: |- + ConnectionClientState queries the client state associated with the + connection. + operationId: ConnectionClientState responses: '200': description: A successful response. schema: type: object properties: - acknowledgements: - type: array - items: - type: object - properties: - port_id: - type: string - description: channel port identifier. - channel_id: - type: string - description: channel unique identifier. - sequence: - type: string - format: uint64 - description: packet sequence. - data: - type: string - format: byte - description: embedded data that represents packet state. - description: >- - PacketState defines the generic type necessary to retrieve - and store - - packet commitments, acknowledgements, and receipts. - - Caller is responsible for knowing the context necessary to - interpret this - - state as a commitment, acknowledgement, or a receipt. - pagination: - title: pagination response + identified_client_state: + title: client state associated with the channel type: object properties: - next_key: - type: string - format: byte - title: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently - total: + client_id: type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type + of the serialized - was set, its value is undefined otherwise - description: >- - PageResponse is to be embedded in gRPC response messages where - the + protocol buffer message. This string must contain at + least - corresponding request message has used PageRequest. + one "/" character. The last segment of the URL's path + must represent - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - height: - title: query block height - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping + the fully qualified name of the type (as in - RevisionNumber the same. However some consensus algorithms may - choose to + `path/google.protobuf.Duration`). The name should be + in a canonical form - reset the height in certain conditions e.g. hard forks, - state-machine + (e.g., leading "." is not accepted). - breaking changes In these cases, the RevisionNumber is - incremented so that - height continues to be monitonically increasing even as the + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can + optionally set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results + based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty + scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the + above specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any + values in the form + + of utility functions or additional generated methods of + the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and + the unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will + yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a + custom JSON + + representation, that representation will be embedded + adding a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: >- + IdentifiedClientState defines a client state with an + additional client + + identifier field. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the RevisionHeight gets reset title: |- - QueryPacketAcknowledgemetsResponse is the request type for the - Query/QueryPacketAcknowledgements RPC method + QueryConnectionClientStateResponse is the response type for the + Query/ConnectionClientState RPC method default: description: An unexpected error response schema: @@ -7418,88 +7347,200 @@ paths: "value": "1.212s" } parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier + - name: connection_id + description: connection identifier in: path required: true type: string - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. + tags: + - Query + '/ibc/core/connection/v1/connections/{connection_id}/consensus_state/revision/{revision_number}/height/{revision_height}': + get: + summary: |- + ConnectionConsensusState queries the consensus state associated with the + connection. + operationId: ConnectionConsensusState + responses: + '200': + description: A successful response. + schema: + type: object + properties: + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized - It is less efficient than using key. Only one of offset or key - should + protocol buffer message. This string must contain at least - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. + one "/" character. The last segment of the URL's path must + represent - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include + the fully qualified name of the type (as in - a count of the total number of items available for pagination in - UIs. + `path/google.protobuf.Duration`). The name should be in a + canonical form - count_total is only respected when offset is used. It is ignored - when key + (e.g., leading "." is not accepted). - is set. - in: query - required: false - type: boolean - format: boolean - - name: packet_commitment_sequences - description: list of packet sequences. - in: query - required: false - type: array - items: - type: string - format: uint64 - collectionFormat: multi - tags: - - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acks/{sequence}': - get: - summary: PacketAcknowledgement queries a stored packet acknowledgement hash. - operationId: PacketAcknowledgement - responses: - '200': - description: A successful response. - schema: - type: object - properties: - acknowledgement: + + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state associated with the channel + client_id: type: string - format: byte - title: packet associated with the request fields + title: client ID associated with the consensus state proof: type: string format: byte @@ -7533,13 +7574,9 @@ paths: RevisionHeight gets reset - title: >- - QueryPacketAcknowledgementResponse defines the client query - response for a - - packet which also includes a proof and the height from which the - - proof was retrieved + title: |- + QueryConnectionConsensusStateResponse is the response type for the + Query/ConnectionConsensusState RPC method default: description: An unexpected error response schema: @@ -7730,65 +7767,113 @@ paths: "value": "1.212s" } parameters: - - name: channel_id - description: channel unique identifier + - name: connection_id + description: connection identifier in: path required: true type: string - - name: port_id - description: port unique identifier + - name: revision_number in: path required: true type: string - - name: sequence - description: packet sequence + format: uint64 + - name: revision_height in: path required: true type: string format: uint64 tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments': + /ibc/core/channel/v1/channels: get: - summary: |- - PacketCommitments returns all the packet commitments hashes associated - with a channel. - operationId: PacketCommitments + summary: Channels queries all the IBC channels of a chain. + operationId: Channels responses: '200': description: A successful response. schema: type: object properties: - commitments: + channels: type: array items: type: object properties: - port_id: - type: string - description: channel port identifier. - channel_id: - type: string - description: channel unique identifier. - sequence: - type: string - format: uint64 - description: packet sequence. - data: + state: + title: current state of the channel end type: string - format: byte - description: embedded data that represents packet state. - description: >- - PacketState defines the generic type necessary to retrieve - and store - - packet commitments, acknowledgements, and receipts. + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: >- + State defines if a channel is in one of the following + states: - Caller is responsible for knowing the context necessary to - interpret this + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. - state as a commitment, acknowledgement, or a receipt. + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: >- + - ORDER_NONE_UNSPECIFIED: zero-value for channel + ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other + end of the channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: >- + list of connection identifiers, in order, along which + packets sent on + + this channel will travel + version: + type: string + title: >- + opaque channel version, which is agreed upon during the + handshake + port_id: + type: string + title: port identifier + channel_id: + type: string + title: channel identifier + description: >- + IdentifiedChannel defines a channel with additional port and + channel + + identifier fields. + description: list of stored channels of the chain. pagination: title: pagination response type: object @@ -7846,9 +7931,9 @@ paths: RevisionHeight gets reset - title: |- - QueryPacketCommitmentsResponse is the request type for the - Query/QueryPacketCommitments RPC method + description: >- + QueryChannelsResponse is the response type for the Query/Channels + RPC method. default: description: An unexpected error response schema: @@ -8039,16 +8124,6 @@ paths: "value": "1.212s" } parameters: - - name: channel_id - description: channel unique identifier - in: path - required: true - type: string - - name: port_id - description: port unique identifier - in: path - required: true - type: string - name: pagination.key description: |- key is a value returned in PageResponse.next_key to begin @@ -8098,28 +8173,96 @@ paths: format: boolean tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{packet_ack_sequences}/unreceived_acks': + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}': get: - summary: >- - UnreceivedAcks returns all the unreceived IBC acknowledgements - associated - - with a channel and sequences. - operationId: UnreceivedAcks + summary: Channel queries an IBC Channel. + operationId: Channel responses: '200': description: A successful response. schema: type: object properties: - sequences: - type: array - items: - type: string - format: uint64 - title: list of unreceived acknowledgement sequences - height: - title: query block height + channel: + title: channel associated with the request identifiers + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: >- + State defines if a channel is in one of the following + states: + + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: |- + - ORDER_NONE_UNSPECIFIED: zero-value for channel ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other + end of the channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: >- + list of connection identifiers, in order, along which + packets sent on + + this channel will travel + version: + type: string + title: >- + opaque channel version, which is agreed upon during the + handshake + description: >- + Channel defines pipeline for exactly-once packet delivery + between specific + + modules on separate blockchains, which has at least one end + capable of + + sending packets and one end capable of receiving packets. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved type: object properties: revision_number: @@ -8147,9 +8290,14 @@ paths: RevisionHeight gets reset - title: |- - QueryUnreceivedAcksResponse is the response type for the - Query/UnreceivedAcks RPC method + description: >- + QueryChannelResponse is the response type for the Query/Channel + RPC method. + + Besides the Channel end, it includes a proof and the height from + which the + + proof was retrieved. default: description: An unexpected error response schema: @@ -8350,72 +8498,248 @@ paths: in: path required: true type: string - - name: packet_ack_sequences - description: list of acknowledgement sequences - in: path - required: true - type: array - items: - type: string - format: uint64 - collectionFormat: csv - minItems: 1 tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{packet_commitment_sequences}/unreceived_packets': + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/client_state': get: summary: >- - UnreceivedPackets returns all the unreceived IBC packets associated with - a + ChannelClientState queries for the client state for the channel + associated - channel and sequences. - operationId: UnreceivedPackets + with the provided channel identifiers. + operationId: ChannelClientState responses: '200': description: A successful response. schema: type: object properties: - sequences: - type: array - items: - type: string - format: uint64 - title: list of unreceived packet sequences - height: - title: query block height + identified_client_state: + title: client state associated with the channel type: object properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: + client_id: type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping + title: client identifier + client_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type + of the serialized - RevisionNumber the same. However some consensus algorithms may - choose to + protocol buffer message. This string must contain at + least - reset the height in certain conditions e.g. hard forks, - state-machine + one "/" character. The last segment of the URL's path + must represent - breaking changes In these cases, the RevisionNumber is - incremented so that + the fully qualified name of the type (as in - height continues to be monitonically increasing even as the - RevisionHeight + `path/google.protobuf.Duration`). The name should be + in a canonical form - gets reset - title: |- - QueryUnreceivedPacketsResponse is the response type for the - Query/UnreceivedPacketCommitments RPC method - default: - description: An unexpected error response + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can + optionally set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results + based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty + scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the + above specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any + values in the form + + of utility functions or additional generated methods of + the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and + the unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will + yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a + custom JSON + + representation, that representation will be embedded + adding a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: client state + description: >- + IdentifiedClientState defines a client state with an + additional client + + identifier field. + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryChannelClientStateResponse is the Response type for the + Query/QueryChannelClientState RPC method + default: + description: An unexpected error response schema: type: object properties: @@ -8614,73 +8938,231 @@ paths: in: path required: true type: string - - name: packet_commitment_sequences - description: list of packet sequences - in: path - required: true - type: array - items: - type: string - format: uint64 - collectionFormat: csv - minItems: 1 tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{sequence}': + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/consensus_state/revision/{revision_number}/height/{revision_height}': get: - summary: PacketCommitment queries a stored packet commitment hash. - operationId: PacketCommitment + summary: |- + ChannelConsensusState queries for the consensus state for the channel + associated with the provided channel identifiers. + operationId: ChannelConsensusState responses: '200': description: A successful response. schema: type: object properties: - commitment: - type: string - format: byte - title: packet associated with the request fields - proof: - type: string - format: byte - title: merkle proof of existence - proof_height: - title: height at which the proof was retrieved + consensus_state: type: object properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: + type_url: type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping + description: >- + A URL/resource name that uniquely identifies the type of + the serialized - RevisionNumber the same. However some consensus algorithms may - choose to + protocol buffer message. This string must contain at least - reset the height in certain conditions e.g. hard forks, - state-machine + one "/" character. The last segment of the URL's path must + represent - breaking changes In these cases, the RevisionNumber is - incremented so that + the fully qualified name of the type (as in - height continues to be monitonically increasing even as the - RevisionHeight + `path/google.protobuf.Duration`). The name should be in a + canonical form - gets reset - title: >- - QueryPacketCommitmentResponse defines the client query response - for a packet + (e.g., leading "." is not accepted). - which also includes a proof and the height from which the proof - was - retrieved + In practice, teams usually precompile into the binary all + types that they + + expect it to use in the context of Any. However, for URLs + which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message + along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in + the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default + use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the last + '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding a + field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state associated with the channel + client_id: + type: string + title: client ID associated with the consensus state + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryChannelClientStateResponse is the Response type for the + Query/QueryChannelClientState RPC method default: description: An unexpected error response schema: @@ -8881,32 +9363,36 @@ paths: in: path required: true type: string - - name: sequence - description: packet sequence + - name: revision_number + description: revision number of the consensus state + in: path + required: true + type: string + format: uint64 + - name: revision_height + description: revision height of the consensus state in: path required: true type: string format: uint64 tags: - Query - '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_receipts/{sequence}': + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/next_sequence': get: summary: >- - PacketReceipt queries if a given packet sequence has been received on - the - - queried chain - operationId: PacketReceipt + NextSequenceReceive returns the next receive sequence for a given + channel. + operationId: NextSequenceReceive responses: '200': description: A successful response. schema: type: object properties: - received: - type: boolean - format: boolean - title: success flag for if receipt exists + next_sequence_receive: + type: string + format: uint64 + title: next sequence receive number proof: type: string format: byte @@ -8940,14 +9426,9 @@ paths: RevisionHeight gets reset - title: >- - QueryPacketReceiptResponse defines the client query response for a - packet - - receipt which also includes a proof, and the height from which the - proof was - - retrieved + title: |- + QuerySequenceResponse is the request type for the + Query/QueryNextSequenceReceiveResponse RPC method default: description: An unexpected error response schema: @@ -9148,106 +9629,51 @@ paths: in: path required: true type: string - - name: sequence - description: packet sequence - in: path - required: true - type: string - format: uint64 tags: - Query - '/ibc/core/channel/v1/connections/{connection}/channels': + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acknowledgements': get: - summary: |- - ConnectionChannels queries all the channels associated with a connection - end. - operationId: ConnectionChannels + summary: >- + PacketAcknowledgements returns all the packet acknowledgements + associated + + with a channel. + operationId: PacketAcknowledgements responses: '200': description: A successful response. schema: type: object properties: - channels: + acknowledgements: type: array items: type: object properties: - state: - title: current state of the channel end - type: string - enum: - - STATE_UNINITIALIZED_UNSPECIFIED - - STATE_INIT - - STATE_TRYOPEN - - STATE_OPEN - - STATE_CLOSED - default: STATE_UNINITIALIZED_UNSPECIFIED - description: >- - State defines if a channel is in one of the following - states: - - CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. - - - STATE_UNINITIALIZED_UNSPECIFIED: Default State - - STATE_INIT: A channel has just started the opening handshake. - - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. - - STATE_OPEN: A channel has completed the handshake. Open channels are - ready to send and receive packets. - - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive - packets. - ordering: - title: whether the channel is ordered or unordered - type: string - enum: - - ORDER_NONE_UNSPECIFIED - - ORDER_UNORDERED - - ORDER_ORDERED - default: ORDER_NONE_UNSPECIFIED - description: >- - - ORDER_NONE_UNSPECIFIED: zero-value for channel - ordering - - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in - which they were sent. - - ORDER_ORDERED: packets are delivered exactly in the order which they were sent - counterparty: - title: counterparty channel end - type: object - properties: - port_id: - type: string - description: >- - port on the counterparty chain which owns the other - end of the channel. - channel_id: - type: string - title: channel end on the counterparty chain - connection_hops: - type: array - items: - type: string - title: >- - list of connection identifiers, in order, along which - packets sent on - - this channel will travel - version: - type: string - title: >- - opaque channel version, which is agreed upon during the - handshake port_id: type: string - title: port identifier + description: channel port identifier. channel_id: type: string - title: channel identifier + description: channel unique identifier. + sequence: + type: string + format: uint64 + description: packet sequence. + data: + type: string + format: byte + description: embedded data that represents packet state. description: >- - IdentifiedChannel defines a channel with additional port and - channel + PacketState defines the generic type necessary to retrieve + and store - identifier fields. - description: list of channels associated with a connection. + packet commitments, acknowledgements, and receipts. + + Caller is responsible for knowing the context necessary to + interpret this + + state as a commitment, acknowledgement, or a receipt. pagination: title: pagination response type: object @@ -9306,8 +9732,8 @@ paths: gets reset title: |- - QueryConnectionChannelsResponse is the Response type for the - Query/QueryConnectionChannels RPC method + QueryPacketAcknowledgemetsResponse is the request type for the + Query/QueryPacketAcknowledgements RPC method default: description: An unexpected error response schema: @@ -9498,8 +9924,13 @@ paths: "value": "1.212s" } parameters: - - name: connection - description: connection unique identifier + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier in: path required: true type: string @@ -9550,615 +9981,3384 @@ paths: required: false type: boolean format: boolean + - name: packet_commitment_sequences + description: list of packet sequences. + in: query + required: false + type: array + items: + type: string + format: uint64 + collectionFormat: multi tags: - Query -definitions: - cosmos.base.query.v1beta1.PageRequest: - type: object - properties: - key: - type: string - format: byte - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - offset: - type: string - format: uint64 - description: |- - offset is a numeric offset that can be used when key is unavailable. - It is less efficient than using key. Only one of offset or key should - be set. - limit: - type: string - format: uint64 - description: >- - limit is the total number of results to be returned in the result - page. + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_acks/{sequence}': + get: + summary: PacketAcknowledgement queries a stored packet acknowledgement hash. + operationId: PacketAcknowledgement + responses: + '200': + description: A successful response. + schema: + type: object + properties: + acknowledgement: + type: string + format: byte + title: packet associated with the request fields + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping - If left empty it will default to a value to be set by each app. - count_total: - type: boolean - format: boolean - description: >- - count_total is set to true to indicate that the result set should - include + RevisionNumber the same. However some consensus algorithms may + choose to - a count of the total number of items available for pagination in UIs. + reset the height in certain conditions e.g. hard forks, + state-machine - count_total is only respected when offset is used. It is ignored when - key + breaking changes In these cases, the RevisionNumber is + incremented so that - is set. - description: |- - message SomeRequest { - Foo some_parameter = 1; - PageRequest pagination = 2; - } - title: |- - PageRequest is to be embedded in gRPC request messages for efficient - pagination. Ex: - cosmos.base.query.v1beta1.PageResponse: - type: object - properties: - next_key: - type: string - format: byte - title: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently - total: - type: string - format: uint64 - title: |- - total is total number of results available if PageRequest.count_total - was set, its value is undefined otherwise - description: |- - PageResponse is to be embedded in gRPC response messages where the - corresponding request message has used PageRequest. + height continues to be monitonically increasing even as the + RevisionHeight - message SomeResponse { - repeated Bar results = 1; - PageResponse page = 2; - } - google.protobuf.Any: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized + gets reset + title: >- + QueryPacketAcknowledgementResponse defines the client query + response for a - protocol buffer message. This string must contain at least + packet which also includes a proof and the height from which the - one "/" character. The last segment of the URL's path must represent + proof was retrieved + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized - the fully qualified name of the type (as in + protocol buffer message. This string must contain at + least - `path/google.protobuf.Duration`). The name should be in a canonical - form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the binary all types that - they - - expect it to use in the context of Any. However, for URLs which use - the - - scheme `http`, `https`, or no scheme, one can optionally set up a type - - server that maps type URLs to message definitions as follows: - - - * If no scheme is provided, `https` is assumed. + one "/" character. The last segment of the URL's path + must represent - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) + the fully qualified name of the type (as in - Note: this functionality is not currently available in the official + `path/google.protobuf.Duration`). The name should be in + a canonical form - protobuf release, and it is not used for type URLs beginning with + (e.g., leading "." is not accepted). - type.googleapis.com. + In practice, teams usually precompile into the binary + all types that they - Schemes other than `http`, `https` (or the empty scheme) might be + expect it to use in the context of Any. However, for + URLs which use the - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the above specified - type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along with - a + scheme `http`, `https`, or no scheme, one can optionally + set up a type - URL that describes the type of the serialized message. + server that maps type URLs to message definitions as + follows: - Protobuf library provides support to pack/unpack Any values in the form + * If no scheme is provided, `https` is assumed. - of utility functions or additional generated methods of the Any type. + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + Note: this functionality is not currently available in + the official - Example 1: Pack and unpack a message in C++. + protobuf release, and it is not used for type URLs + beginning with - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } + type.googleapis.com. - Example 2: Pack and unpack a message in Java. - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } + Schemes other than `http`, `https` (or the empty scheme) + might be - Example 3: Pack and unpack a message in Python. + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... + URL that describes the type of the serialized message. - Example 4: Pack and unpack a message in Go - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } + Protobuf library provides support to pack/unpack Any values + in the form - The pack methods provided by protobuf library will by default use + of utility functions or additional generated methods of the + Any type. - 'type.googleapis.com/full.type.name' as the type URL and the unpack - methods only use the fully qualified type name after the last '/' + Example 1: Pack and unpack a message in C++. - in the type URL, for example "foo.bar.com/x/y.z" will yield type + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - name "y.z". + Example 2: Pack and unpack a message in Java. + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + Example 3: Pack and unpack a message in Python. - JSON + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... - ==== + Example 4: Pack and unpack a message in Go - The JSON representation of an `Any` value uses the regular + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } - representation of the deserialized, embedded message, with an + The pack methods provided by protobuf library will by + default use - additional field `@type` which contains the type URL. Example: + 'type.googleapis.com/full.type.name' as the type URL and the + unpack - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + methods only use the fully qualified type name after the + last '/' - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } + in the type URL, for example "foo.bar.com/x/y.z" will yield + type - If the embedded message type is well-known and has a custom JSON + name "y.z". - representation, that representation will be embedded adding a field - `value` which holds the custom JSON in addition to the `@type` - field. Example (for message [google.protobuf.Duration][]): + JSON - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - grpc.gateway.runtime.Error: - type: object - properties: - error: - type: string - code: - type: integer - format: int32 - message: - type: string - details: - type: array - items: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the type of the - serialized + ==== - protocol buffer message. This string must contain at least + The JSON representation of an `Any` value uses the regular - one "/" character. The last segment of the URL's path must - represent + representation of the deserialized, embedded message, with + an - the fully qualified name of the type (as in + additional field `@type` which contains the type URL. + Example: - `path/google.protobuf.Duration`). The name should be in a - canonical form + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } - (e.g., leading "." is not accepted). + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + If the embedded message type is well-known and has a custom + JSON - In practice, teams usually precompile into the binary all types - that they + representation, that representation will be embedded adding + a field - expect it to use in the context of Any. However, for URLs which - use the + `value` which holds the custom JSON in addition to the + `@type` - scheme `http`, `https`, or no scheme, one can optionally set up - a type + field. Example (for message [google.protobuf.Duration][]): - server that maps type URLs to message definitions as follows: + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: sequence + description: packet sequence + in: path + required: true + type: string + format: uint64 + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments': + get: + summary: |- + PacketCommitments returns all the packet commitments hashes associated + with a channel. + operationId: PacketCommitments + responses: + '200': + description: A successful response. + schema: + type: object + properties: + commitments: + type: array + items: + type: object + properties: + port_id: + type: string + description: channel port identifier. + channel_id: + type: string + description: channel unique identifier. + sequence: + type: string + format: uint64 + description: packet sequence. + data: + type: string + format: byte + description: embedded data that represents packet state. + description: >- + PacketState defines the generic type necessary to retrieve + and store + + packet commitments, acknowledgements, and receipts. + + Caller is responsible for knowing the context necessary to + interpret this + + state as a commitment, acknowledgement, or a receipt. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryPacketCommitmentsResponse is the request type for the + Query/QueryPacketCommitments RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{packet_ack_sequences}/unreceived_acks': + get: + summary: >- + UnreceivedAcks returns all the unreceived IBC acknowledgements + associated + + with a channel and sequences. + operationId: UnreceivedAcks + responses: + '200': + description: A successful response. + schema: + type: object + properties: + sequences: + type: array + items: + type: string + format: uint64 + title: list of unreceived acknowledgement sequences + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryUnreceivedAcksResponse is the response type for the + Query/UnreceivedAcks RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: packet_ack_sequences + description: list of acknowledgement sequences + in: path + required: true + type: array + items: + type: string + format: uint64 + collectionFormat: csv + minItems: 1 + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{packet_commitment_sequences}/unreceived_packets': + get: + summary: >- + UnreceivedPackets returns all the unreceived IBC packets associated with + a + + channel and sequences. + operationId: UnreceivedPackets + responses: + '200': + description: A successful response. + schema: + type: object + properties: + sequences: + type: array + items: + type: string + format: uint64 + title: list of unreceived packet sequences + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryUnreceivedPacketsResponse is the response type for the + Query/UnreceivedPacketCommitments RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: packet_commitment_sequences + description: list of packet sequences + in: path + required: true + type: array + items: + type: string + format: uint64 + collectionFormat: csv + minItems: 1 + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_commitments/{sequence}': + get: + summary: PacketCommitment queries a stored packet commitment hash. + operationId: PacketCommitment + responses: + '200': + description: A successful response. + schema: + type: object + properties: + commitment: + type: string + format: byte + title: packet associated with the request fields + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + QueryPacketCommitmentResponse defines the client query response + for a packet + + which also includes a proof and the height from which the proof + was + + retrieved + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: sequence + description: packet sequence + in: path + required: true + type: string + format: uint64 + tags: + - Query + '/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/packet_receipts/{sequence}': + get: + summary: >- + PacketReceipt queries if a given packet sequence has been received on + the + + queried chain + operationId: PacketReceipt + responses: + '200': + description: A successful response. + schema: + type: object + properties: + received: + type: boolean + format: boolean + title: success flag for if receipt exists + proof: + type: string + format: byte + title: merkle proof of existence + proof_height: + title: height at which the proof was retrieved + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + QueryPacketReceiptResponse defines the client query response for a + packet + + receipt which also includes a proof, and the height from which the + proof was + + retrieved + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: channel unique identifier + in: path + required: true + type: string + - name: port_id + description: port unique identifier + in: path + required: true + type: string + - name: sequence + description: packet sequence + in: path + required: true + type: string + format: uint64 + tags: + - Query + '/ibc/core/channel/v1/connections/{connection}/channels': + get: + summary: |- + ConnectionChannels queries all the channels associated with a connection + end. + operationId: ConnectionChannels + responses: + '200': + description: A successful response. + schema: + type: object + properties: + channels: + type: array + items: + type: object + properties: + state: + title: current state of the channel end + type: string + enum: + - STATE_UNINITIALIZED_UNSPECIFIED + - STATE_INIT + - STATE_TRYOPEN + - STATE_OPEN + - STATE_CLOSED + default: STATE_UNINITIALIZED_UNSPECIFIED + description: >- + State defines if a channel is in one of the following + states: + + CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. + + - STATE_UNINITIALIZED_UNSPECIFIED: Default State + - STATE_INIT: A channel has just started the opening handshake. + - STATE_TRYOPEN: A channel has acknowledged the handshake step on the counterparty chain. + - STATE_OPEN: A channel has completed the handshake. Open channels are + ready to send and receive packets. + - STATE_CLOSED: A channel has been closed and can no longer be used to send or receive + packets. + ordering: + title: whether the channel is ordered or unordered + type: string + enum: + - ORDER_NONE_UNSPECIFIED + - ORDER_UNORDERED + - ORDER_ORDERED + default: ORDER_NONE_UNSPECIFIED + description: >- + - ORDER_NONE_UNSPECIFIED: zero-value for channel + ordering + - ORDER_UNORDERED: packets can be delivered in any order, which may differ from the order in + which they were sent. + - ORDER_ORDERED: packets are delivered exactly in the order which they were sent + counterparty: + title: counterparty channel end + type: object + properties: + port_id: + type: string + description: >- + port on the counterparty chain which owns the other + end of the channel. + channel_id: + type: string + title: channel end on the counterparty chain + connection_hops: + type: array + items: + type: string + title: >- + list of connection identifiers, in order, along which + packets sent on + + this channel will travel + version: + type: string + title: >- + opaque channel version, which is agreed upon during the + handshake + port_id: + type: string + title: port identifier + channel_id: + type: string + title: channel identifier + description: >- + IdentifiedChannel defines a channel with additional port and + channel + + identifier fields. + description: list of channels associated with a connection. + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + height: + title: query block height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: |- + QueryConnectionChannelsResponse is the Response type for the + Query/QueryConnectionChannels RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: connection + description: connection unique identifier + in: path + required: true + type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query +definitions: + cosmos.base.query.v1beta1.PageRequest: + type: object + properties: + key: + type: string + format: byte + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + offset: + type: string + format: uint64 + description: |- + offset is a numeric offset that can be used when key is unavailable. + It is less efficient than using key. Only one of offset or key should + be set. + limit: + type: string + format: uint64 + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + count_total: + type: boolean + format: boolean + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in UIs. + + count_total is only respected when offset is used. It is ignored when + key + + is set. + description: |- + message SomeRequest { + Foo some_parameter = 1; + PageRequest pagination = 2; + } + title: |- + PageRequest is to be embedded in gRPC request messages for efficient + pagination. Ex: + cosmos.base.query.v1beta1.PageResponse: + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: |- + total is total number of results available if PageRequest.count_total + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + google.protobuf.Any: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a canonical + form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types that + they + + expect it to use in the context of Any. However, for URLs which use + the + + scheme `http`, `https`, or no scheme, one can optionally set up a type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the official + + protobuf release, and it is not used for type URLs beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above specified + type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along with + a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the form + + of utility functions or additional generated methods of the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + grpc.gateway.runtime.Error: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of the + serialized + + protocol buffer message. This string must contain at least + + one "/" character. The last segment of the URL's path must + represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in a + canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary all types + that they + + expect it to use in the context of Any. However, for URLs which + use the + + scheme `http`, `https`, or no scheme, one can optionally set up + a type + + server that maps type URLs to message definitions as follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the + official + + protobuf release, and it is not used for type URLs beginning + with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) might + be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer message along + with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values in the + form + + of utility functions or additional generated methods of the Any + type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + + 'type.googleapis.com/full.type.name' as the type URL and the unpack + + methods only use the fully qualified type name after the last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with an + + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + + representation, that representation will be embedded adding a field + + `value` which holds the custom JSON in addition to the `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + ibc.applications.transfer.v1.DenomTrace: + type: object + properties: + path: + type: string + description: >- + path defines the chain of port/channel identifiers used for tracing + the + + source of the fungible token. + base_denom: + type: string + description: base denomination of the relayed fungible token. + description: >- + DenomTrace contains the base denomination for ICS20 fungible tokens and + the + + source tracing information path. + ibc.applications.transfer.v1.Params: + type: object + properties: + send_enabled: + type: boolean + format: boolean + description: >- + send_enabled enables or disables all cross-chain token transfers from + this + + chain. + receive_enabled: + type: boolean + format: boolean + description: >- + receive_enabled enables or disables all cross-chain token transfers to + this + + chain. + description: >- + Params defines the set of IBC transfer parameters. + + NOTE: To prevent a single token from being transferred, set the + + TransfersEnabled parameter to true and then set the bank module's + SendEnabled + + parameter for the denomination to false. + ibc.applications.transfer.v1.QueryDenomHashResponse: + type: object + properties: + hash: + type: string + description: hash (in hex format) of the denomination trace information. + description: |- + QueryDenomHashResponse is the response type for the Query/DenomHash RPC + method. + ibc.applications.transfer.v1.QueryDenomTraceResponse: + type: object + properties: + denom_trace: + type: object + properties: + path: + type: string + description: >- + path defines the chain of port/channel identifiers used for + tracing the + + source of the fungible token. + base_denom: + type: string + description: base denomination of the relayed fungible token. + description: >- + DenomTrace contains the base denomination for ICS20 fungible tokens + and the + + source tracing information path. + description: |- + QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC + method. + ibc.applications.transfer.v1.QueryDenomTracesResponse: + type: object + properties: + denom_traces: + type: array + items: + type: object + properties: + path: + type: string + description: >- + path defines the chain of port/channel identifiers used for + tracing the + + source of the fungible token. + base_denom: + type: string + description: base denomination of the relayed fungible token. + description: >- + DenomTrace contains the base denomination for ICS20 fungible tokens + and the + + source tracing information path. + description: denom_traces returns all denominations trace information. + pagination: + description: pagination defines the pagination in the response. + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + QueryConnectionsResponse is the response type for the Query/DenomTraces + RPC + + method. + ibc.applications.transfer.v1.QueryParamsResponse: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + send_enabled: + type: boolean + format: boolean + description: >- + send_enabled enables or disables all cross-chain token transfers + from this + + chain. + receive_enabled: + type: boolean + format: boolean + description: >- + receive_enabled enables or disables all cross-chain token + transfers to this + + chain. + description: QueryParamsResponse is the response type for the Query/Params RPC method. + ibc.applications.interchain_accounts.controller.v1.Params: + type: object + properties: + controller_enabled: + type: boolean + format: boolean + description: controller_enabled enables or disables the controller submodule. + description: |- + Params defines the set of on-chain interchain accounts parameters. + The following parameters may be used to disable the controller submodule. + ibc.applications.interchain_accounts.controller.v1.QueryParamsResponse: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + controller_enabled: + type: boolean + format: boolean + description: controller_enabled enables or disables the controller submodule. + description: QueryParamsResponse is the response type for the Query/Params RPC method. + ibc.applications.interchain_accounts.host.v1.Params: + type: object + properties: + host_enabled: + type: boolean + format: boolean + description: host_enabled enables or disables the host submodule. + allow_messages: + type: array + items: + type: string + description: >- + allow_messages defines a list of sdk message typeURLs allowed to be + executed on a host chain. + description: |- + Params defines the set of on-chain interchain accounts parameters. + The following parameters may be used to disable the host submodule. + ibc.applications.interchain_accounts.host.v1.QueryParamsResponse: + type: object + properties: + params: + description: params defines the parameters of the module. + type: object + properties: + host_enabled: + type: boolean + format: boolean + description: host_enabled enables or disables the host submodule. + allow_messages: + type: array + items: + type: string + description: >- + allow_messages defines a list of sdk message typeURLs allowed to + be executed on a host chain. + description: QueryParamsResponse is the response type for the Query/Params RPC method. + cosmos.base.v1beta1.Coin: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. + + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + ibc.applications.fee.v1.Fee: + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. + + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. + + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. + + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + title: the packet timeout fee + title: 'Fee defines the ICS29 receive, acknowledgement and timeout fees' + ibc.applications.fee.v1.FeeEnabledChannel: + type: object + properties: + port_id: + type: string + title: unique port identifier + channel_id: + type: string + title: unique channel identifier + title: >- + FeeEnabledChannel contains the PortID & ChannelID for a fee enabled + channel + ibc.applications.fee.v1.IdentifiedPacketFees: + type: object + properties: + packet_id: + title: >- + unique packet identifier comprised of the channel ID, port ID and + sequence + type: object + properties: + port_id: + type: string + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: + type: string + format: uint64 + title: packet sequence + packet_fees: + type: array + items: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees associated with + an IBC packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - * If no scheme is provided, `https` is assumed. + NOTE: The amount field is an Int which implements the + custom method - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - Note: this functionality is not currently available in the - official - protobuf release, and it is not used for type URLs beginning - with + NOTE: The amount field is an Int which implements the + custom method - type.googleapis.com. + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - Schemes other than `http`, `https` (or the empty scheme) might - be + NOTE: The amount field is an Int which implements the + custom method - used with implementation specific semantics. - value: + signatures required by gogoproto. + title: the packet timeout fee + refund_address: type: string - format: byte + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: optional list of relayers permitted to receive fees + title: >- + PacketFee contains ICS29 relayer fees, refund address and optional + list of permitted relayers + title: list of packet fees + title: >- + IdentifiedPacketFees contains a list of type PacketFee and associated + PacketId + ibc.applications.fee.v1.PacketFee: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees associated with an IBC + packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string description: >- - Must be a valid serialized protocol buffer of the above - specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer message along - with a - - URL that describes the type of the serialized message. - + Coin defines a token with a denomination and an amount. - Protobuf library provides support to pack/unpack Any values in the - form - - of utility functions or additional generated methods of the Any - type. - - - Example 1: Pack and unpack a message in C++. - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } + NOTE: The amount field is an Int which implements the custom + method - Example 2: Pack and unpack a message in Java. + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - Example 3: Pack and unpack a message in Python. + NOTE: The amount field is an Int which implements the custom + method - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - Example 4: Pack and unpack a message in Go - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } + NOTE: The amount field is an Int which implements the custom + method - The pack methods provided by protobuf library will by default use + signatures required by gogoproto. + title: the packet timeout fee + refund_address: + type: string + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: optional list of relayers permitted to receive fees + title: >- + PacketFee contains ICS29 relayer fees, refund address and optional list of + permitted relayers + ibc.applications.fee.v1.QueryCounterpartyAddressResponse: + type: object + properties: + counterparty_address: + type: string + title: the counterparty address used to compensate forward relaying + title: >- + QueryCounterpartyAddressResponse defines the response type for the + CounterpartyAddress rpc + ibc.applications.fee.v1.QueryFeeEnabledChannelResponse: + type: object + properties: + fee_enabled: + type: boolean + format: boolean + title: boolean flag representing the fee enabled channel status + title: >- + QueryFeeEnabledChannelResponse defines the response type for the + FeeEnabledChannel rpc + ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse: + type: object + properties: + fee_enabled_channels: + type: array + items: + type: object + properties: + port_id: + type: string + title: unique port identifier + channel_id: + type: string + title: unique channel identifier + title: >- + FeeEnabledChannel contains the PortID & ChannelID for a fee enabled + channel + title: list of fee enabled channels + title: >- + QueryFeeEnabledChannelsResponse defines the response type for the + FeeEnabledChannels rpc + ibc.applications.fee.v1.QueryIncentivizedPacketResponse: + type: object + properties: + incentivized_packet: + title: the identified fees for the incentivized packet + type: object + properties: + packet_id: + title: >- + unique packet identifier comprised of the channel ID, port ID and + sequence + type: object + properties: + port_id: + type: string + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: + type: string + format: uint64 + title: packet sequence + packet_fees: + type: array + items: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees associated + with an IBC packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - 'type.googleapis.com/full.type.name' as the type URL and the unpack - methods only use the fully qualified type name after the last '/' + NOTE: The amount field is an Int which implements the + custom method - in the type URL, for example "foo.bar.com/x/y.z" will yield type + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - name "y.z". + NOTE: The amount field is an Int which implements the + custom method + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - JSON - ==== + NOTE: The amount field is an Int which implements the + custom method - The JSON representation of an `Any` value uses the regular + signatures required by gogoproto. + title: the packet timeout fee + refund_address: + type: string + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: optional list of relayers permitted to receive fees + title: >- + PacketFee contains ICS29 relayer fees, refund address and + optional list of permitted relayers + title: list of packet fees + title: >- + QueryIncentivizedPacketsResponse defines the response type for the + IncentivizedPacket rpc + ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse: + type: object + properties: + incentivized_packets: + type: array + items: + type: object + properties: + packet_id: + title: >- + unique packet identifier comprised of the channel ID, port ID + and sequence + type: object + properties: + port_id: + type: string + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: + type: string + format: uint64 + title: packet sequence + packet_fees: + type: array + items: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees associated + with an IBC packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - representation of the deserialized, embedded message, with an - additional field `@type` which contains the type URL. Example: + NOTE: The amount field is an Int which implements + the custom method - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - If the embedded message type is well-known and has a custom JSON + NOTE: The amount field is an Int which implements + the custom method - representation, that representation will be embedded adding a field + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - `value` which holds the custom JSON in addition to the `@type` - field. Example (for message [google.protobuf.Duration][]): + NOTE: The amount field is an Int which implements + the custom method - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - ibc.applications.transfer.v1.DenomTrace: + signatures required by gogoproto. + title: the packet timeout fee + refund_address: + type: string + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: optional list of relayers permitted to receive fees + title: >- + PacketFee contains ICS29 relayer fees, refund address and + optional list of permitted relayers + title: list of packet fees + title: >- + IdentifiedPacketFees contains a list of type PacketFee and + associated PacketId + title: Map of all incentivized_packets + title: >- + QueryIncentivizedPacketsResponse defines the response type for the + incentivized packets RPC + ibc.applications.fee.v1.QueryIncentivizedPacketsResponse: type: object properties: - path: - type: string - description: >- - path defines the chain of port/channel identifiers used for tracing - the + incentivized_packets: + type: array + items: + type: object + properties: + packet_id: + title: >- + unique packet identifier comprised of the channel ID, port ID + and sequence + type: object + properties: + port_id: + type: string + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: + type: string + format: uint64 + title: packet sequence + packet_fees: + type: array + items: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees associated + with an IBC packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - source of the fungible token. - base_denom: - type: string - description: base denomination of the relayed fungible token. - description: >- - DenomTrace contains the base denomination for ICS20 fungible tokens and - the - source tracing information path. - ibc.applications.transfer.v1.Params: - type: object - properties: - send_enabled: - type: boolean - format: boolean - description: >- - send_enabled enables or disables all cross-chain token transfers from - this + NOTE: The amount field is an Int which implements + the custom method - chain. - receive_enabled: - type: boolean - format: boolean - description: >- - receive_enabled enables or disables all cross-chain token transfers to - this + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - chain. - description: >- - Params defines the set of IBC transfer parameters. - NOTE: To prevent a single token from being transferred, set the + NOTE: The amount field is an Int which implements + the custom method - TransfersEnabled parameter to true and then set the bank module's - SendEnabled + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an + amount. - parameter for the denomination to false. - ibc.applications.transfer.v1.QueryDenomHashResponse: - type: object - properties: - hash: - type: string - description: hash (in hex format) of the denomination trace information. - description: |- - QueryDenomHashResponse is the response type for the Query/DenomHash RPC - method. - ibc.applications.transfer.v1.QueryDenomTraceResponse: - type: object - properties: - denom_trace: - type: object - properties: - path: - type: string - description: >- - path defines the chain of port/channel identifiers used for - tracing the - source of the fungible token. - base_denom: - type: string - description: base denomination of the relayed fungible token. - description: >- - DenomTrace contains the base denomination for ICS20 fungible tokens - and the + NOTE: The amount field is an Int which implements + the custom method - source tracing information path. - description: |- - QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC - method. - ibc.applications.transfer.v1.QueryDenomTracesResponse: + signatures required by gogoproto. + title: the packet timeout fee + refund_address: + type: string + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: optional list of relayers permitted to receive fees + title: >- + PacketFee contains ICS29 relayer fees, refund address and + optional list of permitted relayers + title: list of packet fees + title: >- + IdentifiedPacketFees contains a list of type PacketFee and + associated PacketId + title: list of identified fees for incentivized packets + title: >- + QueryIncentivizedPacketsResponse defines the response type for the + IncentivizedPackets rpc + ibc.applications.fee.v1.QueryTotalAckFeesResponse: type: object properties: - denom_traces: + ack_fees: type: array items: type: object properties: - path: + denom: type: string - description: >- - path defines the chain of port/channel identifiers used for - tracing the - - source of the fungible token. - base_denom: + amount: type: string - description: base denomination of the relayed fungible token. - description: >- - DenomTrace contains the base denomination for ICS20 fungible tokens - and the - - source tracing information path. - description: denom_traces returns all denominations trace information. - pagination: - description: pagination defines the pagination in the response. - type: object - properties: - next_key: - type: string - format: byte - title: |- - next_key is the key to be passed to PageRequest.key to - query the next page most efficiently - total: - type: string - format: uint64 - title: >- - total is total number of results available if - PageRequest.count_total - - was set, its value is undefined otherwise - description: >- - QueryConnectionsResponse is the response type for the Query/DenomTraces - RPC + description: |- + Coin defines a token with a denomination and an amount. - method. - ibc.applications.transfer.v1.QueryParamsResponse: + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + title: the total packet acknowledgement fees + title: >- + QueryTotalAckFeesResponse defines the response type for the TotalAckFees + rpc + ibc.applications.fee.v1.QueryTotalRecvFeesResponse: type: object properties: - params: - description: params defines the parameters of the module. - type: object - properties: - send_enabled: - type: boolean - format: boolean - description: >- - send_enabled enables or disables all cross-chain token transfers - from this - - chain. - receive_enabled: - type: boolean - format: boolean - description: >- - receive_enabled enables or disables all cross-chain token - transfers to this + recv_fees: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. - chain. - description: QueryParamsResponse is the response type for the Query/Params RPC method. - ibc.applications.interchain_accounts.controller.v1.Params: - type: object - properties: - controller_enabled: - type: boolean - format: boolean - description: controller_enabled enables or disables the controller submodule. - description: |- - Params defines the set of on-chain interchain accounts parameters. - The following parameters may be used to disable the controller submodule. - ibc.applications.interchain_accounts.controller.v1.QueryParamsResponse: - type: object - properties: - params: - description: params defines the parameters of the module. - type: object - properties: - controller_enabled: - type: boolean - format: boolean - description: controller_enabled enables or disables the controller submodule. - description: QueryParamsResponse is the response type for the Query/Params RPC method. - ibc.applications.interchain_accounts.host.v1.Params: + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + title: the total packet receive fees + title: >- + QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees + rpc + ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse: type: object properties: - host_enabled: - type: boolean - format: boolean - description: host_enabled enables or disables the host submodule. - allow_messages: + timeout_fees: type: array items: - type: string - description: >- - allow_messages defines a list of sdk message typeURLs allowed to be - executed on a host chain. - description: |- - Params defines the set of on-chain interchain accounts parameters. - The following parameters may be used to disable the host submodule. - ibc.applications.interchain_accounts.host.v1.QueryParamsResponse: + type: object + properties: + denom: + type: string + amount: + type: string + description: |- + Coin defines a token with a denomination and an amount. + + NOTE: The amount field is an Int which implements the custom method + signatures required by gogoproto. + title: the total packet timeout fees + title: >- + QueryTotalTimeoutFeesResponse defines the response type for the + TotalTimeoutFees rpc + ibc.core.channel.v1.PacketId: type: object properties: - params: - description: params defines the parameters of the module. - type: object - properties: - host_enabled: - type: boolean - format: boolean - description: host_enabled enables or disables the host submodule. - allow_messages: - type: array - items: - type: string - description: >- - allow_messages defines a list of sdk message typeURLs allowed to - be executed on a host chain. - description: QueryParamsResponse is the response type for the Query/Params RPC method. + port_id: + type: string + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: + type: string + format: uint64 + title: packet sequence + title: |- + PacketId is an identifer for a unique Packet + Source chains refer to packets by source port/channel + Destination chains refer to packets by destination port/channel ibc.core.client.v1.ConsensusStateWithHeight: type: object properties: From 374875d0a04f43394307c128c5e4bb4cb81fa3c4 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 24 May 2022 21:37:53 +0200 Subject: [PATCH 125/275] add new team member to global code owners (#1404) --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2c6a4204e19..6eac5144e65 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,6 @@ # CODEOWNERS: https://help.github.com/articles/about-codeowners/ -* @colin-axner @AdityaSripal @crodriguezvega @seantking @charleenfei @damiannolan +* @colin-axner @AdityaSripal @crodriguezvega @seantking @charleenfei @damiannolan @chatton # Order is important; the last matching pattern takes the most # precedence. When someone opens a pull request that only From bd0adfb4e7f008ff81a29d22944e17704942c6ba Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 24 May 2022 21:47:34 +0200 Subject: [PATCH 126/275] add section for fee code owners (#1405) --- .github/CODEOWNERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6eac5144e65..26359b79718 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -30,3 +30,8 @@ /modules/apps/27-interchain-accounts/ @seantking @colin-axner @AdityaSripal @damiannolan /proto/applications/interchain_accounts/ @seantking @colin-axner @AdityaSripal @damiannolan + +# CODEOWNERS for fee module + +/modules/apps/29-fee/ @AdityaSripal @seantking @charleenfei @colin-axner @damiannolan +/proto/ibc/applications/fee/ @AdityaSripal @seantking @charleenfei @colin-axner @damiannolan From 1acb3cc8645422a98babee6c6667485a9cc87366 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 24 May 2022 21:55:33 +0200 Subject: [PATCH 127/275] fix path (#1406) --- .github/CODEOWNERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 26359b79718..bd59278e6a4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -14,22 +14,22 @@ # CODEOWNERS for the core IBC module /modules/core/ @colin-axner @fedekunze @AdityaSripal -/proto/core/ @colin-axner @fedekunze @AdityaSripal +/proto/ibc/core/ @colin-axner @fedekunze @AdityaSripal # CODEOWNERS for the light-clients /modules/light-clients/ @colin-axner @fedekunze @AdityaSripal -/proto/lightclients/ @colin-axner @fedekunze @AdityaSripal +/proto/ibc/lightclients/ @colin-axner @fedekunze @AdityaSripal # CODEOWNERS for ICS 20 /modules/apps/transfer/ @colin-axner @fedekunze @AdityaSripal -/proto/applications/transfer/ @colin-axner @fedekunze @AdityaSripal +/proto/ibc/applications/transfer/ @colin-axner @fedekunze @AdityaSripal # CODEOWNERS for interchain-accounts module /modules/apps/27-interchain-accounts/ @seantking @colin-axner @AdityaSripal @damiannolan -/proto/applications/interchain_accounts/ @seantking @colin-axner @AdityaSripal @damiannolan +/proto/ibc/applications/interchain_accounts/ @seantking @colin-axner @AdityaSripal @damiannolan # CODEOWNERS for fee module From 25767f6bdb5bab2c2a116b41d92d753c93e18121 Mon Sep 17 00:00:00 2001 From: HaeSung Date: Thu, 26 May 2022 04:38:32 +0900 Subject: [PATCH 128/275] fix: ica controller middleware error typo (#1419) Co-authored-by: Carlos Rodriguez --- .../apps/27-interchain-accounts/controller/ibc_middleware.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 9bf874fa8eb..b0b6bd6767c 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -173,13 +173,12 @@ func (im IBCMiddleware) OnTimeoutPacket( } // SendPacket implements the ICS4 Wrapper interface -// The ICA controller module builds the outgoing ICA packet and calls the core IBC SendPacket func (im IBCMiddleware) SendPacket( ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, ) error { - panic("SendPacket not supported for ICA-auth module. Please use SendTx") + panic("SendPacket not supported for ICA controller module. Please use SendTx") } // WriteAcknowledgement implements the ICS4 Wrapper interface From f12f841874b57376eafe30aa8a25c0dbd51d386b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 29 May 2022 13:53:47 +0200 Subject: [PATCH 129/275] build(deps): bump github.com/spf13/viper from 1.11.0 to 1.12.0 (#1448) Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.11.0 to 1.12.0. - [Release notes](https://github.com/spf13/viper/releases) - [Commits](https://github.com/spf13/viper/compare/v1.11.0...v1.12.0) --- updated-dependencies: - dependency-name: github.com/spf13/viper dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 20 +++++++++---------- go.sum | 62 +++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index e595ea97f26..b2f2e409401 100644 --- a/go.mod +++ b/go.mod @@ -16,11 +16,11 @@ require ( github.com/regen-network/cosmos-proto v0.3.1 github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.4.0 - github.com/spf13/viper v1.11.0 + github.com/spf13/viper v1.12.0 github.com/stretchr/testify v1.7.1 github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 - google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac + google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd google.golang.org/grpc v1.46.2 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 @@ -52,7 +52,7 @@ require ( github.com/dustin/go-humanize v1.0.0 // indirect github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/gin-gonic/gin v1.7.0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.0 // indirect @@ -85,10 +85,10 @@ require ( github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/pelletier/go-toml v1.9.4 // indirect - github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -103,7 +103,7 @@ require ( github.com/spf13/afero v1.8.2 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/subosito/gotenv v1.2.0 // indirect + github.com/subosito/gotenv v1.3.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/btcd v0.1.1 // indirect @@ -112,11 +112,11 @@ require ( github.com/zondax/hid v0.9.0 // indirect go.etcd.io/bbolt v1.3.6 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect - golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect gopkg.in/ini.v1 v1.66.4 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.0 // indirect nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/go.sum b/go.sum index 0b1381b5098..6d985a7ab23 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,8 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= @@ -328,8 +330,9 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3 github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -440,8 +443,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= @@ -477,6 +481,7 @@ github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pf github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= @@ -696,8 +701,9 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -793,10 +799,11 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.0-beta.8 h1:dy81yyLYJDwMTifq24Oi/IslOslRrDSb3jwDggjz3Z0= -github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= @@ -826,6 +833,7 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -889,7 +897,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= -github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= +github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= @@ -940,8 +948,8 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= -github.com/spf13/viper v1.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44= -github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk= +github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= @@ -962,8 +970,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= +github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= @@ -1024,14 +1033,15 @@ go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= +go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= -go.etcd.io/etcd/client/v2 v2.305.2/go.mod h1:2D7ZejHVMIfog1221iLSYlQRzrtECw3kz4I4VAQm3qI= +go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1196,8 +1206,10 @@ golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1229,6 +1241,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1334,8 +1347,10 @@ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -1428,8 +1443,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1471,6 +1486,9 @@ google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQ google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1558,8 +1576,14 @@ google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2 google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac h1:qSNTkEN+L2mvWcLgJOR+8bdHX9rN/IdU3A1Ghpfb1Rg= google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1597,6 +1621,7 @@ google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -1649,8 +1674,9 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 8062d014956682b153f82e247d943310f5ff62a9 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 30 May 2022 11:46:26 +0200 Subject: [PATCH 130/275] add actual parameter example to denom-trace and denom-hash CLI queries (#1442) --- modules/apps/transfer/client/cli/query.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/client/cli/query.go b/modules/apps/transfer/client/cli/query.go index 5eb1a1a0c9b..2a6e3161a93 100644 --- a/modules/apps/transfer/client/cli/query.go +++ b/modules/apps/transfer/client/cli/query.go @@ -17,7 +17,7 @@ func GetCmdQueryDenomTrace() *cobra.Command { Use: "denom-trace [hash/denom]", Short: "Query the denom trace info from a given trace hash or ibc denom", Long: "Query the denom trace info from a given trace hash or ibc denom", - Example: fmt.Sprintf("%s query ibc-transfer denom-trace [hash/denom]", version.AppName), + Example: fmt.Sprintf("%s query ibc-transfer denom-trace 27A6394C3F9FF9C9DCF5DFFADF9BB5FE9A37C7E92B006199894CF1824DF9AC7C", version.AppName), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) @@ -142,7 +142,7 @@ func GetCmdQueryDenomHash() *cobra.Command { Use: "denom-hash [trace]", Short: "Query the denom hash info from a given denom trace", Long: "Query the denom hash info from a given denom trace", - Example: fmt.Sprintf("%s query ibc-transfer denom-hash [denom_trace]", version.AppName), + Example: fmt.Sprintf("%s query ibc-transfer denom-hash transfer/channel-0/uatom", version.AppName), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) From 373e1e68fa494bf6c57566e6b22c225cf1d4849e Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 30 May 2022 12:28:52 +0200 Subject: [PATCH 131/275] refactor of rest urls (#1431) --- docs/client/swagger-ui/swagger.yaml | 876 +++++++++++----------- proto/ibc/applications/fee/v1/query.proto | 22 +- 2 files changed, 451 insertions(+), 447 deletions(-) diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml index 7e83bdcd814..3175828f119 100644 --- a/docs/client/swagger-ui/swagger.yaml +++ b/docs/client/swagger-ui/swagger.yaml @@ -399,24 +399,25 @@ paths: format: byte tags: - Query - '/ibc/apps/fee/v1/counterparty_address/{relayer_address}/channel/{channel_id}': + '/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled': get: summary: >- - CounterpartyAddress returns the registered counterparty address for - forward relaying - operationId: CounterpartyAddress + FeeEnabledChannel returns true if the provided port and channel + identifiers belong to a fee enabled channel + operationId: FeeEnabledChannel responses: '200': description: A successful response. schema: type: object properties: - counterparty_address: - type: string - title: the counterparty address used to compensate forward relaying + fee_enabled: + type: boolean + format: boolean + title: boolean flag representing the fee enabled channel status title: >- - QueryCounterpartyAddressResponse defines the response type for the - CounterpartyAddress rpc + QueryFeeEnabledChannelResponse defines the response type for the + FeeEnabledChannel rpc default: description: An unexpected error response schema: @@ -607,46 +608,138 @@ paths: "value": "1.212s" } parameters: - - name: relayer_address - description: the relayer address to which the counterparty is registered + - name: channel_id + description: unique channel identifier in: path required: true type: string - - name: channel_id - description: unique channel identifier + - name: port_id + description: unique port identifier in: path required: true type: string tags: - Query - /ibc/apps/fee/v1/fee_enabled: + '/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/incentivized_packets': get: - summary: FeeEnabledChannels returns a list of all fee enabled channels - operationId: FeeEnabledChannels + summary: Gets all incentivized packets for a specific channel + operationId: IncentivizedPacketsForChannel responses: '200': description: A successful response. schema: type: object properties: - fee_enabled_channels: + incentivized_packets: type: array items: type: object properties: - port_id: - type: string - title: unique port identifier - channel_id: - type: string - title: unique channel identifier + packet_id: + title: >- + unique packet identifier comprised of the channel ID, + port ID and sequence + type: object + properties: + port_id: + type: string + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: + type: string + format: uint64 + title: packet sequence + packet_fees: + type: array + items: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees + associated with an IBC packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet timeout fee + refund_address: + type: string + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: >- + optional list of relayers permitted to receive + fees + title: >- + PacketFee contains ICS29 relayer fees, refund address + and optional list of permitted relayers + title: list of packet fees title: >- - FeeEnabledChannel contains the PortID & ChannelID for a fee - enabled channel - title: list of fee enabled channels + IdentifiedPacketFees contains a list of type PacketFee and + associated PacketId + title: Map of all incentivized_packets title: >- - QueryFeeEnabledChannelsResponse defines the response type for the - FeeEnabledChannels rpc + QueryIncentivizedPacketsResponse defines the response type for the + incentivized packets RPC default: description: An unexpected error response schema: @@ -837,6 +930,14 @@ paths: "value": "1.212s" } parameters: + - name: channel_id + in: path + required: true + type: string + - name: port_id + in: path + required: true + type: string - name: pagination.key description: |- key is a value returned in PageResponse.next_key to begin @@ -885,32 +986,31 @@ paths: type: boolean format: boolean - name: query_height - description: block height at which to query. + description: Height to query at. in: query required: false type: string format: uint64 tags: - Query - '/ibc/apps/fee/v1/fee_enabled/port/{port_id}/channel/{channel_id}': + '/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address': get: summary: >- - FeeEnabledChannel returns true if the provided port and channel - identifiers belong to a fee enabled channel - operationId: FeeEnabledChannel + CounterpartyAddress returns the registered counterparty address for + forward relaying + operationId: CounterpartyAddress responses: '200': description: A successful response. schema: type: object properties: - fee_enabled: - type: boolean - format: boolean - title: boolean flag representing the fee enabled channel status + counterparty_address: + type: string + title: the counterparty address used to compensate forward relaying title: >- - QueryFeeEnabledChannelResponse defines the response type for the - FeeEnabledChannel rpc + QueryCounterpartyAddressResponse defines the response type for the + CounterpartyAddress rpc default: description: An unexpected error response schema: @@ -1101,19 +1201,19 @@ paths: "value": "1.212s" } parameters: - - name: port_id - description: unique port identifier + - name: channel_id + description: unique channel identifier in: path required: true type: string - - name: channel_id - description: unique channel identifier + - name: relayer_address + description: the relayer address to which the counterparty is registered in: path required: true type: string tags: - Query - '/ibc/apps/fee/v1/incentivized_packet/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}': + '/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/incentivized_packet': get: summary: >- IncentivizedPacket returns all packet fees for a packet given its @@ -1126,7 +1226,6 @@ paths: type: object properties: incentivized_packet: - title: the identified fees for the incentivized packet type: object properties: packet_id: @@ -1225,6 +1324,9 @@ paths: PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers title: list of packet fees + title: >- + IdentifiedPacketFees contains a list of type PacketFee and + associated PacketId title: >- QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPacket rpc @@ -1418,13 +1520,13 @@ paths: "value": "1.212s" } parameters: - - name: packet_id.port_id - description: channel port identifier + - name: packet_id.channel_id + description: channel unique identifier in: path required: true type: string - - name: packet_id.channel_id - description: channel unique identifier + - name: packet_id.port_id + description: channel port identifier in: path required: true type: string @@ -1442,128 +1544,39 @@ paths: format: uint64 tags: - Query - /ibc/apps/fee/v1/incentivized_packets: + '/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_ack_fees': get: summary: >- - IncentivizedPackets returns all incentivized packets and their - associated fees - operationId: IncentivizedPackets + TotalAckFees returns the total acknowledgement fees for a packet given + its identifier + operationId: TotalAckFees responses: '200': description: A successful response. schema: type: object properties: - incentivized_packets: + ack_fees: type: array items: type: object properties: - packet_id: - title: >- - unique packet identifier comprised of the channel ID, - port ID and sequence - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - packet_fees: - type: array - items: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees - associated with an IBC packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - NOTE: The amount field is an Int which - implements the custom method + NOTE: The amount field is an Int which implements the custom + method - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: >- - optional list of relayers permitted to receive - fees - title: >- - PacketFee contains ICS29 relayer fees, refund address - and optional list of permitted relayers - title: list of packet fees - title: >- - IdentifiedPacketFees contains a list of type PacketFee and - associated PacketId - title: list of identified fees for incentivized packets + signatures required by gogoproto. + title: the total packet acknowledgement fees title: >- - QueryIncentivizedPacketsResponse defines the response type for the - IncentivizedPackets rpc + QueryTotalAckFeesResponse defines the response type for the + TotalAckFees rpc default: description: An unexpected error response schema: @@ -1754,181 +1767,57 @@ paths: "value": "1.212s" } parameters: - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false + - name: packet_id.channel_id + description: channel unique identifier + in: path + required: true type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false + - name: packet_id.port_id + description: channel port identifier + in: path + required: true type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - format: boolean - - name: query_height - description: block height at which to query. - in: query - required: false + - name: packet_id.sequence + description: packet sequence + in: path + required: true type: string format: uint64 tags: - Query - '/ibc/apps/fee/v1/incentivized_packets/port/{port_id}/channel/{channel_id}': + '/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_recv_fees': get: - summary: Gets all incentivized packets for a specific channel - operationId: IncentivizedPacketsForChannel + summary: >- + TotalRecvFees returns the total receive fees for a packet given its + identifier + operationId: TotalRecvFees responses: '200': description: A successful response. schema: type: object properties: - incentivized_packets: + recv_fees: type: array items: type: object properties: - packet_id: - title: >- - unique packet identifier comprised of the channel ID, - port ID and sequence - type: object - properties: - port_id: - type: string - title: channel port identifier - channel_id: - type: string - title: channel unique identifier - sequence: - type: string - format: uint64 - title: packet sequence - packet_fees: - type: array - items: - type: object - properties: - fee: - title: >- - fee encapsulates the recv, ack and timeout fees - associated with an IBC packet - type: object - properties: - recv_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet receive fee - ack_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. - - - NOTE: The amount field is an Int which - implements the custom method - - signatures required by gogoproto. - title: the packet acknowledgement fee - timeout_fee: - type: array - items: - type: object - properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and - an amount. + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and an amount. - NOTE: The amount field is an Int which - implements the custom method + NOTE: The amount field is an Int which implements the custom + method - signatures required by gogoproto. - title: the packet timeout fee - refund_address: - type: string - title: the refund address for unspent fees - relayers: - type: array - items: - type: string - title: >- - optional list of relayers permitted to receive - fees - title: >- - PacketFee contains ICS29 relayer fees, refund address - and optional list of permitted relayers - title: list of packet fees - title: >- - IdentifiedPacketFees contains a list of type PacketFee and - associated PacketId - title: Map of all incentivized_packets + signatures required by gogoproto. + title: the total packet receive fees title: >- - QueryIncentivizedPacketsResponse defines the response type for the - incentivized packets RPC + QueryTotalRecvFeesResponse defines the response type for the + TotalRecvFees rpc default: description: An unexpected error response schema: @@ -2119,82 +2008,37 @@ paths: "value": "1.212s" } parameters: - - name: port_id + - name: packet_id.channel_id + description: channel unique identifier in: path required: true type: string - - name: channel_id + - name: packet_id.port_id + description: channel port identifier in: path required: true type: string - - name: pagination.key - description: |- - key is a value returned in PageResponse.next_key to begin - querying the next page most efficiently. Only one of offset or key - should be set. - in: query - required: false - type: string - format: byte - - name: pagination.offset - description: >- - offset is a numeric offset that can be used when key is unavailable. - - It is less efficient than using key. Only one of offset or key - should - - be set. - in: query - required: false - type: string - format: uint64 - - name: pagination.limit - description: >- - limit is the total number of results to be returned in the result - page. - - If left empty it will default to a value to be set by each app. - in: query - required: false - type: string - format: uint64 - - name: pagination.count_total - description: >- - count_total is set to true to indicate that the result set should - include - - a count of the total number of items available for pagination in - UIs. - - count_total is only respected when offset is used. It is ignored - when key - - is set. - in: query - required: false - type: boolean - format: boolean - - name: query_height - description: Height to query at. - in: query - required: false + - name: packet_id.sequence + description: packet sequence + in: path + required: true type: string format: uint64 tags: - Query - '/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}': + '/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_timeout_fees': get: summary: >- - TotalAckFees returns the total acknowledgement fees for a packet given - its identifier - operationId: TotalAckFees + TotalTimeoutFees returns the total timeout fees for a packet given its + identifier + operationId: TotalTimeoutFees responses: '200': description: A successful response. schema: type: object properties: - ack_fees: + timeout_fees: type: array items: type: object @@ -2211,10 +2055,10 @@ paths: method signatures required by gogoproto. - title: the total packet acknowledgement fees + title: the total packet timeout fees title: >- - QueryTotalAckFeesResponse defines the response type for the - TotalAckFees rpc + QueryTotalTimeoutFeesResponse defines the response type for the + TotalTimeoutFees rpc default: description: An unexpected error response schema: @@ -2405,13 +2249,13 @@ paths: "value": "1.212s" } parameters: - - name: packet_id.port_id - description: channel port identifier + - name: packet_id.channel_id + description: channel unique identifier in: path required: true type: string - - name: packet_id.channel_id - description: channel unique identifier + - name: packet_id.port_id + description: channel port identifier in: path required: true type: string @@ -2423,39 +2267,34 @@ paths: format: uint64 tags: - Query - '/ibc/apps/fee/v1/total_recv_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}': + /ibc/apps/fee/v1/fee_enabled: get: - summary: >- - TotalRecvFees returns the total receive fees for a packet given its - identifier - operationId: TotalRecvFees + summary: FeeEnabledChannels returns a list of all fee enabled channels + operationId: FeeEnabledChannels responses: '200': description: A successful response. schema: type: object properties: - recv_fees: + fee_enabled_channels: type: array items: type: object properties: - denom: - type: string - amount: + port_id: type: string - description: >- - Coin defines a token with a denomination and an amount. - - - NOTE: The amount field is an Int which implements the custom - method - - signatures required by gogoproto. - title: the total packet receive fees + title: unique port identifier + channel_id: + type: string + title: unique channel identifier + title: >- + FeeEnabledChannel contains the PortID & ChannelID for a fee + enabled channel + title: list of fee enabled channels title: >- - QueryTotalRecvFeesResponse defines the response type for the - TotalRecvFees rpc + QueryFeeEnabledChannelsResponse defines the response type for the + FeeEnabledChannels rpc default: description: An unexpected error response schema: @@ -2646,57 +2485,183 @@ paths: "value": "1.212s" } parameters: - - name: packet_id.port_id - description: channel port identifier - in: path - required: true + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false type: string - - name: packet_id.channel_id - description: channel unique identifier - in: path - required: true + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false type: string - - name: packet_id.sequence - description: packet sequence - in: path - required: true + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + - name: query_height + description: block height at which to query. + in: query + required: false type: string format: uint64 tags: - Query - '/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}': + /ibc/apps/fee/v1/incentivized_packets: get: summary: >- - TotalTimeoutFees returns the total timeout fees for a packet given its - identifier - operationId: TotalTimeoutFees + IncentivizedPackets returns all incentivized packets and their + associated fees + operationId: IncentivizedPackets responses: '200': description: A successful response. schema: type: object properties: - timeout_fees: + incentivized_packets: type: array items: type: object properties: - denom: - type: string - amount: - type: string - description: >- - Coin defines a token with a denomination and an amount. + packet_id: + title: >- + unique packet identifier comprised of the channel ID, + port ID and sequence + type: object + properties: + port_id: + type: string + title: channel port identifier + channel_id: + type: string + title: channel unique identifier + sequence: + type: string + format: uint64 + title: packet sequence + packet_fees: + type: array + items: + type: object + properties: + fee: + title: >- + fee encapsulates the recv, ack and timeout fees + associated with an IBC packet + type: object + properties: + recv_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. - NOTE: The amount field is an Int which implements the custom - method + NOTE: The amount field is an Int which + implements the custom method - signatures required by gogoproto. - title: the total packet timeout fees + signatures required by gogoproto. + title: the packet receive fee + ack_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet acknowledgement fee + timeout_fee: + type: array + items: + type: object + properties: + denom: + type: string + amount: + type: string + description: >- + Coin defines a token with a denomination and + an amount. + + + NOTE: The amount field is an Int which + implements the custom method + + signatures required by gogoproto. + title: the packet timeout fee + refund_address: + type: string + title: the refund address for unspent fees + relayers: + type: array + items: + type: string + title: >- + optional list of relayers permitted to receive + fees + title: >- + PacketFee contains ICS29 relayer fees, refund address + and optional list of permitted relayers + title: list of packet fees + title: >- + IdentifiedPacketFees contains a list of type PacketFee and + associated PacketId + title: list of identified fees for incentivized packets title: >- - QueryTotalTimeoutFeesResponse defines the response type for the - TotalTimeoutFees rpc + QueryIncentivizedPacketsResponse defines the response type for the + IncentivizedPackets rpc default: description: An unexpected error response schema: @@ -2887,20 +2852,57 @@ paths: "value": "1.212s" } parameters: - - name: packet_id.port_id - description: channel port identifier - in: path - required: true + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false type: string - - name: packet_id.channel_id - description: channel unique identifier - in: path - required: true + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false type: string - - name: packet_id.sequence - description: packet sequence - in: path - required: true + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + - name: query_height + description: block height at which to query. + in: query + required: false type: string format: uint64 tags: @@ -12955,7 +12957,6 @@ definitions: type: object properties: incentivized_packet: - title: the identified fees for the incentivized packet type: object properties: packet_id: @@ -13054,6 +13055,9 @@ definitions: PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers title: list of packet fees + title: >- + IdentifiedPacketFees contains a list of type PacketFee and associated + PacketId title: >- QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPacket rpc diff --git a/proto/ibc/applications/fee/v1/query.proto b/proto/ibc/applications/fee/v1/query.proto index acab12f5161..0e1caa5d0f7 100644 --- a/proto/ibc/applications/fee/v1/query.proto +++ b/proto/ibc/applications/fee/v1/query.proto @@ -22,37 +22,37 @@ service Query { // IncentivizedPacket returns all packet fees for a packet given its identifier rpc IncentivizedPacket(QueryIncentivizedPacketRequest) returns (QueryIncentivizedPacketResponse) { option (google.api.http).get = - "/ibc/apps/fee/v1/incentivized_packet/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/" - "{packet_id.sequence}"; + "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/" + "{packet_id.sequence}/incentivized_packet"; } // Gets all incentivized packets for a specific channel rpc IncentivizedPacketsForChannel(QueryIncentivizedPacketsForChannelRequest) returns (QueryIncentivizedPacketsForChannelResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/incentivized_packets/port/{port_id}/channel/{channel_id}"; + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/incentivized_packets"; } // TotalRecvFees returns the total receive fees for a packet given its identifier rpc TotalRecvFees(QueryTotalRecvFeesRequest) returns (QueryTotalRecvFeesResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/total_recv_fees/port/{packet_id.port_id}/channel/" - "{packet_id.channel_id}/sequence/{packet_id.sequence}"; + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" + "sequences/{packet_id.sequence}/total_recv_fees"; } // TotalAckFees returns the total acknowledgement fees for a packet given its identifier rpc TotalAckFees(QueryTotalAckFeesRequest) returns (QueryTotalAckFeesResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/" - "{packet_id.channel_id}/sequence/{packet_id.sequence}"; + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" + "sequences/{packet_id.sequence}/total_ack_fees"; } // TotalTimeoutFees returns the total timeout fees for a packet given its identifier rpc TotalTimeoutFees(QueryTotalTimeoutFeesRequest) returns (QueryTotalTimeoutFeesResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/" - "{packet_id.channel_id}/sequence/{packet_id.sequence}"; + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" + "sequences/{packet_id.sequence}/total_timeout_fees"; } // CounterpartyAddress returns the registered counterparty address for forward relaying rpc CounterpartyAddress(QueryCounterpartyAddressRequest) returns (QueryCounterpartyAddressResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/counterparty_address/{relayer_address}/channel/{channel_id}"; + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address"; } // FeeEnabledChannels returns a list of all fee enabled channels @@ -62,7 +62,7 @@ service Query { // FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel rpc FeeEnabledChannel(QueryFeeEnabledChannelRequest) returns (QueryFeeEnabledChannelResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/fee_enabled/port/{port_id}/channel/{channel_id}"; + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled"; } } From 899f7911a2c75ae8df0c49e782d276a515a672ff Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Mon, 30 May 2022 12:03:06 +0100 Subject: [PATCH 132/275] Adding gRPC query for escrow address (#1416) --- CHANGELOG.md | 1 + docs/client/swagger-ui/swagger.yaml | 62 +++ docs/ibc/proto-docs.md | 34 ++ modules/apps/transfer/keeper/grpc_query.go | 13 + .../apps/transfer/keeper/grpc_query_test.go | 43 ++ modules/apps/transfer/types/query.pb.go | 519 ++++++++++++++++-- modules/apps/transfer/types/query.pb.gw.go | 120 ++++ .../ibc/applications/transfer/v1/query.proto | 19 + 8 files changed, 772 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 465c738b2ee..ad49532bffb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (apps/29-fee) [\#1224](https://github.com/cosmos/ibc-go/pull/1224) Adding Query/CounterpartyAddress and CLI to ICS29 fee middleware * (apps/29-fee) [\#1225](https://github.com/cosmos/ibc-go/pull/1225) Adding Query/FeeEnabledChannel and Query/FeeEnabledChannels with CLIs to ICS29 fee middleware. * (modules/apps/29-fee) [\#1230](https://github.com/cosmos/ibc-go/pull/1230) Adding CLI command for getting incentivized packets for a specific channel-id. +* (modules/apps/transfer) [\#1416](https://github.com/cosmos/ibc-go/pull/1416) Adding gRPC endpoint for getting an escrow account for a given port-id and channel-id. ### Bug Fixes diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml index 3175828f119..3ca3e772583 100644 --- a/docs/client/swagger-ui/swagger.yaml +++ b/docs/client/swagger-ui/swagger.yaml @@ -4,6 +4,59 @@ info: description: A REST interface for state queries version: 1.0.0 paths: + '/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address': + get: + summary: >- + EscrowAddress returns the escrow address for a particular port and + channel id. + operationId: EscrowAddress + responses: + '200': + description: A successful response. + schema: + type: object + properties: + escrow_address: + type: string + title: the escrow account address + description: >- + QueryEscrowAddressResponse is the response type of the + EscrowAddress RPC method. + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + value: + type: string + format: byte + parameters: + - name: channel_id + description: unique channel identifier + in: path + required: true + type: string + - name: port_id + description: unique port identifier + in: path + required: true + type: string + tags: + - Query '/ibc/apps/transfer/v1/denom_hashes/{trace}': get: summary: DenomHash queries a denomination hash information. @@ -12584,6 +12637,15 @@ definitions: QueryConnectionsResponse is the response type for the Query/DenomTraces RPC + method. + ibc.applications.transfer.v1.QueryEscrowAddressResponse: + type: object + properties: + escrow_address: + type: string + title: the escrow account address + description: >- + QueryEscrowAddressResponse is the response type of the EscrowAddress RPC method. ibc.applications.transfer.v1.QueryParamsResponse: type: object diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index db7c27316c4..ecf3ca2aa87 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -126,6 +126,8 @@ - [QueryDenomTraceResponse](#ibc.applications.transfer.v1.QueryDenomTraceResponse) - [QueryDenomTracesRequest](#ibc.applications.transfer.v1.QueryDenomTracesRequest) - [QueryDenomTracesResponse](#ibc.applications.transfer.v1.QueryDenomTracesResponse) + - [QueryEscrowAddressRequest](#ibc.applications.transfer.v1.QueryEscrowAddressRequest) + - [QueryEscrowAddressResponse](#ibc.applications.transfer.v1.QueryEscrowAddressResponse) - [QueryParamsRequest](#ibc.applications.transfer.v1.QueryParamsRequest) - [QueryParamsResponse](#ibc.applications.transfer.v1.QueryParamsResponse) @@ -1920,6 +1922,37 @@ method. + + +### QueryEscrowAddressRequest +QueryEscrowAddressRequest is the request type for the EscrowAddress RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | unique port identifier | +| `channel_id` | [string](#string) | | unique channel identifier | + + + + + + + + +### QueryEscrowAddressResponse +QueryEscrowAddressResponse is the response type of the EscrowAddress RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `escrow_address` | [string](#string) | | the escrow account address | + + + + + + ### QueryParamsRequest @@ -1962,6 +1995,7 @@ Query provides defines the gRPC querier service. | `DenomTraces` | [QueryDenomTracesRequest](#ibc.applications.transfer.v1.QueryDenomTracesRequest) | [QueryDenomTracesResponse](#ibc.applications.transfer.v1.QueryDenomTracesResponse) | DenomTraces queries all denomination traces. | GET|/ibc/apps/transfer/v1/denom_traces| | `Params` | [QueryParamsRequest](#ibc.applications.transfer.v1.QueryParamsRequest) | [QueryParamsResponse](#ibc.applications.transfer.v1.QueryParamsResponse) | Params queries all parameters of the ibc-transfer module. | GET|/ibc/apps/transfer/v1/params| | `DenomHash` | [QueryDenomHashRequest](#ibc.applications.transfer.v1.QueryDenomHashRequest) | [QueryDenomHashResponse](#ibc.applications.transfer.v1.QueryDenomHashResponse) | DenomHash queries a denomination hash information. | GET|/ibc/apps/transfer/v1/denom_hashes/{trace}| +| `EscrowAddress` | [QueryEscrowAddressRequest](#ibc.applications.transfer.v1.QueryEscrowAddressRequest) | [QueryEscrowAddressResponse](#ibc.applications.transfer.v1.QueryEscrowAddressResponse) | EscrowAddress returns the escrow address for a particular port and channel id. | GET|/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address| diff --git a/modules/apps/transfer/keeper/grpc_query.go b/modules/apps/transfer/keeper/grpc_query.go index 25bbbe3d75b..512e8e58396 100644 --- a/modules/apps/transfer/keeper/grpc_query.go +++ b/modules/apps/transfer/keeper/grpc_query.go @@ -108,3 +108,16 @@ func (q Keeper) DenomHash(c context.Context, req *types.QueryDenomHashRequest) ( Hash: denomHash.String(), }, nil } + +// EscrowAddress implements the EscrowAddress gRPC method +func (q Keeper) EscrowAddress(c context.Context, req *types.QueryEscrowAddressRequest) (*types.QueryEscrowAddressResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + addr := types.GetEscrowAddress(req.PortId, req.ChannelId) + + return &types.QueryEscrowAddressResponse{ + EscrowAddress: addr.String(), + }, nil +} diff --git a/modules/apps/transfer/keeper/grpc_query_test.go b/modules/apps/transfer/keeper/grpc_query_test.go index 085891e265b..c0edaea2a20 100644 --- a/modules/apps/transfer/keeper/grpc_query_test.go +++ b/modules/apps/transfer/keeper/grpc_query_test.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" ) func (suite *KeeperTestSuite) TestQueryDenomTrace() { @@ -220,3 +221,45 @@ func (suite *KeeperTestSuite) TestQueryDenomHash() { }) } } + +func (suite *KeeperTestSuite) TestEscrowAddress() { + var ( + req *types.QueryEscrowAddressRequest + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "success", + func() { + req = &types.QueryEscrowAddressRequest{ + PortId: ibctesting.TransferPort, + ChannelId: ibctesting.FirstChannelID, + } + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + + res, err := suite.queryClient.EscrowAddress(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + expected := types.GetEscrowAddress(ibctesting.TransferPort, ibctesting.FirstChannelID).String() + suite.Require().Equal(expected, res.EscrowAddress) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/modules/apps/transfer/types/query.pb.go b/modules/apps/transfer/types/query.pb.go index e1206ab0e30..a137649a094 100644 --- a/modules/apps/transfer/types/query.pb.go +++ b/modules/apps/transfer/types/query.pb.go @@ -404,6 +404,107 @@ func (m *QueryDenomHashResponse) GetHash() string { return "" } +// QueryEscrowAddressRequest is the request type for the EscrowAddress RPC method. +type QueryEscrowAddressRequest struct { + // unique port identifier + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + // unique channel identifier + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` +} + +func (m *QueryEscrowAddressRequest) Reset() { *m = QueryEscrowAddressRequest{} } +func (m *QueryEscrowAddressRequest) String() string { return proto.CompactTextString(m) } +func (*QueryEscrowAddressRequest) ProtoMessage() {} +func (*QueryEscrowAddressRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a638e2800a01538c, []int{8} +} +func (m *QueryEscrowAddressRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryEscrowAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryEscrowAddressRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryEscrowAddressRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryEscrowAddressRequest.Merge(m, src) +} +func (m *QueryEscrowAddressRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryEscrowAddressRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryEscrowAddressRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryEscrowAddressRequest proto.InternalMessageInfo + +func (m *QueryEscrowAddressRequest) GetPortId() string { + if m != nil { + return m.PortId + } + return "" +} + +func (m *QueryEscrowAddressRequest) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +// QueryEscrowAddressResponse is the response type of the EscrowAddress RPC method. +type QueryEscrowAddressResponse struct { + // the escrow account address + EscrowAddress string `protobuf:"bytes,1,opt,name=escrow_address,json=escrowAddress,proto3" json:"escrow_address,omitempty"` +} + +func (m *QueryEscrowAddressResponse) Reset() { *m = QueryEscrowAddressResponse{} } +func (m *QueryEscrowAddressResponse) String() string { return proto.CompactTextString(m) } +func (*QueryEscrowAddressResponse) ProtoMessage() {} +func (*QueryEscrowAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a638e2800a01538c, []int{9} +} +func (m *QueryEscrowAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryEscrowAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryEscrowAddressResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryEscrowAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryEscrowAddressResponse.Merge(m, src) +} +func (m *QueryEscrowAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryEscrowAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryEscrowAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryEscrowAddressResponse proto.InternalMessageInfo + +func (m *QueryEscrowAddressResponse) GetEscrowAddress() string { + if m != nil { + return m.EscrowAddress + } + return "" +} + func init() { proto.RegisterType((*QueryDenomTraceRequest)(nil), "ibc.applications.transfer.v1.QueryDenomTraceRequest") proto.RegisterType((*QueryDenomTraceResponse)(nil), "ibc.applications.transfer.v1.QueryDenomTraceResponse") @@ -413,6 +514,8 @@ func init() { proto.RegisterType((*QueryParamsResponse)(nil), "ibc.applications.transfer.v1.QueryParamsResponse") proto.RegisterType((*QueryDenomHashRequest)(nil), "ibc.applications.transfer.v1.QueryDenomHashRequest") proto.RegisterType((*QueryDenomHashResponse)(nil), "ibc.applications.transfer.v1.QueryDenomHashResponse") + proto.RegisterType((*QueryEscrowAddressRequest)(nil), "ibc.applications.transfer.v1.QueryEscrowAddressRequest") + proto.RegisterType((*QueryEscrowAddressResponse)(nil), "ibc.applications.transfer.v1.QueryEscrowAddressResponse") } func init() { @@ -420,45 +523,52 @@ func init() { } var fileDescriptor_a638e2800a01538c = []byte{ - // 595 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4f, 0x6f, 0xd3, 0x30, - 0x1c, 0xad, 0x07, 0xab, 0x34, 0x17, 0x71, 0x30, 0x05, 0xaa, 0xa8, 0xca, 0xa6, 0xa8, 0x82, 0xd2, - 0x6d, 0x36, 0x69, 0x07, 0x5c, 0x38, 0x4d, 0x88, 0x3f, 0xb7, 0xad, 0x70, 0x82, 0x03, 0x72, 0x52, - 0x93, 0x46, 0x6a, 0xe3, 0x2c, 0x4e, 0x2b, 0x4d, 0x68, 0x17, 0x3e, 0x01, 0xd2, 0xbe, 0x02, 0x07, - 0x34, 0xf1, 0x21, 0x38, 0xee, 0x38, 0x89, 0x0b, 0x27, 0x40, 0x2d, 0x1f, 0x04, 0xc5, 0x76, 0xda, - 0x84, 0x56, 0xdd, 0x72, 0x73, 0xdd, 0xdf, 0xfb, 0xfd, 0xde, 0x7b, 0xbf, 0x17, 0xc3, 0xa6, 0xef, - 0xb8, 0x84, 0x86, 0xe1, 0xc0, 0x77, 0x69, 0xec, 0xf3, 0x40, 0x90, 0x38, 0xa2, 0x81, 0xf8, 0xc0, - 0x22, 0x32, 0xb6, 0xc9, 0xd1, 0x88, 0x45, 0xc7, 0x38, 0x8c, 0x78, 0xcc, 0x51, 0xdd, 0x77, 0x5c, - 0x9c, 0xad, 0xc4, 0x69, 0x25, 0x1e, 0xdb, 0x46, 0xd5, 0xe3, 0x1e, 0x97, 0x85, 0x24, 0x39, 0x29, - 0x8c, 0xd1, 0x72, 0xb9, 0x18, 0x72, 0x41, 0x1c, 0x2a, 0x98, 0x6a, 0x46, 0xc6, 0xb6, 0xc3, 0x62, - 0x6a, 0x93, 0x90, 0x7a, 0x7e, 0x20, 0x1b, 0xe9, 0xda, 0xed, 0x95, 0x4c, 0x66, 0xb3, 0x54, 0x71, - 0xdd, 0xe3, 0xdc, 0x1b, 0x30, 0x42, 0x43, 0x9f, 0xd0, 0x20, 0xe0, 0xb1, 0xa6, 0x24, 0xff, 0xb5, - 0x76, 0xe0, 0x9d, 0xc3, 0x64, 0xd8, 0x33, 0x16, 0xf0, 0xe1, 0x9b, 0x88, 0xba, 0xac, 0xcb, 0x8e, - 0x46, 0x4c, 0xc4, 0x08, 0xc1, 0xeb, 0x7d, 0x2a, 0xfa, 0x35, 0xb0, 0x05, 0x9a, 0x1b, 0x5d, 0x79, - 0xb6, 0x7a, 0xf0, 0xee, 0x42, 0xb5, 0x08, 0x79, 0x20, 0x18, 0x7a, 0x05, 0x2b, 0xbd, 0xe4, 0xf6, - 0x7d, 0x9c, 0x5c, 0x4b, 0x54, 0xa5, 0xdd, 0xc4, 0xab, 0x9c, 0xc0, 0x99, 0x36, 0xb0, 0x37, 0x3b, - 0x5b, 0x74, 0x61, 0x8a, 0x48, 0x49, 0x3d, 0x87, 0x70, 0xee, 0x86, 0x1e, 0x72, 0x0f, 0x2b, 0xeb, - 0x70, 0x62, 0x1d, 0x56, 0x7b, 0xd0, 0xd6, 0xe1, 0x03, 0xea, 0xa5, 0x82, 0xba, 0x19, 0xa4, 0xf5, - 0x1d, 0xc0, 0xda, 0xe2, 0x0c, 0x2d, 0xe5, 0x1d, 0xbc, 0x91, 0x91, 0x22, 0x6a, 0x60, 0xeb, 0x5a, - 0x11, 0x2d, 0xfb, 0x37, 0xcf, 0x7f, 0x6d, 0x96, 0xce, 0x7e, 0x6f, 0x96, 0x75, 0xdf, 0xca, 0x5c, - 0x9b, 0x40, 0x2f, 0x72, 0x0a, 0xd6, 0xa4, 0x82, 0xfb, 0x97, 0x2a, 0x50, 0xcc, 0x72, 0x12, 0xaa, - 0x10, 0x49, 0x05, 0x07, 0x34, 0xa2, 0xc3, 0xd4, 0x20, 0xeb, 0x35, 0xbc, 0x95, 0xbb, 0xd5, 0x92, - 0x9e, 0xc2, 0x72, 0x28, 0x6f, 0xb4, 0x67, 0x8d, 0xd5, 0x62, 0x34, 0x5a, 0x63, 0xac, 0x5d, 0x78, - 0x7b, 0x6e, 0xd6, 0x4b, 0x2a, 0xfa, 0xe9, 0x3a, 0xaa, 0x70, 0x7d, 0xbe, 0xee, 0x8d, 0xae, 0xfa, - 0x91, 0xcf, 0x94, 0x2a, 0xd7, 0x34, 0x96, 0x64, 0xaa, 0xfd, 0x65, 0x1d, 0xae, 0xcb, 0x72, 0xf4, - 0x0d, 0x40, 0x38, 0xb7, 0x11, 0xed, 0xad, 0xe6, 0xb8, 0x3c, 0xb6, 0xc6, 0xa3, 0x82, 0x28, 0xc5, - 0xcc, 0xb2, 0x3f, 0xfd, 0xf8, 0x7b, 0xba, 0xb6, 0x8d, 0x1e, 0x10, 0xfd, 0x6d, 0xe5, 0xbf, 0xa9, - 0x6c, 0x1e, 0xc8, 0xc7, 0x84, 0xf7, 0x09, 0xfa, 0x0a, 0x60, 0x25, 0x13, 0x1f, 0x54, 0x6c, 0x72, - 0xba, 0x31, 0xe3, 0x71, 0x51, 0x98, 0x66, 0xdc, 0x92, 0x8c, 0x1b, 0xc8, 0xba, 0x9c, 0x31, 0x3a, - 0x05, 0xb0, 0xac, 0x76, 0x8a, 0x1e, 0x5e, 0x61, 0x5c, 0x2e, 0x52, 0x86, 0x5d, 0x00, 0xa1, 0xb9, - 0x35, 0x24, 0x37, 0x13, 0xd5, 0x97, 0x73, 0x53, 0xb1, 0x42, 0x67, 0x00, 0x6e, 0xcc, 0x32, 0x82, - 0x3a, 0x57, 0xf5, 0x21, 0x13, 0x40, 0x63, 0xaf, 0x18, 0x48, 0xd3, 0x6b, 0x4b, 0x7a, 0x3b, 0xa8, - 0xb5, 0xca, 0xba, 0x64, 0xc9, 0xc9, 0xb2, 0xa5, 0x85, 0x27, 0xfb, 0x87, 0xe7, 0x13, 0x13, 0x5c, - 0x4c, 0x4c, 0xf0, 0x67, 0x62, 0x82, 0xcf, 0x53, 0xb3, 0x74, 0x31, 0x35, 0x4b, 0x3f, 0xa7, 0x66, - 0xe9, 0xed, 0x13, 0xcf, 0x8f, 0xfb, 0x23, 0x07, 0xbb, 0x7c, 0x48, 0xf4, 0x23, 0xee, 0x3b, 0xee, - 0xae, 0xc7, 0xc9, 0xb8, 0x43, 0x86, 0xbc, 0x37, 0x1a, 0x30, 0xf1, 0xdf, 0x90, 0xf8, 0x38, 0x64, - 0xc2, 0x29, 0xcb, 0x27, 0xb8, 0xf3, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x16, 0x01, 0x88, 0xe2, 0x59, - 0x06, 0x00, 0x00, + // 715 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xcd, 0x6e, 0xd3, 0x4c, + 0x14, 0x8d, 0xfb, 0x7d, 0x0d, 0xca, 0x0d, 0xed, 0x62, 0x28, 0xb4, 0x58, 0xc5, 0xad, 0xac, 0x02, + 0xa5, 0x3f, 0x1e, 0xd2, 0x16, 0xca, 0x82, 0x0d, 0xe5, 0xb7, 0x88, 0x45, 0x9b, 0xb2, 0x82, 0x45, + 0x35, 0xb6, 0x07, 0xc7, 0x52, 0xe2, 0x71, 0x3d, 0x4e, 0x50, 0x55, 0x65, 0xc3, 0x13, 0x20, 0xf5, + 0x25, 0x50, 0xc5, 0x43, 0xb0, 0xec, 0xb2, 0x12, 0x12, 0x62, 0x05, 0xa8, 0xe5, 0x35, 0x90, 0x90, + 0x67, 0x26, 0x89, 0x4d, 0xa3, 0x34, 0xde, 0x8d, 0x67, 0xee, 0xb9, 0xf7, 0x9c, 0x73, 0xef, 0x95, + 0x61, 0xde, 0xb7, 0x1d, 0x4c, 0xc2, 0xb0, 0xee, 0x3b, 0x24, 0xf6, 0x59, 0xc0, 0x71, 0x1c, 0x91, + 0x80, 0xbf, 0xa3, 0x11, 0x6e, 0x55, 0xf0, 0x5e, 0x93, 0x46, 0xfb, 0x56, 0x18, 0xb1, 0x98, 0xa1, + 0x69, 0xdf, 0x76, 0xac, 0x74, 0xa4, 0xd5, 0x89, 0xb4, 0x5a, 0x15, 0x7d, 0xc2, 0x63, 0x1e, 0x13, + 0x81, 0x38, 0x39, 0x49, 0x8c, 0xbe, 0xe0, 0x30, 0xde, 0x60, 0x1c, 0xdb, 0x84, 0x53, 0x99, 0x0c, + 0xb7, 0x2a, 0x36, 0x8d, 0x49, 0x05, 0x87, 0xc4, 0xf3, 0x03, 0x91, 0x48, 0xc5, 0x2e, 0x0e, 0x64, + 0xd2, 0xad, 0x25, 0x83, 0xa7, 0x3d, 0xc6, 0xbc, 0x3a, 0xc5, 0x24, 0xf4, 0x31, 0x09, 0x02, 0x16, + 0x2b, 0x4a, 0xe2, 0xd5, 0x5c, 0x82, 0x6b, 0xdb, 0x49, 0xb1, 0x27, 0x34, 0x60, 0x8d, 0xd7, 0x11, + 0x71, 0x68, 0x95, 0xee, 0x35, 0x29, 0x8f, 0x11, 0x82, 0xff, 0x6b, 0x84, 0xd7, 0xa6, 0xb4, 0x59, + 0x6d, 0xbe, 0x54, 0x15, 0x67, 0xd3, 0x85, 0xc9, 0x73, 0xd1, 0x3c, 0x64, 0x01, 0xa7, 0x68, 0x13, + 0xca, 0x6e, 0x72, 0xbb, 0x1b, 0x27, 0xd7, 0x02, 0x55, 0x5e, 0x99, 0xb7, 0x06, 0x39, 0x61, 0xa5, + 0xd2, 0x80, 0xdb, 0x3d, 0x9b, 0xe4, 0x5c, 0x15, 0xde, 0x21, 0xf5, 0x0c, 0xa0, 0xe7, 0x86, 0x2a, + 0x72, 0xcb, 0x92, 0xd6, 0x59, 0x89, 0x75, 0x96, 0xec, 0x83, 0xb2, 0xce, 0xda, 0x22, 0x5e, 0x47, + 0x50, 0x35, 0x85, 0x34, 0xbf, 0x68, 0x30, 0x75, 0xbe, 0x86, 0x92, 0xf2, 0x16, 0x2e, 0xa7, 0xa4, + 0xf0, 0x29, 0x6d, 0xf6, 0xbf, 0x3c, 0x5a, 0x36, 0xc6, 0x8f, 0x7f, 0xcc, 0x14, 0x8e, 0x7e, 0xce, + 0x14, 0x55, 0xde, 0x72, 0x4f, 0x1b, 0x47, 0xcf, 0x33, 0x0a, 0x46, 0x84, 0x82, 0xdb, 0x17, 0x2a, + 0x90, 0xcc, 0x32, 0x12, 0x26, 0x00, 0x09, 0x05, 0x5b, 0x24, 0x22, 0x8d, 0x8e, 0x41, 0xe6, 0x0e, + 0x5c, 0xc9, 0xdc, 0x2a, 0x49, 0x0f, 0xa1, 0x18, 0x8a, 0x1b, 0xe5, 0xd9, 0xdc, 0x60, 0x31, 0x0a, + 0xad, 0x30, 0xe6, 0x32, 0x5c, 0xed, 0x99, 0xf5, 0x82, 0xf0, 0x5a, 0xa7, 0x1d, 0x13, 0x30, 0xda, + 0x6b, 0x77, 0xa9, 0x2a, 0x3f, 0xb2, 0x33, 0x25, 0xc3, 0x15, 0x8d, 0x7e, 0x33, 0xb5, 0x03, 0xd7, + 0x45, 0xf4, 0x53, 0xee, 0x44, 0xec, 0xfd, 0x23, 0xd7, 0x8d, 0x28, 0xef, 0xf6, 0x7b, 0x12, 0x2e, + 0x85, 0x2c, 0x8a, 0x77, 0x7d, 0x57, 0x61, 0x8a, 0xc9, 0xe7, 0xa6, 0x8b, 0x6e, 0x00, 0x38, 0x35, + 0x12, 0x04, 0xb4, 0x9e, 0xbc, 0x8d, 0x88, 0xb7, 0x92, 0xba, 0xd9, 0x74, 0xcd, 0xc7, 0xa0, 0xf7, + 0x4b, 0xaa, 0x68, 0xdc, 0x84, 0x71, 0x2a, 0x1e, 0x76, 0x89, 0x7c, 0x51, 0xc9, 0xc7, 0x68, 0x3a, + 0x7c, 0xe5, 0x4f, 0x11, 0x46, 0x45, 0x16, 0xf4, 0x59, 0x03, 0xe8, 0x35, 0x18, 0xad, 0x0d, 0x76, + 0xaf, 0xff, 0x42, 0xe9, 0xf7, 0x72, 0xa2, 0x24, 0x59, 0xb3, 0xf2, 0xe1, 0xeb, 0xef, 0xc3, 0x91, + 0x45, 0x74, 0x07, 0xab, 0xad, 0xcf, 0x6e, 0x7b, 0x7a, 0x52, 0xf1, 0x41, 0xe2, 0x68, 0x1b, 0x7d, + 0xd2, 0xa0, 0x9c, 0x1a, 0x6c, 0x94, 0xaf, 0x72, 0xc7, 0x7c, 0xfd, 0x7e, 0x5e, 0x98, 0x62, 0xbc, + 0x20, 0x18, 0xcf, 0x21, 0xf3, 0x62, 0xc6, 0xe8, 0x50, 0x83, 0xa2, 0x9c, 0x36, 0x74, 0x77, 0x88, + 0x72, 0x99, 0x61, 0xd7, 0x2b, 0x39, 0x10, 0x8a, 0xdb, 0x9c, 0xe0, 0x66, 0xa0, 0xe9, 0xfe, 0xdc, + 0xe4, 0xc0, 0xa3, 0x23, 0x0d, 0x4a, 0xdd, 0xe9, 0x45, 0xab, 0xc3, 0xfa, 0x90, 0x5a, 0x0d, 0x7d, + 0x2d, 0x1f, 0x48, 0xd1, 0x5b, 0x11, 0xf4, 0x96, 0xd0, 0xc2, 0x20, 0xeb, 0x92, 0x26, 0x27, 0xcd, + 0x16, 0x16, 0xb6, 0xd1, 0x37, 0x0d, 0xc6, 0x32, 0x73, 0x8e, 0xd6, 0x87, 0xa8, 0xdd, 0x6f, 0xdd, + 0xf4, 0x07, 0xf9, 0x81, 0x8a, 0x78, 0x55, 0x10, 0x7f, 0x85, 0x5e, 0xf6, 0x27, 0xae, 0x36, 0x93, + 0xe3, 0x83, 0xde, 0xd6, 0xb6, 0x71, 0xb2, 0xcb, 0x1c, 0x1f, 0xa8, 0x0d, 0x6f, 0xe3, 0xec, 0x52, + 0x6e, 0x6c, 0x1f, 0x9f, 0x1a, 0xda, 0xc9, 0xa9, 0xa1, 0xfd, 0x3a, 0x35, 0xb4, 0x8f, 0x67, 0x46, + 0xe1, 0xe4, 0xcc, 0x28, 0x7c, 0x3f, 0x33, 0x0a, 0x6f, 0xd6, 0x3d, 0x3f, 0xae, 0x35, 0x6d, 0xcb, + 0x61, 0x0d, 0xac, 0xfe, 0x9b, 0xbe, 0xed, 0x2c, 0x7b, 0x0c, 0xb7, 0x56, 0x71, 0x83, 0xb9, 0xcd, + 0x3a, 0xe5, 0xff, 0x90, 0x88, 0xf7, 0x43, 0xca, 0xed, 0xa2, 0xf8, 0xeb, 0xad, 0xfe, 0x0d, 0x00, + 0x00, 0xff, 0xff, 0x32, 0xbb, 0x42, 0xe2, 0xcc, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -481,6 +591,8 @@ type QueryClient interface { Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) // DenomHash queries a denomination hash information. DenomHash(ctx context.Context, in *QueryDenomHashRequest, opts ...grpc.CallOption) (*QueryDenomHashResponse, error) + // EscrowAddress returns the escrow address for a particular port and channel id. + EscrowAddress(ctx context.Context, in *QueryEscrowAddressRequest, opts ...grpc.CallOption) (*QueryEscrowAddressResponse, error) } type queryClient struct { @@ -527,6 +639,15 @@ func (c *queryClient) DenomHash(ctx context.Context, in *QueryDenomHashRequest, return out, nil } +func (c *queryClient) EscrowAddress(ctx context.Context, in *QueryEscrowAddressRequest, opts ...grpc.CallOption) (*QueryEscrowAddressResponse, error) { + out := new(QueryEscrowAddressResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.transfer.v1.Query/EscrowAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // DenomTrace queries a denomination trace information. @@ -537,6 +658,8 @@ type QueryServer interface { Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) // DenomHash queries a denomination hash information. DenomHash(context.Context, *QueryDenomHashRequest) (*QueryDenomHashResponse, error) + // EscrowAddress returns the escrow address for a particular port and channel id. + EscrowAddress(context.Context, *QueryEscrowAddressRequest) (*QueryEscrowAddressResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -555,6 +678,9 @@ func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsReq func (*UnimplementedQueryServer) DenomHash(ctx context.Context, req *QueryDenomHashRequest) (*QueryDenomHashResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DenomHash not implemented") } +func (*UnimplementedQueryServer) EscrowAddress(ctx context.Context, req *QueryEscrowAddressRequest) (*QueryEscrowAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method EscrowAddress not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -632,6 +758,24 @@ func _Query_DenomHash_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } +func _Query_EscrowAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryEscrowAddressRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).EscrowAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.transfer.v1.Query/EscrowAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).EscrowAddress(ctx, req.(*QueryEscrowAddressRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "ibc.applications.transfer.v1.Query", HandlerType: (*QueryServer)(nil), @@ -652,6 +796,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "DenomHash", Handler: _Query_DenomHash_Handler, }, + { + MethodName: "EscrowAddress", + Handler: _Query_EscrowAddress_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "ibc/applications/transfer/v1/query.proto", @@ -924,6 +1072,73 @@ func (m *QueryDenomHashResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *QueryEscrowAddressRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryEscrowAddressRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryEscrowAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryEscrowAddressResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryEscrowAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryEscrowAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.EscrowAddress) > 0 { + i -= len(m.EscrowAddress) + copy(dAtA[i:], m.EscrowAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.EscrowAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -1041,6 +1256,36 @@ func (m *QueryDenomHashResponse) Size() (n int) { return n } +func (m *QueryEscrowAddressRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryEscrowAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.EscrowAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1721,6 +1966,202 @@ func (m *QueryDenomHashResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryEscrowAddressRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryEscrowAddressRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryEscrowAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryEscrowAddressResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryEscrowAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryEscrowAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EscrowAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EscrowAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/transfer/types/query.pb.gw.go b/modules/apps/transfer/types/query.pb.gw.go index 6f17d4dc055..71474a1b2fc 100644 --- a/modules/apps/transfer/types/query.pb.gw.go +++ b/modules/apps/transfer/types/query.pb.gw.go @@ -193,6 +193,82 @@ func local_request_Query_DenomHash_0(ctx context.Context, marshaler runtime.Mars } +func request_Query_EscrowAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryEscrowAddressRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + msg, err := client.EscrowAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_EscrowAddress_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryEscrowAddressRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + val, ok = pathParams["port_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + } + + protoReq.PortId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + } + + msg, err := server.EscrowAddress(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -279,6 +355,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_EscrowAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_EscrowAddress_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_EscrowAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -400,6 +496,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_EscrowAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_EscrowAddress_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_EscrowAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -411,6 +527,8 @@ var ( pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "apps", "transfer", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_DenomHash_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "apps", "transfer", "v1", "denom_hashes", "trace"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_EscrowAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "transfer", "v1", "channels", "channel_id", "ports", "port_id", "escrow_address"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -421,4 +539,6 @@ var ( forward_Query_Params_0 = runtime.ForwardResponseMessage forward_Query_DenomHash_0 = runtime.ForwardResponseMessage + + forward_Query_EscrowAddress_0 = runtime.ForwardResponseMessage ) diff --git a/proto/ibc/applications/transfer/v1/query.proto b/proto/ibc/applications/transfer/v1/query.proto index 8491c52139b..5298338c10c 100644 --- a/proto/ibc/applications/transfer/v1/query.proto +++ b/proto/ibc/applications/transfer/v1/query.proto @@ -30,6 +30,11 @@ service Query { rpc DenomHash(QueryDenomHashRequest) returns (QueryDenomHashResponse) { option (google.api.http).get = "/ibc/apps/transfer/v1/denom_hashes/{trace}"; } + + // EscrowAddress returns the escrow address for a particular port and channel id. + rpc EscrowAddress(QueryEscrowAddressRequest) returns (QueryEscrowAddressResponse) { + option (google.api.http).get = "/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address"; + } } // QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC @@ -84,3 +89,17 @@ message QueryDenomHashResponse { // hash (in hex format) of the denomination trace information. string hash = 1; } + +// QueryEscrowAddressRequest is the request type for the EscrowAddress RPC method. +message QueryEscrowAddressRequest { + // unique port identifier + string port_id = 1; + // unique channel identifier + string channel_id = 2; +} + +// QueryEscrowAddressResponse is the response type of the EscrowAddress RPC method. +message QueryEscrowAddressResponse { + // the escrow account address + string escrow_address = 1; +} \ No newline at end of file From 9ed5ca4121d52c8a99076360acf62e52cf7887ea Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 31 May 2022 15:56:17 +0100 Subject: [PATCH 133/275] Emit channel close event on ordered channel close (#1464) --- CHANGELOG.md | 3 ++- modules/core/04-channel/keeper/events.go | 15 +++++++++++++++ modules/core/04-channel/keeper/timeout.go | 4 ++++ modules/core/04-channel/types/events.go | 1 + 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad49532bffb..c0ac41e180c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees * (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. ### Features @@ -68,7 +69,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (apps/29-fee) [\#1224](https://github.com/cosmos/ibc-go/pull/1224) Adding Query/CounterpartyAddress and CLI to ICS29 fee middleware * (apps/29-fee) [\#1225](https://github.com/cosmos/ibc-go/pull/1225) Adding Query/FeeEnabledChannel and Query/FeeEnabledChannels with CLIs to ICS29 fee middleware. * (modules/apps/29-fee) [\#1230](https://github.com/cosmos/ibc-go/pull/1230) Adding CLI command for getting incentivized packets for a specific channel-id. -* (modules/apps/transfer) [\#1416](https://github.com/cosmos/ibc-go/pull/1416) Adding gRPC endpoint for getting an escrow account for a given port-id and channel-id. +* (modules/apps/transfer) [\#1416](https://github.com/cosmos/ibc-go/pull/1416) Adding gRPC endpoint for getting an escrow account for a given port-id and channel-id. ### Bug Fixes diff --git a/modules/core/04-channel/keeper/events.go b/modules/core/04-channel/keeper/events.go index 731d298a2ae..66b47467216 100644 --- a/modules/core/04-channel/keeper/events.go +++ b/modules/core/04-channel/keeper/events.go @@ -252,3 +252,18 @@ func EmitTimeoutPacketEvent(ctx sdk.Context, packet exported.PacketI, channel ty ), }) } + +// EmitChannelClosedEvent emits a channel closed event. +func EmitChannelClosedEvent(ctx sdk.Context, packet exported.PacketI, channel types.Channel) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelClosed, + sdk.NewAttribute(types.AttributeKeyPortID, packet.GetSourcePort()), + sdk.NewAttribute(types.AttributeKeyChannelID, packet.GetSourceChannel()), + sdk.NewAttribute(types.AttributeCounterpartyPortID, channel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, channel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyConnectionID, channel.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeKeyChannelOrdering, channel.Ordering.String()), + ), + }) +} diff --git a/modules/core/04-channel/keeper/timeout.go b/modules/core/04-channel/keeper/timeout.go index 5a14ef85b6b..f29f1cca671 100644 --- a/modules/core/04-channel/keeper/timeout.go +++ b/modules/core/04-channel/keeper/timeout.go @@ -170,6 +170,10 @@ func (k Keeper) TimeoutExecuted( // emit an event marking that we have processed the timeout EmitTimeoutPacketEvent(ctx, packet, channel) + if channel.Ordering == types.ORDERED && channel.State == types.CLOSED { + EmitChannelClosedEvent(ctx, packet, channel) + } + return nil } diff --git a/modules/core/04-channel/types/events.go b/modules/core/04-channel/types/events.go index e9f909a695d..8740c3838eb 100644 --- a/modules/core/04-channel/types/events.go +++ b/modules/core/04-channel/types/events.go @@ -48,6 +48,7 @@ var ( EventTypeChannelOpenConfirm = "channel_open_confirm" EventTypeChannelCloseInit = "channel_close_init" EventTypeChannelCloseConfirm = "channel_close_confirm" + EventTypeChannelClosed = "channel_close" AttributeValueCategory = fmt.Sprintf("%s_%s", host.ModuleName, SubModuleName) ) From 7484dbde7302a6d05bd2eca9039aa22bde68d9ef Mon Sep 17 00:00:00 2001 From: Kevin Yang Date: Wed, 1 Jun 2022 04:45:09 -0700 Subject: [PATCH 134/275] Fix typo (#1468) Co-authored-by: Carlos Rodriguez --- docs/ibc/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ibc/overview.md b/docs/ibc/overview.md index 53ad64e08e8..f36b366a5e0 100644 --- a/docs/ibc/overview.md +++ b/docs/ibc/overview.md @@ -46,7 +46,7 @@ and the global client counter appended in the format: `{client-type}-{N}`. A `ClientState` should contain chain specific and light client specific information necessary for verifying updates and upgrades to the IBC client. The `ClientState` may contain information such as chain-id, latest height, proof specs, unbonding periods or the status of the light client. The `ClientState` should not contain information that -is specific to a given block at a certain height, this is the function of the `CosnensusState`. Each `ConsensusState` +is specific to a given block at a certain height, this is the function of the `ConsensusState`. Each `ConsensusState` should be associated with a unique block and should be referenced using a height. IBC clients are given a client identifier prefixed store to store their associated client state and consensus states along with any metadata associated with the consensus states. Consensus states are stored using their associated height. From b9a95020d38384dd990fd68a09a76731ceda91c5 Mon Sep 17 00:00:00 2001 From: GNONG <65050483+Choi-Jinhong@users.noreply.github.com> Date: Thu, 2 Jun 2022 04:15:35 +0900 Subject: [PATCH 135/275] fix typo in comment (#1435) fix typo in comment Co-authored-by: Carlos Rodriguez --- modules/core/05-port/types/module.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 7ac57479dbd..26501af313c 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -105,7 +105,7 @@ type IBCModule interface { ) error } -// ICS4Wrapper implements the ICS4 interfaces that IBC applications use to send packets and acknolwedgements. +// ICS4Wrapper implements the ICS4 interfaces that IBC applications use to send packets and acknowledgements. type ICS4Wrapper interface { SendPacket( ctx sdk.Context, From e19336552f75277c12e98ad3ba6038e19fc267f4 Mon Sep 17 00:00:00 2001 From: GNONG <65050483+Choi-Jinhong@users.noreply.github.com> Date: Thu, 2 Jun 2022 05:12:49 +0900 Subject: [PATCH 136/275] fix typo (#1434) fix typo Co-authored-by: Carlos Rodriguez --- docs/ibc/apps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ibc/apps.md b/docs/ibc/apps.md index f729d7dfd71..267a2e5ca55 100644 --- a/docs/ibc/apps.md +++ b/docs/ibc/apps.md @@ -17,7 +17,7 @@ protocol. Then the document goes into detail on the abstraction layer most relev developers (channels and ports), and describes how to define your own custom packets, and `IBCModule` callbacks. -To have your module interact over IBC you must: bind to a port(s), define your own packet data and acknolwedgement structs as well as how to encode/decode them, and implement the +To have your module interact over IBC you must: bind to a port(s), define your own packet data and acknowledgement structs as well as how to encode/decode them, and implement the `IBCModule` interface. Below is a more detailed explanation of how to write an IBC application module correctly. From 25665692d231facd2277aa14b7a9890ae5b4b5ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 10:26:37 +0200 Subject: [PATCH 137/275] build(deps): bump github.com/armon/go-metrics from 0.3.11 to 0.4.0 (#1441) Bumps [github.com/armon/go-metrics](https://github.com/armon/go-metrics) from 0.3.11 to 0.4.0. - [Release notes](https://github.com/armon/go-metrics/releases) - [Commits](https://github.com/armon/go-metrics/compare/v0.3.11...v0.4.0) --- updated-dependencies: - dependency-name: github.com/armon/go-metrics dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b2f2e409401..17781d244b5 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ module github.com/cosmos/ibc-go/v3 replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 require ( - github.com/armon/go-metrics v0.3.11 + github.com/armon/go-metrics v0.4.0 github.com/confio/ics23/go v0.7.0 github.com/cosmos/cosmos-sdk v0.45.4 github.com/gogo/protobuf v1.3.3 diff --git a/go.sum b/go.sum index 6d985a7ab23..acbd0e9c348 100644 --- a/go.sum +++ b/go.sum @@ -131,8 +131,8 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-metrics v0.3.11 h1:/q4zqTAH+/mtFjimfc0SC7yuuxZshlS4TaCeBm+7sZ0= -github.com/armon/go-metrics v0.3.11/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= From 46f5eee52a4cf6ad58e176aa82d8502868d38e52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 17:22:13 +0200 Subject: [PATCH 138/275] build(deps): bump google.golang.org/grpc from 1.46.2 to 1.47.0 (#1481) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.46.2 to 1.47.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.46.2...v1.47.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 17781d244b5..927cb743635 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd - google.golang.org/grpc v1.46.2 + google.golang.org/grpc v1.47.0 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index acbd0e9c348..de1a0cb536a 100644 --- a/go.sum +++ b/go.sum @@ -1622,8 +1622,9 @@ google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 97e6b38e83721159198f534e25c19dcd9ac8e1e2 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Fri, 3 Jun 2022 12:21:38 +0100 Subject: [PATCH 139/275] Add simd Dockerfile (#1485) --- .github/workflows/test.yml | 7 +++++++ Dockerfile | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 Dockerfile diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 31ef80c80f2..be50bf0bdf1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,6 +51,13 @@ jobs: - name: Build run: GOARCH=${{ matrix.go-arch }} LEDGER_ENABLED=false make build + docker-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Docker Build + run: docker build . --no-cache + split-test-files: runs-on: ubuntu-latest steps: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000000..eb044d5eaf9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM golang:1.17 as builder + +ENV GOPATH="" +ENV GOMODULE="on" + +COPY go.mod . +COPY go.sum . + +RUN go mod download + +ADD testing testing +ADD modules modules +ADD LICENSE LICENSE + +COPY Makefile . + +RUN make build + +FROM ubuntu:20.04 + +COPY --from=builder /go/build/simd /bin/simd + +ENTRYPOINT ["simd"] From fe8e456ba93fd5b4021622b89b56f2798975cfce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 22:08:15 +0200 Subject: [PATCH 140/275] build(deps): bump github.com/stretchr/testify from 1.7.1 to 1.7.2 (#1494) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.1 to 1.7.2. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.7.1...v1.7.2) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 927cb743635..52253cfd620 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.12.0 - github.com/stretchr/testify v1.7.1 + github.com/stretchr/testify v1.7.2 github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd @@ -117,6 +117,6 @@ require ( golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect gopkg.in/ini.v1 v1.66.4 // indirect - gopkg.in/yaml.v3 v3.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/go.sum b/go.sum index de1a0cb536a..f79484ffd40 100644 --- a/go.sum +++ b/go.sum @@ -968,8 +968,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= @@ -1676,8 +1677,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From ba83e7094e58dfca203f59f154ea4d2023511710 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 09:13:32 +0200 Subject: [PATCH 141/275] build(deps): bump goreleaser/goreleaser-action from 2 to 3 (#1415) Bumps [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from 2 to 3. - [Release notes](https://github.com/goreleaser/goreleaser-action/releases) - [Commits](https://github.com/goreleaser/goreleaser-action/compare/v2...v3) --- updated-dependencies: - dependency-name: goreleaser/goreleaser-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 06b91b20c75..479d90a432e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: go-version: '1.17' - name: Release - uses: goreleaser/goreleaser-action@v2 + uses: goreleaser/goreleaser-action@v3 if: startsWith(github.ref, 'refs/tags/') with: version: latest From b2ca1932849cc3f05fe9e6ec30049aa4d08e6fc6 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 7 Jun 2022 10:12:17 +0100 Subject: [PATCH 142/275] Emit an event to indicate a successful acknowledgement in the ICA module (#1466) --- CHANGELOG.md | 1 + .../27-interchain-accounts/host/ibc_module.go | 11 ++++++----- .../27-interchain-accounts/host/keeper/events.go | 15 +++++++++++---- .../apps/27-interchain-accounts/types/events.go | 1 + 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0ac41e180c..98f6dac5674 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (channel) [\#644](https://github.com/cosmos/ibc-go/pull/644) Adds `GetChannelConnection` to the ChannelKeeper. This function returns the connectionID and connection state associated with a channel. * (channel) [\#647](https://github.com/cosmos/ibc-go/pull/647) Reorganizes channel handshake handling to set channel state after IBC application callbacks. * (client) [\#724](https://github.com/cosmos/ibc-go/pull/724) `IsRevisionFormat` and `IsClientIDFormat` have been updated to disallow newlines before the dash used to separate the chainID and revision number, and the client type and client sequence. +* (interchain-accounts) [\#1466](https://github.com/cosmos/ibc-go/pull/1466) Emit event when there is an acknowledgement during `OnRecvPacket`. ### Features diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 1598801601f..2e1ba8e0805 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -110,15 +110,16 @@ func (im IBCModule) OnRecvPacket( } txResponse, err := im.keeper.OnRecvPacket(ctx, packet) + ack := channeltypes.NewResultAcknowledgement(txResponse) if err != nil { - // Emit an event including the error msg - keeper.EmitWriteErrorAcknowledgementEvent(ctx, packet, err) - - return types.NewErrorAcknowledgement(err) + ack = types.NewErrorAcknowledgement(err) } + // Emit an event indicating a successful or failed acknowledgement. + keeper.EmitAcknowledgementEvent(ctx, packet, ack, err) + // NOTE: acknowledgement will be written synchronously during IBC handler execution. - return channeltypes.NewResultAcknowledgement(txResponse) + return ack } // OnAcknowledgementPacket implements the IBCModule interface diff --git a/modules/apps/27-interchain-accounts/host/keeper/events.go b/modules/apps/27-interchain-accounts/host/keeper/events.go index 65c75f02618..116fb1cc3f7 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/events.go +++ b/modules/apps/27-interchain-accounts/host/keeper/events.go @@ -1,20 +1,27 @@ package keeper import ( + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" "github.com/cosmos/ibc-go/v3/modules/core/exported" ) -// EmitWriteErrorAcknowledgementEvent emits an event signalling an error acknowledgement and including the error details -func EmitWriteErrorAcknowledgementEvent(ctx sdk.Context, packet exported.PacketI, err error) { +// EmitAcknowledgementEvent emits an event signalling a successful or failed acknowledgement and including the error +// details if any. +func EmitAcknowledgementEvent(ctx sdk.Context, packet exported.PacketI, ack exported.Acknowledgement, err error) { + var errorMsg string + if err != nil { + errorMsg = err.Error() + } + ctx.EventManager().EmitEvent( sdk.NewEvent( icatypes.EventTypePacket, sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), - sdk.NewAttribute(icatypes.AttributeKeyAckError, err.Error()), + sdk.NewAttribute(icatypes.AttributeKeyAckError, errorMsg), sdk.NewAttribute(icatypes.AttributeKeyHostChannelID, packet.GetDestChannel()), + sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), ), ) } diff --git a/modules/apps/27-interchain-accounts/types/events.go b/modules/apps/27-interchain-accounts/types/events.go index 04882a6a644..9bfd1df3049 100644 --- a/modules/apps/27-interchain-accounts/types/events.go +++ b/modules/apps/27-interchain-accounts/types/events.go @@ -6,4 +6,5 @@ const ( AttributeKeyAckError = "error" AttributeKeyHostChannelID = "host_channel_id" + AttributeKeyAckSuccess = "success" ) From 042d8187d751bdacdecbb1e730f3dc09da24caed Mon Sep 17 00:00:00 2001 From: khanh <50263489+catShaark@users.noreply.github.com> Date: Wed, 8 Jun 2022 02:29:23 +0700 Subject: [PATCH 143/275] chore: Add consensus state heights query (#1336) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add ConsensusStateHeights query * add cli for ConsensusStateHeights Query * update CHANGELOG.md * Update modules/core/02-client/keeper/grpc_query.go Co-authored-by: Damian Nolan * Update modules/core/02-client/client/cli/query.go Co-authored-by: Damian Nolan * Update modules/core/02-client/client/cli/query.go Co-authored-by: Damian Nolan * Update modules/core/02-client/client/cli/query.go Co-authored-by: Damian Nolan * update consensus height query * very minor changes in modules/core/02-client grpc_query_test * Update modules/core/02-client/keeper/grpc_query_test.go Co-authored-by: Sean King * Update modules/core/02-client/keeper/grpc_query_test.go Co-authored-by: Sean King * Update modules/core/02-client/keeper/grpc_query_test.go Co-authored-by: Sean King * Update modules/core/02-client/keeper/grpc_query_test.go Co-authored-by: Sean King * Update modules/core/02-client/client/cli/query.go Co-authored-by: Sean King * Update modules/core/02-client/keeper/grpc_query_test.go Co-authored-by: Carlos Rodriguez * Update CHANGELOG.md Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * update swagger.yaml; update 02-client grpc_query_test * Update modules/core/02-client/keeper/grpc_query_test.go Co-authored-by: Damian Nolan * nit Co-authored-by: Damian Nolan Co-authored-by: Sean King Co-authored-by: Carlos Rodriguez Co-authored-by: vuong <56973102+vuong177@users.noreply.github.com> Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- CHANGELOG.md | 1 + docs/client/swagger-ui/swagger.yaml | 435 +++++++++++- docs/ibc/proto-docs.md | 37 + modules/core/02-client/client/cli/cli.go | 1 + modules/core/02-client/client/cli/query.go | 43 ++ modules/core/02-client/keeper/grpc_query.go | 40 ++ .../core/02-client/keeper/grpc_query_test.go | 154 +++- modules/core/02-client/types/query.pb.go | 664 ++++++++++++++++-- modules/core/02-client/types/query.pb.gw.go | 116 +++ modules/core/keeper/grpc_query.go | 5 + proto/ibc/core/client/v1/query.proto | 23 + 11 files changed, 1409 insertions(+), 110 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98f6dac5674..104c9bb142e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* (modules/core/02-client) [\#1336](https://github.com/cosmos/ibc-go/pull/1336) Adding Query/ConsensusStateHeights gRPC for fetching the height of every consensus state associated with a client. * [\#276](https://github.com/cosmos/ibc-go/pull/276) Adding the Fee Middleware module v1 * (apps/29-fee) [\#1229](https://github.com/cosmos/ibc-go/pull/1229) Adding CLI commands for getting all unrelayed incentivized packets and packet by packet-id. * (apps/29-fee) [\#1224](https://github.com/cosmos/ibc-go/pull/1224) Adding Query/CounterpartyAddress and CLI to ICS29 fee middleware diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml index 3ca3e772583..084cc498a5d 100644 --- a/docs/client/swagger-ui/swagger.yaml +++ b/docs/client/swagger-ui/swagger.yaml @@ -4285,6 +4285,331 @@ paths: type: string tags: - Query + '/ibc/core/client/v1/consensus_states/heights/{client_id}': + get: + summary: >- + ConsensusStateHeights queries the height of every consensus states + associated with a given client. + operationId: ConsensusStateHeights + responses: + '200': + description: A successful response. + schema: + type: object + properties: + consensus_state_heights: + type: array + items: + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping + + RevisionNumber the same. However some consensus algorithms + may choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is + incremented so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + Height is a monotonically increasing data type + + that can be compared against another Height for the purposes + of updating and + + freezing clients + title: consensus state heights + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: >- + PageResponse is to be embedded in gRPC response messages where + the + + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + title: |- + QueryConsensusStateHeightsResponse is the response type for the + Query/ConsensusStateHeights RPC method + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: client_id + description: client identifier + in: path + required: true + type: string + - name: pagination.key + description: |- + key is a value returned in PageResponse.next_key to begin + querying the next page most efficiently. Only one of offset or key + should be set. + in: query + required: false + type: string + format: byte + - name: pagination.offset + description: >- + offset is a numeric offset that can be used when key is unavailable. + + It is less efficient than using key. Only one of offset or key + should + + be set. + in: query + required: false + type: string + format: uint64 + - name: pagination.limit + description: >- + limit is the total number of results to be returned in the result + page. + + If left empty it will default to a value to be set by each app. + in: query + required: false + type: string + format: uint64 + - name: pagination.count_total + description: >- + count_total is set to true to indicate that the result set should + include + + a count of the total number of items available for pagination in + UIs. + + count_total is only respected when offset is used. It is ignored + when key + + is set. + in: query + required: false + type: boolean + format: boolean + tags: + - Query '/ibc/core/client/v1/consensus_states/{client_id}': get: summary: |- @@ -4303,7 +4628,6 @@ paths: type: object properties: height: - title: consensus state height type: object properties: revision_number: @@ -4331,6 +4655,13 @@ paths: the RevisionHeight gets reset + title: >- + Height is a monotonically increasing data type + + that can be compared against another Height for the + purposes of updating and + + freezing clients consensus_state: type: object properties: @@ -4983,7 +5314,6 @@ paths: format: byte title: merkle proof of existence proof_height: - title: height at which the proof was retrieved type: object properties: revision_number: @@ -5011,6 +5341,13 @@ paths: RevisionHeight gets reset + title: >- + Height is a monotonically increasing data type + + that can be compared against another Height for the purposes + of updating and + + freezing clients title: >- QueryConsensusStateResponse is the response type for the Query/ConsensusState @@ -13429,7 +13766,6 @@ definitions: type: object properties: height: - title: consensus state height type: object properties: revision_number: @@ -13456,6 +13792,13 @@ definitions: RevisionHeight gets reset + title: >- + Height is a monotonically increasing data type + + that can be compared against another Height for the purposes of + updating and + + freezing clients consensus_state: type: object properties: @@ -14271,6 +14614,76 @@ definitions: RPC method. It returns the current status of the IBC client. + ibc.core.client.v1.QueryConsensusStateHeightsResponse: + type: object + properties: + consensus_state_heights: + type: array + items: + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height while + keeping + + RevisionNumber the same. However some consensus algorithms may + choose to + + reset the height in certain conditions e.g. hard forks, + state-machine + + breaking changes In these cases, the RevisionNumber is incremented + so that + + height continues to be monitonically increasing even as the + RevisionHeight + + gets reset + title: >- + Height is a monotonically increasing data type + + that can be compared against another Height for the purposes of + updating and + + freezing clients + title: consensus state heights + pagination: + title: pagination response + type: object + properties: + next_key: + type: string + format: byte + title: |- + next_key is the key to be passed to PageRequest.key to + query the next page most efficiently + total: + type: string + format: uint64 + title: >- + total is total number of results available if + PageRequest.count_total + + was set, its value is undefined otherwise + description: |- + PageResponse is to be embedded in gRPC response messages where the + corresponding request message has used PageRequest. + + message SomeResponse { + repeated Bar results = 1; + PageResponse page = 2; + } + title: |- + QueryConsensusStateHeightsResponse is the response type for the + Query/ConsensusStateHeights RPC method ibc.core.client.v1.QueryConsensusStateResponse: type: object properties: @@ -14441,7 +14854,6 @@ definitions: format: byte title: merkle proof of existence proof_height: - title: height at which the proof was retrieved type: object properties: revision_number: @@ -14468,6 +14880,13 @@ definitions: RevisionHeight gets reset + title: >- + Height is a monotonically increasing data type + + that can be compared against another Height for the purposes of + updating and + + freezing clients title: >- QueryConsensusStateResponse is the response type for the Query/ConsensusState @@ -14482,7 +14901,6 @@ definitions: type: object properties: height: - title: consensus state height type: object properties: revision_number: @@ -14510,6 +14928,13 @@ definitions: RevisionHeight gets reset + title: >- + Height is a monotonically increasing data type + + that can be compared against another Height for the purposes of + updating and + + freezing clients consensus_state: type: object properties: diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index ecf3ca2aa87..9bbf462a18f 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -216,6 +216,8 @@ - [QueryClientStatesResponse](#ibc.core.client.v1.QueryClientStatesResponse) - [QueryClientStatusRequest](#ibc.core.client.v1.QueryClientStatusRequest) - [QueryClientStatusResponse](#ibc.core.client.v1.QueryClientStatusResponse) + - [QueryConsensusStateHeightsRequest](#ibc.core.client.v1.QueryConsensusStateHeightsRequest) + - [QueryConsensusStateHeightsResponse](#ibc.core.client.v1.QueryConsensusStateHeightsResponse) - [QueryConsensusStateRequest](#ibc.core.client.v1.QueryConsensusStateRequest) - [QueryConsensusStateResponse](#ibc.core.client.v1.QueryConsensusStateResponse) - [QueryConsensusStatesRequest](#ibc.core.client.v1.QueryConsensusStatesRequest) @@ -3236,6 +3238,40 @@ method. It returns the current status of the IBC client. + + +### QueryConsensusStateHeightsRequest +QueryConsensusStateHeightsRequest is the request type for Query/ConsensusStateHeights +RPC method. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `client_id` | [string](#string) | | client identifier | +| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination request | + + + + + + + + +### QueryConsensusStateHeightsResponse +QueryConsensusStateHeightsResponse is the response type for the +Query/ConsensusStateHeights RPC method + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `consensus_state_heights` | [Height](#ibc.core.client.v1.Height) | repeated | consensus state heights | +| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination response | + + + + + + ### QueryConsensusStateRequest @@ -3379,6 +3415,7 @@ Query provides defines the gRPC querier service | `ClientStates` | [QueryClientStatesRequest](#ibc.core.client.v1.QueryClientStatesRequest) | [QueryClientStatesResponse](#ibc.core.client.v1.QueryClientStatesResponse) | ClientStates queries all the IBC light clients of a chain. | GET|/ibc/core/client/v1/client_states| | `ConsensusState` | [QueryConsensusStateRequest](#ibc.core.client.v1.QueryConsensusStateRequest) | [QueryConsensusStateResponse](#ibc.core.client.v1.QueryConsensusStateResponse) | ConsensusState queries a consensus state associated with a client state at a given height. | GET|/ibc/core/client/v1/consensus_states/{client_id}/revision/{revision_number}/height/{revision_height}| | `ConsensusStates` | [QueryConsensusStatesRequest](#ibc.core.client.v1.QueryConsensusStatesRequest) | [QueryConsensusStatesResponse](#ibc.core.client.v1.QueryConsensusStatesResponse) | ConsensusStates queries all the consensus state associated with a given client. | GET|/ibc/core/client/v1/consensus_states/{client_id}| +| `ConsensusStateHeights` | [QueryConsensusStateHeightsRequest](#ibc.core.client.v1.QueryConsensusStateHeightsRequest) | [QueryConsensusStateHeightsResponse](#ibc.core.client.v1.QueryConsensusStateHeightsResponse) | ConsensusStateHeights queries the height of every consensus states associated with a given client. | GET|/ibc/core/client/v1/consensus_states/heights/{client_id}| | `ClientStatus` | [QueryClientStatusRequest](#ibc.core.client.v1.QueryClientStatusRequest) | [QueryClientStatusResponse](#ibc.core.client.v1.QueryClientStatusResponse) | Status queries the status of an IBC client. | GET|/ibc/core/client/v1/client_status/{client_id}| | `ClientParams` | [QueryClientParamsRequest](#ibc.core.client.v1.QueryClientParamsRequest) | [QueryClientParamsResponse](#ibc.core.client.v1.QueryClientParamsResponse) | ClientParams queries all parameters of the ibc client. | GET|/ibc/client/v1/params| | `UpgradedClientState` | [QueryUpgradedClientStateRequest](#ibc.core.client.v1.QueryUpgradedClientStateRequest) | [QueryUpgradedClientStateResponse](#ibc.core.client.v1.QueryUpgradedClientStateResponse) | UpgradedClientState queries an Upgraded IBC light client. | GET|/ibc/core/client/v1/upgraded_client_states| diff --git a/modules/core/02-client/client/cli/cli.go b/modules/core/02-client/client/cli/cli.go index be33557d7ed..d06977016bd 100644 --- a/modules/core/02-client/client/cli/cli.go +++ b/modules/core/02-client/client/cli/cli.go @@ -22,6 +22,7 @@ func GetQueryCmd() *cobra.Command { GetCmdQueryClientState(), GetCmdQueryClientStatus(), GetCmdQueryConsensusStates(), + GetCmdQueryConsensusStateHeights(), GetCmdQueryConsensusState(), GetCmdQueryHeader(), GetCmdSelfConsensusState(), diff --git a/modules/core/02-client/client/cli/query.go b/modules/core/02-client/client/cli/query.go index d5e18679a28..56093a8368f 100644 --- a/modules/core/02-client/client/cli/query.go +++ b/modules/core/02-client/client/cli/query.go @@ -164,6 +164,49 @@ func GetCmdQueryConsensusStates() *cobra.Command { return cmd } +// GetCmdQueryConsensusStateHeights defines the command to query the heights of all client consensus states associated with the +// provided client ID. +func GetCmdQueryConsensusStateHeights() *cobra.Command { + cmd := &cobra.Command{ + Use: "consensus-state-heights [client-id]", + Short: "Query the heights of all consensus states of a client.", + Long: "Query the heights of all consensus states associated with the provided client ID.", + Example: fmt.Sprintf("%s query %s %s consensus-state-heights [client-id]", version.AppName, host.ModuleName, types.SubModuleName), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + clientID := args[0] + + queryClient := types.NewQueryClient(clientCtx) + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryConsensusStateHeightsRequest{ + ClientId: clientID, + Pagination: pageReq, + } + + res, err := queryClient.ConsensusStateHeights(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "consensus state heights") + + return cmd +} + // GetCmdQueryConsensusState defines the command to query the consensus state of // the chain as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-002-client-semantics#query func GetCmdQueryConsensusState() *cobra.Command { diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index 555994e0a88..bc7ce9f8241 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -186,6 +186,46 @@ func (q Keeper) ConsensusStates(c context.Context, req *types.QueryConsensusStat }, nil } +// ConsensusStateHeights implements the Query/ConsensusStateHeights gRPC method +func (q Keeper) ConsensusStateHeights(c context.Context, req *types.QueryConsensusStateHeightsRequest) (*types.QueryConsensusStateHeightsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + if err := host.ClientIdentifierValidator(req.ClientId); err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + ctx := sdk.UnwrapSDKContext(c) + + var consensusStateHeights []types.Height + store := prefix.NewStore(ctx.KVStore(q.storeKey), host.FullClientKey(req.ClientId, []byte(fmt.Sprintf("%s/", host.KeyConsensusStatePrefix)))) + + pageRes, err := query.FilteredPaginate(store, req.Pagination, func(key, _ []byte, accumulate bool) (bool, error) { + // filter any metadata stored under consensus state key + if bytes.Contains(key, []byte("/")) { + return false, nil + } + + height, err := types.ParseHeight(string(key)) + if err != nil { + return false, err + } + + consensusStateHeights = append(consensusStateHeights, height) + return true, nil + }) + + if err != nil { + return nil, err + } + + return &types.QueryConsensusStateHeightsResponse{ + ConsensusStateHeights: consensusStateHeights, + Pagination: pageRes, + }, nil +} + // ClientStatus implements the Query/ClientStatus gRPC method func (q Keeper) ClientStatus(c context.Context, req *types.QueryClientStatusRequest) (*types.QueryClientStatusResponse, error) { if req == nil { diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index 7506291f4ae..e6d3a1ae1ba 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -2,7 +2,6 @@ package keeper_test import ( "fmt" - "time" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,7 +10,6 @@ import ( "google.golang.org/grpc/metadata" "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v3/modules/core/exported" ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" @@ -299,7 +297,7 @@ func (suite *KeeperTestSuite) TestQueryConsensusState() { func (suite *KeeperTestSuite) TestQueryConsensusStates() { var ( req *types.QueryConsensusStatesRequest - expConsensusStates = []types.ConsensusStateWithHeight{} + expConsensusStates []types.ConsensusStateWithHeight ) testCases := []struct { @@ -308,14 +306,7 @@ func (suite *KeeperTestSuite) TestQueryConsensusStates() { expPass bool }{ { - "invalid client identifier", - func() { - req = &types.QueryConsensusStatesRequest{} - }, - false, - }, - { - "empty pagination", + "success: without pagination", func() { req = &types.QueryConsensusStatesRequest{ ClientId: testClientID, @@ -339,29 +330,30 @@ func (suite *KeeperTestSuite) TestQueryConsensusStates() { { "success", func() { - cs := ibctmtypes.NewConsensusState( - suite.consensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte("hash1")), nil, - ) - cs2 := ibctmtypes.NewConsensusState( - suite.consensusState.Timestamp.Add(time.Second), commitmenttypes.NewMerkleRoot([]byte("hash2")), nil, - ) - - clientState := ibctmtypes.NewClientState( - testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false, - ) - - // Use CreateClient to ensure that processedTime metadata gets stored. - clientId, err := suite.keeper.CreateClient(suite.ctx, clientState, cs) + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(path) + + height1 := path.EndpointA.GetClientState().GetLatestHeight().(types.Height) + expConsensusStates = append( + expConsensusStates, + types.NewConsensusStateWithHeight( + height1, + path.EndpointA.GetConsensusState(height1), + )) + + err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - suite.keeper.SetClientConsensusState(suite.ctx, clientId, testClientHeight.Increment(), cs2) - // order is swapped because the res is sorted by client id - expConsensusStates = []types.ConsensusStateWithHeight{ - types.NewConsensusStateWithHeight(testClientHeight, cs), - types.NewConsensusStateWithHeight(testClientHeight.Increment().(types.Height), cs2), - } + height2 := path.EndpointA.GetClientState().GetLatestHeight().(types.Height) + expConsensusStates = append( + expConsensusStates, + types.NewConsensusStateWithHeight( + height2, + path.EndpointA.GetConsensusState(height2), + )) + req = &types.QueryConsensusStatesRequest{ - ClientId: clientId, + ClientId: path.EndpointA.ClientID, Pagination: &query.PageRequest{ Limit: 3, CountTotal: true, @@ -370,6 +362,13 @@ func (suite *KeeperTestSuite) TestQueryConsensusStates() { }, true, }, + { + "invalid client identifier", + func() { + req = &types.QueryConsensusStatesRequest{} + }, + false, + }, } for _, tc := range testCases { @@ -377,9 +376,8 @@ func (suite *KeeperTestSuite) TestQueryConsensusStates() { suite.SetupTest() // reset tc.malleate() - ctx := sdk.WrapSDKContext(suite.ctx) - - res, err := suite.queryClient.ConsensusStates(ctx, req) + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.chainA.QueryServer.ConsensusStates(ctx, req) if tc.expPass { suite.Require().NoError(err) @@ -400,6 +398,94 @@ func (suite *KeeperTestSuite) TestQueryConsensusStates() { } } +func (suite *KeeperTestSuite) TestQueryConsensusStateHeights() { + var ( + req *types.QueryConsensusStateHeightsRequest + expConsensusStateHeights []types.Height + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "success: without pagination", + func() { + req = &types.QueryConsensusStateHeightsRequest{ + ClientId: testClientID, + } + }, + true, + }, + { + "success: response contains no results", + func() { + req = &types.QueryConsensusStateHeightsRequest{ + ClientId: testClientID, + Pagination: &query.PageRequest{ + Limit: 3, + CountTotal: true, + }, + } + }, + true, + }, + { + "success: returns consensus heights", + func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.SetupClients(path) + + expConsensusStateHeights = append(expConsensusStateHeights, path.EndpointA.GetClientState().GetLatestHeight().(types.Height)) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + expConsensusStateHeights = append(expConsensusStateHeights, path.EndpointA.GetClientState().GetLatestHeight().(types.Height)) + + req = &types.QueryConsensusStateHeightsRequest{ + ClientId: path.EndpointA.ClientID, + Pagination: &query.PageRequest{ + Limit: 3, + CountTotal: true, + }, + } + }, + true, + }, + { + "invalid client identifier", + func() { + req = &types.QueryConsensusStateHeightsRequest{} + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.chainA.QueryServer.ConsensusStateHeights(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + suite.Require().Equal(len(expConsensusStateHeights), len(res.ConsensusStateHeights)) + for i := range expConsensusStateHeights { + suite.Require().NotNil(res.ConsensusStateHeights[i]) + suite.Require().Equal(expConsensusStateHeights[i], res.ConsensusStateHeights[i]) + } + } else { + suite.Require().Error(err) + } + }) + } +} + func (suite *KeeperTestSuite) TestQueryClientStatus() { var req *types.QueryClientStatusRequest diff --git a/modules/core/02-client/types/query.pb.go b/modules/core/02-client/types/query.pb.go index 7ea1d377be6..f4c033bfea3 100644 --- a/modules/core/02-client/types/query.pb.go +++ b/modules/core/02-client/types/query.pb.go @@ -500,6 +500,118 @@ func (m *QueryConsensusStatesResponse) GetPagination() *query.PageResponse { return nil } +// QueryConsensusStateHeightsRequest is the request type for Query/ConsensusStateHeights +// RPC method. +type QueryConsensusStateHeightsRequest struct { + // client identifier + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + // pagination request + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryConsensusStateHeightsRequest) Reset() { *m = QueryConsensusStateHeightsRequest{} } +func (m *QueryConsensusStateHeightsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryConsensusStateHeightsRequest) ProtoMessage() {} +func (*QueryConsensusStateHeightsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_dc42cdfd1d52d76e, []int{8} +} +func (m *QueryConsensusStateHeightsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsensusStateHeightsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsensusStateHeightsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsensusStateHeightsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsensusStateHeightsRequest.Merge(m, src) +} +func (m *QueryConsensusStateHeightsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryConsensusStateHeightsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsensusStateHeightsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsensusStateHeightsRequest proto.InternalMessageInfo + +func (m *QueryConsensusStateHeightsRequest) GetClientId() string { + if m != nil { + return m.ClientId + } + return "" +} + +func (m *QueryConsensusStateHeightsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryConsensusStateHeightsResponse is the response type for the +// Query/ConsensusStateHeights RPC method +type QueryConsensusStateHeightsResponse struct { + // consensus state heights + ConsensusStateHeights []Height `protobuf:"bytes,1,rep,name=consensus_state_heights,json=consensusStateHeights,proto3" json:"consensus_state_heights"` + // pagination response + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryConsensusStateHeightsResponse) Reset() { *m = QueryConsensusStateHeightsResponse{} } +func (m *QueryConsensusStateHeightsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryConsensusStateHeightsResponse) ProtoMessage() {} +func (*QueryConsensusStateHeightsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_dc42cdfd1d52d76e, []int{9} +} +func (m *QueryConsensusStateHeightsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryConsensusStateHeightsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryConsensusStateHeightsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryConsensusStateHeightsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryConsensusStateHeightsResponse.Merge(m, src) +} +func (m *QueryConsensusStateHeightsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryConsensusStateHeightsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryConsensusStateHeightsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryConsensusStateHeightsResponse proto.InternalMessageInfo + +func (m *QueryConsensusStateHeightsResponse) GetConsensusStateHeights() []Height { + if m != nil { + return m.ConsensusStateHeights + } + return nil +} + +func (m *QueryConsensusStateHeightsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + // QueryClientStatusRequest is the request type for the Query/ClientStatus RPC // method type QueryClientStatusRequest struct { @@ -511,7 +623,7 @@ func (m *QueryClientStatusRequest) Reset() { *m = QueryClientStatusReque func (m *QueryClientStatusRequest) String() string { return proto.CompactTextString(m) } func (*QueryClientStatusRequest) ProtoMessage() {} func (*QueryClientStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_dc42cdfd1d52d76e, []int{8} + return fileDescriptor_dc42cdfd1d52d76e, []int{10} } func (m *QueryClientStatusRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -557,7 +669,7 @@ func (m *QueryClientStatusResponse) Reset() { *m = QueryClientStatusResp func (m *QueryClientStatusResponse) String() string { return proto.CompactTextString(m) } func (*QueryClientStatusResponse) ProtoMessage() {} func (*QueryClientStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_dc42cdfd1d52d76e, []int{9} + return fileDescriptor_dc42cdfd1d52d76e, []int{11} } func (m *QueryClientStatusResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -602,7 +714,7 @@ func (m *QueryClientParamsRequest) Reset() { *m = QueryClientParamsReque func (m *QueryClientParamsRequest) String() string { return proto.CompactTextString(m) } func (*QueryClientParamsRequest) ProtoMessage() {} func (*QueryClientParamsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_dc42cdfd1d52d76e, []int{10} + return fileDescriptor_dc42cdfd1d52d76e, []int{12} } func (m *QueryClientParamsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -642,7 +754,7 @@ func (m *QueryClientParamsResponse) Reset() { *m = QueryClientParamsResp func (m *QueryClientParamsResponse) String() string { return proto.CompactTextString(m) } func (*QueryClientParamsResponse) ProtoMessage() {} func (*QueryClientParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_dc42cdfd1d52d76e, []int{11} + return fileDescriptor_dc42cdfd1d52d76e, []int{13} } func (m *QueryClientParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -687,7 +799,7 @@ func (m *QueryUpgradedClientStateRequest) Reset() { *m = QueryUpgradedCl func (m *QueryUpgradedClientStateRequest) String() string { return proto.CompactTextString(m) } func (*QueryUpgradedClientStateRequest) ProtoMessage() {} func (*QueryUpgradedClientStateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_dc42cdfd1d52d76e, []int{12} + return fileDescriptor_dc42cdfd1d52d76e, []int{14} } func (m *QueryUpgradedClientStateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -727,7 +839,7 @@ func (m *QueryUpgradedClientStateResponse) Reset() { *m = QueryUpgradedC func (m *QueryUpgradedClientStateResponse) String() string { return proto.CompactTextString(m) } func (*QueryUpgradedClientStateResponse) ProtoMessage() {} func (*QueryUpgradedClientStateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_dc42cdfd1d52d76e, []int{13} + return fileDescriptor_dc42cdfd1d52d76e, []int{15} } func (m *QueryUpgradedClientStateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -772,7 +884,7 @@ func (m *QueryUpgradedConsensusStateRequest) Reset() { *m = QueryUpgrade func (m *QueryUpgradedConsensusStateRequest) String() string { return proto.CompactTextString(m) } func (*QueryUpgradedConsensusStateRequest) ProtoMessage() {} func (*QueryUpgradedConsensusStateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_dc42cdfd1d52d76e, []int{14} + return fileDescriptor_dc42cdfd1d52d76e, []int{16} } func (m *QueryUpgradedConsensusStateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -812,7 +924,7 @@ func (m *QueryUpgradedConsensusStateResponse) Reset() { *m = QueryUpgrad func (m *QueryUpgradedConsensusStateResponse) String() string { return proto.CompactTextString(m) } func (*QueryUpgradedConsensusStateResponse) ProtoMessage() {} func (*QueryUpgradedConsensusStateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_dc42cdfd1d52d76e, []int{15} + return fileDescriptor_dc42cdfd1d52d76e, []int{17} } func (m *QueryUpgradedConsensusStateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -857,6 +969,8 @@ func init() { proto.RegisterType((*QueryConsensusStateResponse)(nil), "ibc.core.client.v1.QueryConsensusStateResponse") proto.RegisterType((*QueryConsensusStatesRequest)(nil), "ibc.core.client.v1.QueryConsensusStatesRequest") proto.RegisterType((*QueryConsensusStatesResponse)(nil), "ibc.core.client.v1.QueryConsensusStatesResponse") + proto.RegisterType((*QueryConsensusStateHeightsRequest)(nil), "ibc.core.client.v1.QueryConsensusStateHeightsRequest") + proto.RegisterType((*QueryConsensusStateHeightsResponse)(nil), "ibc.core.client.v1.QueryConsensusStateHeightsResponse") proto.RegisterType((*QueryClientStatusRequest)(nil), "ibc.core.client.v1.QueryClientStatusRequest") proto.RegisterType((*QueryClientStatusResponse)(nil), "ibc.core.client.v1.QueryClientStatusResponse") proto.RegisterType((*QueryClientParamsRequest)(nil), "ibc.core.client.v1.QueryClientParamsRequest") @@ -870,69 +984,74 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/query.proto", fileDescriptor_dc42cdfd1d52d76e) } var fileDescriptor_dc42cdfd1d52d76e = []byte{ - // 983 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0xcd, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xa4, 0x69, 0xd4, 0x3e, 0xbb, 0x09, 0x9a, 0xa6, 0xa9, 0xbb, 0x2d, 0x8e, 0xbb, 0x41, - 0x34, 0x2d, 0xc9, 0x4e, 0xe2, 0x40, 0xd3, 0x0b, 0x07, 0x52, 0xa9, 0xb4, 0x97, 0x52, 0x16, 0x21, - 0x24, 0x24, 0x14, 0xed, 0xae, 0x27, 0x9b, 0x95, 0xec, 0x1d, 0xd7, 0xb3, 0x6b, 0x29, 0xaa, 0x72, - 0xa0, 0x47, 0x4e, 0x48, 0x48, 0x5c, 0x91, 0x38, 0x72, 0xa8, 0x38, 0x20, 0x71, 0xe5, 0x84, 0x7a, - 0xac, 0x04, 0x07, 0x4e, 0x04, 0x25, 0xfc, 0x21, 0x68, 0x67, 0x66, 0xe3, 0x1d, 0x7b, 0x8c, 0xd7, - 0x88, 0xde, 0x76, 0xde, 0xe7, 0xef, 0x7d, 0xcc, 0x6f, 0xb4, 0x50, 0x8f, 0xfc, 0x80, 0x04, 0xac, - 0x47, 0x49, 0xd0, 0x8e, 0x68, 0x9c, 0x90, 0xfe, 0x16, 0x79, 0x9a, 0xd2, 0xde, 0xa1, 0xd3, 0xed, - 0xb1, 0x84, 0x61, 0x1c, 0xf9, 0x81, 0x93, 0xe9, 0x1d, 0xa9, 0x77, 0xfa, 0x5b, 0xd6, 0x9d, 0x80, - 0xf1, 0x0e, 0xe3, 0xc4, 0xf7, 0x38, 0x95, 0xc6, 0xa4, 0xbf, 0xe5, 0xd3, 0xc4, 0xdb, 0x22, 0x5d, - 0x2f, 0x8c, 0x62, 0x2f, 0x89, 0x58, 0x2c, 0xfd, 0xad, 0x15, 0x43, 0x7c, 0x15, 0x49, 0x1a, 0x5c, - 0x0b, 0x19, 0x0b, 0xdb, 0x94, 0x88, 0x93, 0x9f, 0xee, 0x13, 0x2f, 0x56, 0xb9, 0xad, 0x1b, 0x4a, - 0xe5, 0x75, 0x23, 0xe2, 0xc5, 0x31, 0x4b, 0x44, 0x60, 0xae, 0xb4, 0x4b, 0x21, 0x0b, 0x99, 0xf8, - 0x24, 0xd9, 0x97, 0x94, 0xda, 0x77, 0xe1, 0xea, 0xc7, 0x19, 0xa2, 0xfb, 0x22, 0xc7, 0x27, 0x89, - 0x97, 0x50, 0x97, 0x3e, 0x4d, 0x29, 0x4f, 0xf0, 0x75, 0xb8, 0x28, 0x33, 0xef, 0x45, 0xad, 0x1a, - 0x6a, 0xa0, 0xb5, 0x8b, 0xee, 0x05, 0x29, 0x78, 0xd4, 0xb2, 0x5f, 0x20, 0xa8, 0x8d, 0x3a, 0xf2, - 0x2e, 0x8b, 0x39, 0xc5, 0x3b, 0x50, 0x55, 0x9e, 0x3c, 0x93, 0x0b, 0xe7, 0x4a, 0x73, 0xc9, 0x91, - 0xf8, 0x9c, 0x1c, 0xba, 0xf3, 0x41, 0x7c, 0xe8, 0x56, 0x82, 0x41, 0x00, 0xbc, 0x04, 0xe7, 0xbb, - 0x3d, 0xc6, 0xf6, 0x6b, 0xb3, 0x0d, 0xb4, 0x56, 0x75, 0xe5, 0x01, 0xdf, 0x87, 0xaa, 0xf8, 0xd8, - 0x3b, 0xa0, 0x51, 0x78, 0x90, 0xd4, 0xce, 0x89, 0x70, 0x96, 0x33, 0xda, 0x6a, 0xe7, 0xa1, 0xb0, - 0xd8, 0x9d, 0x7b, 0xf9, 0xe7, 0xca, 0x8c, 0x5b, 0x11, 0x5e, 0x52, 0x64, 0xfb, 0xa3, 0x78, 0x79, - 0x5e, 0xe9, 0x03, 0x80, 0xc1, 0x20, 0x14, 0xda, 0xb7, 0x1d, 0x39, 0x35, 0x27, 0x9b, 0x9a, 0x23, - 0x47, 0xac, 0xa6, 0xe6, 0x3c, 0xf1, 0xc2, 0xbc, 0x4b, 0x6e, 0xc1, 0xd3, 0xfe, 0x1d, 0xc1, 0x35, - 0x43, 0x12, 0xd5, 0x95, 0x18, 0x2e, 0x15, 0xbb, 0xc2, 0x6b, 0xa8, 0x71, 0x6e, 0xad, 0xd2, 0xbc, - 0x6d, 0xaa, 0xe3, 0x51, 0x8b, 0xc6, 0x49, 0xb4, 0x1f, 0xd1, 0x56, 0x21, 0xd4, 0x6e, 0x3d, 0x2b, - 0xeb, 0x87, 0xe3, 0x95, 0x65, 0xa3, 0x9a, 0xbb, 0xd5, 0x42, 0x2f, 0x39, 0xfe, 0x50, 0xab, 0x6a, - 0x56, 0x54, 0x75, 0x6b, 0x62, 0x55, 0x12, 0xac, 0x56, 0xd6, 0x8f, 0x08, 0x2c, 0x59, 0x56, 0xa6, - 0x8a, 0x79, 0xca, 0x4b, 0xef, 0x09, 0xbe, 0x05, 0x8b, 0x3d, 0xda, 0x8f, 0x78, 0xc4, 0xe2, 0xbd, - 0x38, 0xed, 0xf8, 0xb4, 0x27, 0x90, 0xcc, 0xb9, 0x0b, 0xb9, 0xf8, 0xb1, 0x90, 0x6a, 0x86, 0x85, - 0x39, 0x17, 0x0c, 0xe5, 0x20, 0xf1, 0x2a, 0x5c, 0x6a, 0x67, 0xf5, 0x25, 0xb9, 0xd9, 0x5c, 0x03, - 0xad, 0x5d, 0x70, 0xab, 0x52, 0xa8, 0xa6, 0xfd, 0x33, 0x82, 0xeb, 0x46, 0xc8, 0x6a, 0x16, 0xef, - 0xc3, 0x62, 0x90, 0x6b, 0x4a, 0x2c, 0xe9, 0x42, 0xa0, 0x85, 0x79, 0x9d, 0x7b, 0xfa, 0xdc, 0x8c, - 0x9c, 0x97, 0xea, 0xf6, 0x03, 0xc3, 0xc8, 0xff, 0xcb, 0x22, 0xff, 0x8a, 0xe0, 0x86, 0x19, 0x84, - 0xea, 0xdf, 0x17, 0xf0, 0xc6, 0x50, 0xff, 0xf2, 0x75, 0x5e, 0x37, 0x95, 0xab, 0x87, 0xf9, 0x2c, - 0x4a, 0x0e, 0xb4, 0x06, 0x2c, 0xea, 0xed, 0xfd, 0x1f, 0x57, 0x77, 0x67, 0xe4, 0xd6, 0xa7, 0xa5, - 0x3a, 0x69, 0x6f, 0x8f, 0xdc, 0xe4, 0x74, 0x50, 0xfd, 0x32, 0xcc, 0x73, 0x21, 0x51, 0x6e, 0xea, - 0x64, 0x5b, 0x5a, 0xb6, 0x27, 0x5e, 0xcf, 0xeb, 0xe4, 0xd9, 0xec, 0x8f, 0xb4, 0x80, 0xb9, 0x4e, - 0x05, 0x6c, 0xc2, 0x7c, 0x57, 0x48, 0xd4, 0x16, 0x1a, 0x77, 0x46, 0xf9, 0x28, 0x4b, 0xfb, 0x26, - 0xac, 0x88, 0x80, 0x9f, 0x76, 0xc3, 0x9e, 0xd7, 0xd2, 0x98, 0x20, 0xcf, 0xd9, 0x86, 0xc6, 0x78, - 0x13, 0x95, 0xfa, 0x21, 0x5c, 0x49, 0x95, 0x7a, 0xaf, 0x34, 0x69, 0x5f, 0x4e, 0x47, 0x23, 0xda, - 0x6f, 0x81, 0xad, 0x67, 0x33, 0xb1, 0x85, 0x9d, 0xc2, 0xea, 0xbf, 0x5a, 0x29, 0x58, 0x8f, 0xa1, - 0x36, 0x80, 0x35, 0xc5, 0x4d, 0x5d, 0x4e, 0x8d, 0x71, 0x9b, 0x5f, 0x56, 0xe0, 0xbc, 0xc8, 0x8b, - 0xbf, 0x43, 0x50, 0x29, 0xc0, 0xc6, 0xef, 0x98, 0x7a, 0x3d, 0xe6, 0x4d, 0xb4, 0xd6, 0xcb, 0x19, - 0xcb, 0x22, 0xec, 0xf7, 0x9e, 0xff, 0xf6, 0xf7, 0x37, 0xb3, 0x04, 0x6f, 0x90, 0xb1, 0xaf, 0xba, - 0xba, 0x3c, 0xe4, 0xd9, 0xd9, 0x2a, 0x1e, 0xe1, 0x6f, 0x11, 0x54, 0x8b, 0xbc, 0x8e, 0x4b, 0x65, - 0xcd, 0x37, 0xcd, 0xda, 0x28, 0x69, 0xad, 0x40, 0xde, 0x16, 0x20, 0x57, 0xf1, 0xcd, 0x89, 0x20, - 0xf1, 0x31, 0x82, 0x05, 0xbd, 0xaf, 0xd8, 0x19, 0x9f, 0xcc, 0x34, 0x7e, 0x8b, 0x94, 0xb6, 0x57, - 0xf0, 0xda, 0x02, 0xde, 0x3e, 0x6e, 0x19, 0xe1, 0x0d, 0x71, 0x50, 0xb1, 0x8d, 0x24, 0x7f, 0x37, - 0xc8, 0xb3, 0xa1, 0x17, 0xe8, 0x88, 0x48, 0x82, 0x2e, 0x28, 0xa4, 0xe0, 0x08, 0xbf, 0x40, 0xb0, - 0x38, 0xc4, 0x79, 0xb8, 0x2c, 0xe4, 0xb3, 0x01, 0x6c, 0x96, 0x77, 0x50, 0x45, 0xde, 0x13, 0x45, - 0x36, 0xf1, 0xe6, 0xb4, 0x45, 0xe2, 0xef, 0xb5, 0x5d, 0x49, 0xcb, 0xed, 0x4a, 0x3a, 0xd5, 0xae, - 0x0c, 0x88, 0xaf, 0xf4, 0x42, 0xa7, 0x3a, 0xc8, 0xaf, 0xce, 0x40, 0x4a, 0x0e, 0x9b, 0x08, 0x52, - 0xa3, 0xce, 0x89, 0x20, 0x75, 0x32, 0xb5, 0xdf, 0x14, 0x20, 0xaf, 0xe2, 0x2b, 0x12, 0xe4, 0x19, - 0x3e, 0xc9, 0x9b, 0xf8, 0x27, 0x04, 0x97, 0x0d, 0x84, 0x88, 0xb7, 0xc7, 0x66, 0x19, 0xcf, 0xb0, - 0xd6, 0xbb, 0xd3, 0x39, 0x29, 0x84, 0x4d, 0x81, 0x70, 0x1d, 0xdf, 0x31, 0xb5, 0xd1, 0xc8, 0xc6, - 0x1c, 0xff, 0x82, 0x60, 0xd9, 0xcc, 0x99, 0xf8, 0xee, 0x64, 0x10, 0xc6, 0xbb, 0xb8, 0x33, 0xb5, - 0x5f, 0x99, 0x35, 0x18, 0x47, 0xdb, 0x7c, 0xd7, 0x7d, 0x79, 0x52, 0x47, 0xaf, 0x4e, 0xea, 0xe8, - 0xaf, 0x93, 0x3a, 0xfa, 0xfa, 0xb4, 0x3e, 0xf3, 0xea, 0xb4, 0x3e, 0xf3, 0xc7, 0x69, 0x7d, 0xe6, - 0xf3, 0x7b, 0x61, 0x94, 0x1c, 0xa4, 0xbe, 0x13, 0xb0, 0x0e, 0x51, 0x3f, 0x4b, 0x91, 0x1f, 0x6c, - 0x84, 0x8c, 0xf4, 0xb7, 0x49, 0x87, 0xb5, 0xd2, 0x36, 0xe5, 0x32, 0xcf, 0x66, 0x73, 0x43, 0xa5, - 0x4a, 0x0e, 0xbb, 0x94, 0xfb, 0xf3, 0x82, 0xfd, 0xb7, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0xb0, - 0x84, 0x64, 0x2c, 0x98, 0x0d, 0x00, 0x00, + // 1057 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcf, 0x6f, 0x1b, 0x45, + 0x14, 0xce, 0xa4, 0x69, 0xd4, 0x3e, 0xbb, 0x09, 0x9a, 0xe6, 0x87, 0xbb, 0x2d, 0x8e, 0xb3, 0x41, + 0x34, 0x2d, 0xc9, 0x4e, 0xe2, 0xd0, 0x24, 0x42, 0x42, 0x82, 0x54, 0x2a, 0xed, 0xa5, 0x94, 0x45, + 0x08, 0x84, 0x84, 0xa2, 0xdd, 0xf5, 0x66, 0xb3, 0x92, 0xbd, 0xe3, 0x7a, 0x76, 0x2d, 0x45, 0x55, + 0x2e, 0x3d, 0x21, 0x4e, 0x48, 0x48, 0x5c, 0x91, 0x38, 0x72, 0xa8, 0x38, 0x20, 0x71, 0xe5, 0x04, + 0x39, 0x70, 0xa8, 0x04, 0x07, 0x4e, 0x14, 0x25, 0xfc, 0x21, 0xc8, 0x33, 0xb3, 0xf6, 0x8e, 0x3d, + 0xae, 0xd7, 0x28, 0x70, 0xdb, 0x9d, 0x79, 0x3f, 0xbe, 0xef, 0x7b, 0xcf, 0xef, 0xad, 0xa1, 0x1c, + 0xba, 0x1e, 0xf1, 0x68, 0xcb, 0x27, 0x5e, 0x3d, 0xf4, 0xa3, 0x98, 0xb4, 0x37, 0xc9, 0xe3, 0xc4, + 0x6f, 0x1d, 0x59, 0xcd, 0x16, 0x8d, 0x29, 0xc6, 0xa1, 0xeb, 0x59, 0x9d, 0x7b, 0x4b, 0xdc, 0x5b, + 0xed, 0x4d, 0xe3, 0xb6, 0x47, 0x59, 0x83, 0x32, 0xe2, 0x3a, 0xcc, 0x17, 0xc6, 0xa4, 0xbd, 0xe9, + 0xfa, 0xb1, 0xb3, 0x49, 0x9a, 0x4e, 0x10, 0x46, 0x4e, 0x1c, 0xd2, 0x48, 0xf8, 0x1b, 0x4b, 0x9a, + 0xf8, 0x32, 0x92, 0x30, 0xb8, 0x16, 0x50, 0x1a, 0xd4, 0x7d, 0xc2, 0xdf, 0xdc, 0xe4, 0x80, 0x38, + 0x91, 0xcc, 0x6d, 0xdc, 0x90, 0x57, 0x4e, 0x33, 0x24, 0x4e, 0x14, 0xd1, 0x98, 0x07, 0x66, 0xf2, + 0x76, 0x2e, 0xa0, 0x01, 0xe5, 0x8f, 0xa4, 0xf3, 0x24, 0x4e, 0xcd, 0x6d, 0x58, 0xfc, 0xa0, 0x83, + 0xe8, 0x2e, 0xcf, 0xf1, 0x61, 0xec, 0xc4, 0xbe, 0xed, 0x3f, 0x4e, 0x7c, 0x16, 0xe3, 0xeb, 0x70, + 0x59, 0x64, 0xde, 0x0f, 0x6b, 0x25, 0x54, 0x41, 0xab, 0x97, 0xed, 0x4b, 0xe2, 0xe0, 0x41, 0xcd, + 0x7c, 0x86, 0xa0, 0x34, 0xe8, 0xc8, 0x9a, 0x34, 0x62, 0x3e, 0xde, 0x81, 0xa2, 0xf4, 0x64, 0x9d, + 0x73, 0xee, 0x5c, 0xa8, 0xce, 0x59, 0x02, 0x9f, 0x95, 0x42, 0xb7, 0xde, 0x8d, 0x8e, 0xec, 0x82, + 0xd7, 0x0b, 0x80, 0xe7, 0xe0, 0x62, 0xb3, 0x45, 0xe9, 0x41, 0x69, 0xb2, 0x82, 0x56, 0x8b, 0xb6, + 0x78, 0xc1, 0x77, 0xa1, 0xc8, 0x1f, 0xf6, 0x0f, 0xfd, 0x30, 0x38, 0x8c, 0x4b, 0x17, 0x78, 0x38, + 0xc3, 0x1a, 0x94, 0xda, 0xba, 0xcf, 0x2d, 0xf6, 0xa6, 0x4e, 0xfe, 0x5c, 0x9a, 0xb0, 0x0b, 0xdc, + 0x4b, 0x1c, 0x99, 0xee, 0x20, 0x5e, 0x96, 0x32, 0xbd, 0x07, 0xd0, 0x2b, 0x84, 0x44, 0xfb, 0xba, + 0x25, 0xaa, 0x66, 0x75, 0xaa, 0x66, 0x89, 0x12, 0xcb, 0xaa, 0x59, 0x8f, 0x9c, 0x20, 0x55, 0xc9, + 0xce, 0x78, 0x9a, 0xbf, 0x23, 0xb8, 0xa6, 0x49, 0x22, 0x55, 0x89, 0xe0, 0x4a, 0x56, 0x15, 0x56, + 0x42, 0x95, 0x0b, 0xab, 0x85, 0xea, 0x2d, 0x1d, 0x8f, 0x07, 0x35, 0x3f, 0x8a, 0xc3, 0x83, 0xd0, + 0xaf, 0x65, 0x42, 0xed, 0x95, 0x3b, 0xb4, 0xbe, 0x7b, 0xb1, 0xb4, 0xa0, 0xbd, 0x66, 0x76, 0x31, + 0xa3, 0x25, 0xc3, 0xef, 0x29, 0xac, 0x26, 0x39, 0xab, 0x9b, 0x23, 0x59, 0x09, 0xb0, 0x0a, 0xad, + 0xef, 0x11, 0x18, 0x82, 0x56, 0xe7, 0x2a, 0x62, 0x09, 0xcb, 0xdd, 0x27, 0xf8, 0x26, 0xcc, 0xb6, + 0xfc, 0x76, 0xc8, 0x42, 0x1a, 0xed, 0x47, 0x49, 0xc3, 0xf5, 0x5b, 0x1c, 0xc9, 0x94, 0x3d, 0x93, + 0x1e, 0x3f, 0xe4, 0xa7, 0x8a, 0x61, 0xa6, 0xce, 0x19, 0x43, 0x51, 0x48, 0xbc, 0x02, 0x57, 0xea, + 0x1d, 0x7e, 0x71, 0x6a, 0x36, 0x55, 0x41, 0xab, 0x97, 0xec, 0xa2, 0x38, 0x94, 0xd5, 0xfe, 0x11, + 0xc1, 0x75, 0x2d, 0x64, 0x59, 0x8b, 0xb7, 0x61, 0xd6, 0x4b, 0x6f, 0x72, 0x34, 0xe9, 0x8c, 0xa7, + 0x84, 0xf9, 0x2f, 0xfb, 0xf4, 0xa9, 0x1e, 0x39, 0xcb, 0xa5, 0xf6, 0x3d, 0x4d, 0xc9, 0xff, 0x4d, + 0x23, 0xff, 0x8c, 0xe0, 0x86, 0x1e, 0x84, 0xd4, 0xef, 0x33, 0x78, 0xa5, 0x4f, 0xbf, 0xb4, 0x9d, + 0xd7, 0x74, 0x74, 0xd5, 0x30, 0x1f, 0x87, 0xf1, 0xa1, 0x22, 0xc0, 0xac, 0x2a, 0xef, 0x39, 0xb6, + 0xee, 0xe7, 0x08, 0x96, 0x35, 0x44, 0x44, 0xf6, 0xff, 0x57, 0xd3, 0x5f, 0x10, 0x98, 0x2f, 0x83, + 0x22, 0x95, 0xfd, 0x04, 0x16, 0xfb, 0x94, 0x95, 0xed, 0x94, 0x0a, 0x3c, 0xba, 0x9f, 0xe6, 0x3d, + 0x5d, 0x86, 0xf3, 0x13, 0x75, 0x67, 0x60, 0x94, 0x26, 0xb9, 0xa4, 0x34, 0xb7, 0x06, 0xc6, 0x63, + 0xd2, 0x23, 0xbe, 0x00, 0xd3, 0x8c, 0x9f, 0x48, 0x37, 0xf9, 0x66, 0x1a, 0x4a, 0xb6, 0x47, 0x4e, + 0xcb, 0x69, 0xa4, 0xd9, 0xcc, 0xf7, 0x95, 0x80, 0xe9, 0x9d, 0x0c, 0x58, 0x85, 0xe9, 0x26, 0x3f, + 0x91, 0x3f, 0x6d, 0xad, 0x70, 0xd2, 0x47, 0x5a, 0x9a, 0xcb, 0xb0, 0xc4, 0x03, 0x7e, 0xd4, 0x0c, + 0x5a, 0x4e, 0x4d, 0x19, 0xaf, 0x69, 0xce, 0x3a, 0x54, 0x86, 0x9b, 0xc8, 0xd4, 0xf7, 0x61, 0x3e, + 0x91, 0xd7, 0xfb, 0xb9, 0x37, 0xe1, 0xd5, 0x64, 0x30, 0xa2, 0xf9, 0x9a, 0x6c, 0x9a, 0x6e, 0x36, + 0xdd, 0x08, 0x36, 0x13, 0x58, 0x79, 0xa9, 0x95, 0x84, 0xf5, 0x10, 0x4a, 0x3d, 0x58, 0x63, 0x8c, + 0xbf, 0x85, 0x44, 0x1b, 0xb7, 0xfa, 0x6b, 0x11, 0x2e, 0xf2, 0xbc, 0xf8, 0x1b, 0x04, 0x85, 0x0c, + 0x6c, 0xfc, 0x86, 0x4e, 0xeb, 0x21, 0x1f, 0x1a, 0xc6, 0x5a, 0x3e, 0x63, 0x41, 0xc2, 0xbc, 0xf3, + 0xf4, 0xb7, 0xbf, 0xbf, 0x9a, 0x24, 0x78, 0x9d, 0x0c, 0xfd, 0x54, 0x92, 0x13, 0x89, 0x3c, 0xe9, + 0xb6, 0xe2, 0x31, 0xfe, 0x1a, 0x41, 0x31, 0xbb, 0x2c, 0x71, 0xae, 0xac, 0x69, 0xa7, 0x19, 0xeb, + 0x39, 0xad, 0x25, 0xc8, 0x5b, 0x1c, 0xe4, 0x0a, 0x5e, 0x1e, 0x09, 0x12, 0xbf, 0x40, 0x30, 0xa3, + 0xea, 0x8a, 0xad, 0xe1, 0xc9, 0x74, 0xe5, 0x37, 0x48, 0x6e, 0x7b, 0x09, 0xaf, 0xce, 0xe1, 0x1d, + 0xe0, 0x9a, 0x16, 0x5e, 0xdf, 0x60, 0xcf, 0xca, 0x48, 0xd2, 0x65, 0x4c, 0x9e, 0xf4, 0xad, 0xf5, + 0x63, 0x22, 0xc6, 0x54, 0xe6, 0x42, 0x1c, 0x1c, 0xe3, 0x67, 0x08, 0x66, 0xfb, 0x16, 0x09, 0xce, + 0x0b, 0xb9, 0x5b, 0x80, 0x8d, 0xfc, 0x0e, 0x92, 0xe4, 0x2e, 0x27, 0x59, 0xc5, 0x1b, 0xe3, 0x92, + 0xc4, 0x27, 0x08, 0xe6, 0xb5, 0x53, 0x1a, 0xdf, 0xc9, 0x89, 0x42, 0x5d, 0x30, 0xc6, 0xf6, 0xb8, + 0x6e, 0x92, 0xc2, 0x3b, 0x9c, 0xc2, 0x5b, 0x78, 0x37, 0x17, 0x05, 0xb9, 0x27, 0x14, 0x2a, 0xdf, + 0x2a, 0x6d, 0x9f, 0xe4, 0x6b, 0xfb, 0x64, 0xac, 0xb6, 0xef, 0xcd, 0xf0, 0xdc, 0xbf, 0xcd, 0x44, + 0x05, 0xf9, 0x45, 0x17, 0xa4, 0x18, 0xc7, 0x23, 0x41, 0x2a, 0x5b, 0x60, 0x24, 0x48, 0x75, 0x2f, + 0x98, 0xaf, 0x72, 0x90, 0x8b, 0x78, 0x5e, 0x80, 0xec, 0xe2, 0x13, 0x2b, 0x00, 0xff, 0x80, 0xe0, + 0xaa, 0x66, 0xb6, 0xe3, 0xad, 0xa1, 0x59, 0x86, 0x2f, 0x0b, 0xe3, 0xcd, 0xf1, 0x9c, 0x24, 0xc2, + 0x2a, 0x47, 0xb8, 0x86, 0x6f, 0xeb, 0x64, 0xd4, 0x2e, 0x16, 0x86, 0x7f, 0x42, 0xb0, 0xa0, 0x1f, + 0xff, 0x78, 0x7b, 0x34, 0x08, 0xed, 0x58, 0xd9, 0x19, 0xdb, 0x2f, 0x4f, 0x1b, 0x0c, 0xdb, 0x40, + 0x6c, 0xcf, 0x3e, 0x39, 0x2d, 0xa3, 0xe7, 0xa7, 0x65, 0xf4, 0xd7, 0x69, 0x19, 0x7d, 0x79, 0x56, + 0x9e, 0x78, 0x7e, 0x56, 0x9e, 0xf8, 0xe3, 0xac, 0x3c, 0xf1, 0xe9, 0x6e, 0x10, 0xc6, 0x87, 0x89, + 0x6b, 0x79, 0xb4, 0x41, 0xe4, 0x9f, 0xe9, 0xd0, 0xf5, 0xd6, 0x03, 0x4a, 0xda, 0x5b, 0xa4, 0x41, + 0x6b, 0x49, 0xdd, 0x67, 0x22, 0xcf, 0x46, 0x75, 0x5d, 0xa6, 0x8a, 0x8f, 0x9a, 0x3e, 0x73, 0xa7, + 0xf9, 0x22, 0xdb, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x80, 0xba, 0x64, 0xbc, 0xb8, 0x0f, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -957,6 +1076,8 @@ type QueryClient interface { // ConsensusStates queries all the consensus state associated with a given // client. ConsensusStates(ctx context.Context, in *QueryConsensusStatesRequest, opts ...grpc.CallOption) (*QueryConsensusStatesResponse, error) + // ConsensusStateHeights queries the height of every consensus states associated with a given client. + ConsensusStateHeights(ctx context.Context, in *QueryConsensusStateHeightsRequest, opts ...grpc.CallOption) (*QueryConsensusStateHeightsResponse, error) // Status queries the status of an IBC client. ClientStatus(ctx context.Context, in *QueryClientStatusRequest, opts ...grpc.CallOption) (*QueryClientStatusResponse, error) // ClientParams queries all parameters of the ibc client. @@ -1011,6 +1132,15 @@ func (c *queryClient) ConsensusStates(ctx context.Context, in *QueryConsensusSta return out, nil } +func (c *queryClient) ConsensusStateHeights(ctx context.Context, in *QueryConsensusStateHeightsRequest, opts ...grpc.CallOption) (*QueryConsensusStateHeightsResponse, error) { + out := new(QueryConsensusStateHeightsResponse) + err := c.cc.Invoke(ctx, "/ibc.core.client.v1.Query/ConsensusStateHeights", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) ClientStatus(ctx context.Context, in *QueryClientStatusRequest, opts ...grpc.CallOption) (*QueryClientStatusResponse, error) { out := new(QueryClientStatusResponse) err := c.cc.Invoke(ctx, "/ibc.core.client.v1.Query/ClientStatus", in, out, opts...) @@ -1059,6 +1189,8 @@ type QueryServer interface { // ConsensusStates queries all the consensus state associated with a given // client. ConsensusStates(context.Context, *QueryConsensusStatesRequest) (*QueryConsensusStatesResponse, error) + // ConsensusStateHeights queries the height of every consensus states associated with a given client. + ConsensusStateHeights(context.Context, *QueryConsensusStateHeightsRequest) (*QueryConsensusStateHeightsResponse, error) // Status queries the status of an IBC client. ClientStatus(context.Context, *QueryClientStatusRequest) (*QueryClientStatusResponse, error) // ClientParams queries all parameters of the ibc client. @@ -1085,6 +1217,9 @@ func (*UnimplementedQueryServer) ConsensusState(ctx context.Context, req *QueryC func (*UnimplementedQueryServer) ConsensusStates(ctx context.Context, req *QueryConsensusStatesRequest) (*QueryConsensusStatesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ConsensusStates not implemented") } +func (*UnimplementedQueryServer) ConsensusStateHeights(ctx context.Context, req *QueryConsensusStateHeightsRequest) (*QueryConsensusStateHeightsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConsensusStateHeights not implemented") +} func (*UnimplementedQueryServer) ClientStatus(ctx context.Context, req *QueryClientStatusRequest) (*QueryClientStatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ClientStatus not implemented") } @@ -1174,6 +1309,24 @@ func _Query_ConsensusStates_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Query_ConsensusStateHeights_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryConsensusStateHeightsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ConsensusStateHeights(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.client.v1.Query/ConsensusStateHeights", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ConsensusStateHeights(ctx, req.(*QueryConsensusStateHeightsRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Query_ClientStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryClientStatusRequest) if err := dec(in); err != nil { @@ -1266,6 +1419,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "ConsensusStates", Handler: _Query_ConsensusStates_Handler, }, + { + MethodName: "ConsensusStateHeights", + Handler: _Query_ConsensusStateHeights_Handler, + }, { MethodName: "ClientStatus", Handler: _Query_ClientStatus_Handler, @@ -1646,6 +1803,97 @@ func (m *QueryConsensusStatesResponse) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } +func (m *QueryConsensusStateHeightsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryConsensusStateHeightsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryConsensusStateHeightsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ClientId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryConsensusStateHeightsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryConsensusStateHeightsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryConsensusStateHeightsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.ConsensusStateHeights) > 0 { + for iNdEx := len(m.ConsensusStateHeights) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ConsensusStateHeights[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *QueryClientStatusRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2032,6 +2280,42 @@ func (m *QueryConsensusStatesResponse) Size() (n int) { return n } +func (m *QueryConsensusStateHeightsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryConsensusStateHeightsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ConsensusStateHeights) > 0 { + for _, e := range m.ConsensusStateHeights { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + func (m *QueryClientStatusRequest) Size() (n int) { if m == nil { return 0 @@ -3102,6 +3386,244 @@ func (m *QueryConsensusStatesResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryConsensusStateHeightsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsensusStateHeightsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsensusStateHeightsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryConsensusStateHeightsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryConsensusStateHeightsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryConsensusStateHeightsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsensusStateHeights", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsensusStateHeights = append(m.ConsensusStateHeights, Height{}) + if err := m.ConsensusStateHeights[len(m.ConsensusStateHeights)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *QueryClientStatusRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/core/02-client/types/query.pb.gw.go b/modules/core/02-client/types/query.pb.gw.go index 3704fb07895..7bc1177962b 100644 --- a/modules/core/02-client/types/query.pb.gw.go +++ b/modules/core/02-client/types/query.pb.gw.go @@ -309,6 +309,78 @@ func local_request_Query_ConsensusStates_0(ctx context.Context, marshaler runtim } +var ( + filter_Query_ConsensusStateHeights_0 = &utilities.DoubleArray{Encoding: map[string]int{"client_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_ConsensusStateHeights_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsensusStateHeightsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["client_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "client_id") + } + + protoReq.ClientId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "client_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ConsensusStateHeights_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ConsensusStateHeights(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ConsensusStateHeights_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryConsensusStateHeightsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["client_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "client_id") + } + + protoReq.ClientId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "client_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ConsensusStateHeights_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ConsensusStateHeights(ctx, &protoReq) + return msg, metadata, err + +} + func request_Query_ClientStatus_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryClientStatusRequest var metadata runtime.ServerMetadata @@ -503,6 +575,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_ConsensusStateHeights_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ConsensusStateHeights_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ConsensusStateHeights_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_ClientStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -704,6 +796,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_ConsensusStateHeights_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ConsensusStateHeights_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ConsensusStateHeights_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_ClientStatus_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -796,6 +908,8 @@ var ( pattern_Query_ConsensusStates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "client", "v1", "consensus_states", "client_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ConsensusStateHeights_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"ibc", "core", "client", "v1", "consensus_states", "heights", "client_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ClientStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "client", "v1", "client_status", "client_id"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_ClientParams_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ibc", "client", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) @@ -814,6 +928,8 @@ var ( forward_Query_ConsensusStates_0 = runtime.ForwardResponseMessage + forward_Query_ConsensusStateHeights_0 = runtime.ForwardResponseMessage + forward_Query_ClientStatus_0 = runtime.ForwardResponseMessage forward_Query_ClientParams_0 = runtime.ForwardResponseMessage diff --git a/modules/core/keeper/grpc_query.go b/modules/core/keeper/grpc_query.go index 2fb171a9c02..138a4e7aa01 100644 --- a/modules/core/keeper/grpc_query.go +++ b/modules/core/keeper/grpc_query.go @@ -28,6 +28,11 @@ func (q Keeper) ConsensusStates(c context.Context, req *clienttypes.QueryConsens return q.ClientKeeper.ConsensusStates(c, req) } +// ConsensusStateHeights implements the IBC QueryServer interface +func (q Keeper) ConsensusStateHeights(c context.Context, req *clienttypes.QueryConsensusStateHeightsRequest) (*clienttypes.QueryConsensusStateHeightsResponse, error) { + return q.ClientKeeper.ConsensusStateHeights(c, req) +} + // ClientStatus implements the IBC QueryServer interface func (q Keeper) ClientStatus(c context.Context, req *clienttypes.QueryClientStatusRequest) (*clienttypes.QueryClientStatusResponse, error) { return q.ClientKeeper.ClientStatus(c, req) diff --git a/proto/ibc/core/client/v1/query.proto b/proto/ibc/core/client/v1/query.proto index 91a906fe54b..72c4fa0e3d7 100644 --- a/proto/ibc/core/client/v1/query.proto +++ b/proto/ibc/core/client/v1/query.proto @@ -36,6 +36,11 @@ service Query { option (google.api.http).get = "/ibc/core/client/v1/consensus_states/{client_id}"; } + // ConsensusStateHeights queries the height of every consensus states associated with a given client. + rpc ConsensusStateHeights(QueryConsensusStateHeightsRequest) returns (QueryConsensusStateHeightsResponse) { + option (google.api.http).get = "/ibc/core/client/v1/consensus_states/heights/{client_id}"; + } + // Status queries the status of an IBC client. rpc ClientStatus(QueryClientStatusRequest) returns (QueryClientStatusResponse) { option (google.api.http).get = "/ibc/core/client/v1/client_status/{client_id}"; @@ -137,6 +142,24 @@ message QueryConsensusStatesResponse { cosmos.base.query.v1beta1.PageResponse pagination = 2; } +// QueryConsensusStateHeightsRequest is the request type for Query/ConsensusStateHeights +// RPC method. +message QueryConsensusStateHeightsRequest { + // client identifier + string client_id = 1; + // pagination request + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryConsensusStateHeightsResponse is the response type for the +// Query/ConsensusStateHeights RPC method +message QueryConsensusStateHeightsResponse { + // consensus state heights + repeated Height consensus_state_heights = 1 [(gogoproto.nullable) = false]; + // pagination response + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + // QueryClientStatusRequest is the request type for the Query/ClientStatus RPC // method message QueryClientStatusRequest { From 15a328091bc2b6760b88a14c89e7f77708183f69 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 8 Jun 2022 11:28:08 +0200 Subject: [PATCH 144/275] feat: adding fee middleware support to ics27 interchain accounts (#1432) * updating simapp to include ics29 fee in ica stacks * updating RegisterInterchainAccount to pass through version arg and support fee middleware functionality * updating tests to support additional version arg in RegisterInterchainAccount * adding migration docs for ICS27 fee middleware support * remove unnecessary spacing * fixing typo in godoc * adding changelog entry * Apply suggestions from code review Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 1 + docs/migrations/v3-to-v4.md | 60 ++++++++++++++++++- .../controller/ibc_middleware_test.go | 9 ++- .../controller/keeper/account.go | 36 +++-------- .../controller/keeper/account_test.go | 32 +++++++--- .../controller/keeper/keeper_test.go | 2 +- .../host/ibc_module_test.go | 2 +- .../host/keeper/keeper_test.go | 2 +- testing/simapp/app.go | 14 +++-- 9 files changed, 111 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 104c9bb142e..bb092156aad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) The `OnChanOpenInit` application callback now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). * (modules/29-fee)[\#1338](https://github.com/cosmos/ibc-go/pull/1338) Renaming `Result` field in `IncentivizedAcknowledgement` to `AppAcknowledgement`. * (modules/29-fee)[\#1343](https://github.com/cosmos/ibc-go/pull/1343) Renaming `KeyForwardRelayerAddress` to `KeyRelayerAddressForAsyncAck`, and `ParseKeyForwardRelayerAddress` to `ParseKeyRelayerAddressForAsyncAck`. +* (apps/27-interchain-accounts)[\#1432](https://github.com/cosmos/ibc-go/pull/1432) Updating `RegisterInterchainAccount` to include an additional `version` argument, supporting ICS29 fee middleware functionality in ICS27 interchain accounts. ### State Machine Breaking diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 5f684581ab2..a6a90055a69 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -18,7 +18,7 @@ No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-g ## Chains -### IS04 - Channel +### ICS04 - Channel The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. This is an API breaking change and as such IBC application developers will have to update any calls to `WriteAcknowledgement`. @@ -26,6 +26,64 @@ This is an API breaking change and as such IBC application developers will have The `OnChanOpenInit` application callback has been modified. The return signature now includes the application version as detailed in the latest IBC [spec changes](https://github.com/cosmos/ibc/pull/629). +### ICS27 - Interchain Accounts + +The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middelware, for relayer incentivization of ICS27 packets. +Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. +This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. + +The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: + +```go +icaMetadata := icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: controllerConnectionID, + HostConnectionId: hostConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, +} + +appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) +if err != nil { + return err +} + +if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(appVersion)); err != nil { + return err +} +``` + +Similarly, if the application stack is configured to route through ICS29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS29 `Metadata` type: + +```go +icaMetadata := icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: controllerConnectionID, + HostConnectionId: hostConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, +} + +appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) +if err != nil { + return err +} + +feeMetadata := feetypes.Metadata{ + AppVersion: string(appVersion), + FeeVersion: feetypes.Version, +} + +feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) +if err != nil { + return err +} + +if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, string(feeEnabledVersion)); err != nil { + return err +} +``` + ## Relayers When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index adaffcb83f9..1c3660c54b5 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -9,9 +9,9 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" - icacontroller "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller" "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + fee "github.com/cosmos/ibc-go/v3/modules/apps/29-fee" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v3/modules/core/24-host" @@ -83,7 +83,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion); err != nil { return err } @@ -714,9 +714,8 @@ func (suite *InterchainAccountsTestSuite) TestGetAppVersion() { cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - controllerModule := cbs.(icacontroller.IBCMiddleware) - - appVersion, found := controllerModule.GetAppVersion(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + controllerStack := cbs.(fee.IBCMiddleware) + appVersion, found := controllerStack.GetAppVersion(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) suite.Require().True(found) suite.Require().Equal(path.EndpointA.ChannelConfig.Version, appVersion) } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account.go b/modules/apps/27-interchain-accounts/controller/keeper/account.go index 282b6e2e77a..2cb5e023e22 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account.go @@ -9,12 +9,14 @@ import ( host "github.com/cosmos/ibc-go/v3/modules/core/24-host" ) -// RegisterInterchainAccount is the entry point to registering an interchain account. -// It generates a new port identifier using the owner address. It will bind to the -// port identifier and call 04-channel 'ChanOpenInit'. An error is returned if the port -// identifier is already in use. Gaining access to interchain accounts whose channels -// have closed cannot be done with this function. A regular MsgChanOpenInit must be used. -func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner string) error { +// RegisterInterchainAccount is the entry point to registering an interchain account: +// - It generates a new port identifier using the provided owner string, binds to the port identifier and claims the associated capability. +// - Callers are expected to provide the appropriate application version string. +// - For example, this could be an ICS27 encoded metadata type or an ICS29 encoded metadata type with a nested application version. +// - A new MsgChannelOpenInit is routed through the MsgServiceRouter, executing the OnOpenChanInit callback stack as configured. +// - An error is returned if the port identifier is already in use. Gaining access to interchain accounts whose channels +// have closed cannot be done with this function. A regular MsgChannelOpenInit must be used. +func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner, version string) error { portID, err := icatypes.NewControllerPortID(owner) if err != nil { return err @@ -36,27 +38,7 @@ func (k Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner s } } - connectionEnd, err := k.channelKeeper.GetConnection(ctx, connectionID) - if err != nil { - return err - } - - // NOTE: An empty string is provided for accAddress, to be fulfilled upon OnChanOpenTry handshake step - metadata := icatypes.NewMetadata( - icatypes.Version, - connectionID, - connectionEnd.GetCounterparty().GetConnectionID(), - "", - icatypes.EncodingProtobuf, - icatypes.TxTypeSDKMultiMsg, - ) - - versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) - if err != nil { - return err - } - - msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) + msg := channeltypes.NewMsgChannelOpenInit(portID, version, channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) handler := k.msgRouter.Handler(msg) res, err := handler(ctx, msg) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go index 9387baa3936..0f8c89c51a8 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go @@ -72,7 +72,7 @@ func (suite *KeeperTestSuite) TestRegisterInterchainAccount() { tc.malleate() // malleate mutates test data - err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner) + err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner, TestVersion) if tc.expPass { suite.Require().NoError(err) @@ -88,15 +88,33 @@ func (suite *KeeperTestSuite) TestRegisterSameOwnerMultipleConnections() { owner := TestOwnerAddress - path := NewICAPath(suite.chainA, suite.chainB) - suite.coordinator.SetupConnections(path) + pathAToB := NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(pathAToB) - path2 := NewICAPath(suite.chainA, suite.chainC) - suite.coordinator.SetupConnections(path2) + pathAToC := NewICAPath(suite.chainA, suite.chainC) + suite.coordinator.SetupConnections(pathAToC) - err := suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner) + // build ICS27 metadata with connection identifiers for path A->B + metadata := &icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: pathAToB.EndpointA.ConnectionID, + HostConnectionId: pathAToB.EndpointB.ConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, + } + + err := suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), pathAToB.EndpointA.ConnectionID, owner, string(icatypes.ModuleCdc.MustMarshalJSON(metadata))) suite.Require().NoError(err) - err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), path2.EndpointA.ConnectionID, owner) + // build ICS27 metadata with connection identifiers for path A->C + metadata = &icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: pathAToC.EndpointA.ConnectionID, + HostConnectionId: pathAToC.EndpointB.ConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, + } + + err = suite.chainA.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(suite.chainA.GetContext(), pathAToC.EndpointA.ConnectionID, owner, string(icatypes.ModuleCdc.MustMarshalJSON(metadata))) suite.Require().NoError(err) } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go index a0772f1e648..76020e17c87 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -95,7 +95,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index db220f86026..78a21cfee01 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -86,7 +86,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion); err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go index 609fb06884d..98f9c06bf25 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go @@ -95,7 +95,7 @@ func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) erro channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) - if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner); err != nil { + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, TestVersion); err != nil { return err } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index b09cf6dffb7..94d5640aa17 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -366,7 +366,7 @@ func NewSimApp( // ICA Controller keeper app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( appCodec, keys[icacontrollertypes.StoreKey], app.GetSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee + app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, scopedICAControllerKeeper, app.MsgServiceRouter(), ) @@ -424,15 +424,21 @@ func NewSimApp( // Create Interchain Accounts Stack // SendPacket, since it is originating from the application to core IBC: - // icaAuthModuleKeeper.SendTx -> icaControllerKeeper.SendPacket -> channel.SendPacket + // icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket // initialize ICA module with mock module as the authentication module on the controller side var icaControllerStack porttypes.IBCModule icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) + icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) - icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) + // RecvPacket, message that originates from core IBC and goes down to app, the flow is: + // channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket + + var icaHostStack porttypes.IBCModule + icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) + icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) // Add host, controller & ica auth modules to IBC router ibcRouter. @@ -440,7 +446,7 @@ func NewSimApp( // ICA controller module owns the port capability for ICA. The ICA authentication module // owns the channel capability. AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). + AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) // Create Mock IBC Fee module stack for testing From 79990014784e606fd3769ec34c410650af0e4a44 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 8 Jun 2022 12:35:26 +0200 Subject: [PATCH 145/275] test: adding fee middleware tests for ics27 interchain accounts (#1433) * adding interchain accounts integration tests for ics29 fee * updating simapp to include fee middleware in ica stack * updating simapp to include ics29 fee in ica stacks * updating RegisterInterchainAccount to pass through version arg and support fee middleware functionality * updating tests to support additional version arg in RegisterInterchainAccount * adding migration docs for ICS27 fee middleware support * remove unnecessary spacing * fixing typo in godoc * adding changelog entry * adding godoc for NewICAPath in fee test suite * adding helper for default metadata version string to ics27 * unexported vars, register counterparty address for recv fee distribution, add comments and adjust assertions --- .../27-interchain-accounts/types/metadata.go | 14 ++ modules/apps/29-fee/ica_test.go | 197 ++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 modules/apps/29-fee/ica_test.go diff --git a/modules/apps/27-interchain-accounts/types/metadata.go b/modules/apps/27-interchain-accounts/types/metadata.go index 3a7eae51cdf..15f27314d47 100644 --- a/modules/apps/27-interchain-accounts/types/metadata.go +++ b/modules/apps/27-interchain-accounts/types/metadata.go @@ -27,6 +27,20 @@ func NewMetadata(version, controllerConnectionID, hostConnectionID, accAddress, } } +// NewDefaultMetadataString creates and returns a new JSON encoded version string containing the default ICS27 Metadata values +// with the provided controller and host connection identifiers +func NewDefaultMetadataString(controllerConnectionID, hostConnectionID string) string { + metadata := Metadata{ + Version: Version, + ControllerConnectionId: controllerConnectionID, + HostConnectionId: hostConnectionID, + Encoding: EncodingProtobuf, + TxType: TxTypeSDKMultiMsg, + } + + return string(ModuleCdc.MustMarshalJSON(&metadata)) +} + // IsPreviousMetadataEqual compares a metadata to a previous version string set in a channel struct. // It ensures all fields are equal except the Address string func IsPreviousMetadataEqual(previousVersion string, metadata Metadata) bool { diff --git a/modules/apps/29-fee/ica_test.go b/modules/apps/29-fee/ica_test.go new file mode 100644 index 00000000000..88b3d088412 --- /dev/null +++ b/modules/apps/29-fee/ica_test.go @@ -0,0 +1,197 @@ +package fee_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +var ( + // defaultOwnerAddress defines a reusable bech32 address for testing purposes + defaultOwnerAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + + // defaultPortID defines a resuable port identifier for testing purposes + defaultPortID, _ = icatypes.NewControllerPortID(defaultOwnerAddress) + + // defaultICAVersion defines a resuable interchainaccounts version string for testing purposes + defaultICAVersion = icatypes.NewDefaultMetadataString(ibctesting.FirstConnectionID, ibctesting.FirstConnectionID) +) + +// NewIncentivizedICAPath creates and returns a new ibctesting path configured for a fee enabled interchain accounts channel +func NewIncentivizedICAPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { + path := ibctesting.NewPath(chainA, chainB) + + feeMetadata := types.Metadata{ + FeeVersion: types.Version, + AppVersion: defaultICAVersion, + } + + feeICAVersion := string(types.ModuleCdc.MustMarshalJSON(&feeMetadata)) + + path.SetChannelOrdered() + path.EndpointA.ChannelConfig.Version = feeICAVersion + path.EndpointB.ChannelConfig.Version = feeICAVersion + path.EndpointA.ChannelConfig.PortID = defaultPortID + path.EndpointB.ChannelConfig.PortID = icatypes.PortID + + return path +} + +// SetupPath performs the InterchainAccounts channel creation handshake using an ibctesting path +func SetupPath(path *ibctesting.Path, owner string) error { + if err := RegisterInterchainAccount(path.EndpointA, owner); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenTry(); err != nil { + return err + } + + if err := path.EndpointA.ChanOpenAck(); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenConfirm(); err != nil { + return err + } + + return nil +} + +// RegisterInterchainAccount invokes the the InterchainAccounts entrypoint, routes a new MsgChannelOpenInit to the appropriate handler, +// commits state changes and updates the testing endpoint accordingly +func RegisterInterchainAccount(endpoint *ibctesting.Endpoint, owner string) error { + portID, err := icatypes.NewControllerPortID(owner) + if err != nil { + return err + } + + channelSequence := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(endpoint.Chain.GetContext()) + + if err := endpoint.Chain.GetSimApp().ICAControllerKeeper.RegisterInterchainAccount(endpoint.Chain.GetContext(), endpoint.ConnectionID, owner, endpoint.ChannelConfig.Version); err != nil { + return err + } + + // commit state changes for proof verification + endpoint.Chain.NextBlock() + + // update port/channel ids + endpoint.ChannelID = channeltypes.FormatChannelIdentifier(channelSequence) + endpoint.ChannelConfig.PortID = portID + + return nil +} + +// TestFeeInterchainAccounts Integration test to ensure ics29 works with ics27 +func (suite *FeeTestSuite) TestFeeInterchainAccounts() { + path := NewIncentivizedICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + + err := SetupPath(path, defaultOwnerAddress) + suite.Require().NoError(err) + + // assert the newly established channel is fee enabled on both ends + suite.Require().True(suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + suite.Require().True(suite.chainB.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) + + // register counterparty address on destination chainB as chainA.SenderAccounts[1] for recv fee distribution + suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), path.EndpointB.ChannelID) + + // escrow a packet fee for the next send sequence + expectedFee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + msgPayPacketFee := types.NewMsgPayPacketFee(expectedFee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil) + + // fetch the account balance before fees are escrowed and assert the difference below + preEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + + res, err := suite.chainA.SendMsgs(msgPayPacketFee) + suite.Require().NotNil(res) + suite.Require().NoError(err) + + postEscrowBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(postEscrowBalance.AddAmount(expectedFee.Total().AmountOf(sdk.DefaultBondDenom)), preEscrowBalance) + + packetID := channeltypes.NewPacketId(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, 1) + packetFees, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().True(found) + suite.Require().Equal(expectedFee, packetFees.PacketFees[0].Fee) + + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + // fund the interchain account on chainB + coins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000))) + msgBankSend := &banktypes.MsgSend{ + FromAddress: suite.chainB.SenderAccount.GetAddress().String(), + ToAddress: interchainAccountAddr, + Amount: coins, + } + + res, err = suite.chainB.SendMsgs(msgBankSend) + suite.Require().NotEmpty(res) + suite.Require().NoError(err) + + // prepare a simple stakingtypes.MsgDelegate to be used as the interchain account msg executed on chainB + validatorAddr := (sdk.ValAddress)(suite.chainB.Vals.Validators[0].Address) + msgDelegate := &stakingtypes.MsgDelegate{ + DelegatorAddress: interchainAccountAddr, + ValidatorAddress: validatorAddr.String(), + Amount: sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(5000)), + } + + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msgDelegate}) + suite.Require().NoError(err) + + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + // ensure chainB is allowed to execute stakingtypes.MsgDelegate + params := icahosttypes.NewParams(true, []string{sdk.MsgTypeURL(msgDelegate)}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) + + // build the interchain accounts packet + packet := buildInterchainAccountsPacket(path, icaPacketData.GetBytes(), 1) + + // write packet commitment to state on chainA and commit state + commitment := channeltypes.CommitPacket(suite.chainA.GetSimApp().AppCodec(), packet) + suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, 1, commitment) + suite.chainA.NextBlock() + + err = path.RelayPacket(packet) + suite.Require().NoError(err) + + // ensure escrowed fees are cleaned up + packetFees, found = suite.chainA.GetSimApp().IBCFeeKeeper.GetFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + suite.Require().Empty(packetFees) + + // assert the value of the account balance after fee distribution + // NOTE: the balance after fee distribution should be equal to the pre-escrow balance minus the recv fee + // as chainA.SenderAccount is used as the msg signer and refund address for msgPayPacketFee above as well as the relyer account for acknowledgements in path.RelayPacket() + postDistBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) + suite.Require().Equal(preEscrowBalance.SubAmount(defaultRecvFee.AmountOf(sdk.DefaultBondDenom)), postDistBalance) +} + +func buildInterchainAccountsPacket(path *ibctesting.Path, data []byte, seq uint64) channeltypes.Packet { + packet := channeltypes.NewPacket( + data, + 1, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + path.EndpointB.ChannelConfig.PortID, + path.EndpointB.ChannelID, + clienttypes.NewHeight(0, 100), + 0, + ) + + return packet +} From 040f2eafc1f5943ec3816cc7e8a85a64873a8bd9 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 8 Jun 2022 15:30:33 +0200 Subject: [PATCH 146/275] feat: adding RegisterPayee rpc to ics29 fee middleware (#1491) * [WIP] adding RegisterDistributionAddress rpc endpoint and implementation. Store funcs, keys.. * updating tests * adding cli for register distribution address rpc * renaming RegisterDistributionAddress rpc to RegisterPayee * renaming RegisterDistributionAddress to RegisterPayee * updating godocs and field ordering * updating inline comment --- docs/ibc/proto-docs.md | 47 +- modules/apps/29-fee/client/cli/cli.go | 3 +- modules/apps/29-fee/client/cli/tx.go | 29 +- modules/apps/29-fee/keeper/keeper.go | 18 + modules/apps/29-fee/keeper/keeper_test.go | 19 + modules/apps/29-fee/keeper/msg_server.go | 28 +- modules/apps/29-fee/keeper/msg_server_test.go | 64 ++ modules/apps/29-fee/types/keys.go | 20 + modules/apps/29-fee/types/keys_test.go | 36 ++ modules/apps/29-fee/types/msgs.go | 47 ++ modules/apps/29-fee/types/msgs_test.go | 75 +++ modules/apps/29-fee/types/query.pb.go | 160 ++--- modules/apps/29-fee/types/query.pb.gw.go | 248 ++++---- modules/apps/29-fee/types/tx.pb.go | 571 ++++++++++++++++-- proto/ibc/applications/fee/v1/query.proto | 3 +- proto/ibc/applications/fee/v1/tx.proto | 27 +- 16 files changed, 1125 insertions(+), 270 deletions(-) diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 9bbf462a18f..577dad6af8d 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -72,6 +72,8 @@ - [MsgPayPacketFeeResponse](#ibc.applications.fee.v1.MsgPayPacketFeeResponse) - [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress) - [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse) + - [MsgRegisterPayee](#ibc.applications.fee.v1.MsgRegisterPayee) + - [MsgRegisterPayeeResponse](#ibc.applications.fee.v1.MsgRegisterPayeeResponse) - [Msg](#ibc.applications.fee.v1.Msg) @@ -1209,14 +1211,14 @@ Query defines the ICS29 gRPC querier service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `IncentivizedPackets` | [QueryIncentivizedPacketsRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsRequest) | [QueryIncentivizedPacketsResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsResponse) | IncentivizedPackets returns all incentivized packets and their associated fees | GET|/ibc/apps/fee/v1/incentivized_packets| -| `IncentivizedPacket` | [QueryIncentivizedPacketRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketRequest) | [QueryIncentivizedPacketResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketResponse) | IncentivizedPacket returns all packet fees for a packet given its identifier | GET|/ibc/apps/fee/v1/incentivized_packet/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| -| `IncentivizedPacketsForChannel` | [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) | [QueryIncentivizedPacketsForChannelResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse) | Gets all incentivized packets for a specific channel | GET|/ibc/apps/fee/v1/incentivized_packets/port/{port_id}/channel/{channel_id}| -| `TotalRecvFees` | [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) | [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) | TotalRecvFees returns the total receive fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_recv_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| -| `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| -| `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}| -| `CounterpartyAddress` | [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) | [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) | CounterpartyAddress returns the registered counterparty address for forward relaying | GET|/ibc/apps/fee/v1/counterparty_address/{relayer_address}/channel/{channel_id}| +| `IncentivizedPacket` | [QueryIncentivizedPacketRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketRequest) | [QueryIncentivizedPacketResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketResponse) | IncentivizedPacket returns all packet fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/incentivized_packet| +| `IncentivizedPacketsForChannel` | [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) | [QueryIncentivizedPacketsForChannelResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse) | Gets all incentivized packets for a specific channel | GET|/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/incentivized_packets| +| `TotalRecvFees` | [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) | [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) | TotalRecvFees returns the total receive fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_recv_fees| +| `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_ack_fees| +| `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_timeout_fees| +| `CounterpartyAddress` | [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) | [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) | CounterpartyAddress returns the registered counterparty address for forward relaying | GET|/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address| | `FeeEnabledChannels` | [QueryFeeEnabledChannelsRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest) | [QueryFeeEnabledChannelsResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse) | FeeEnabledChannels returns a list of all fee enabled channels | GET|/ibc/apps/fee/v1/fee_enabled| -| `FeeEnabledChannel` | [QueryFeeEnabledChannelRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelRequest) | [QueryFeeEnabledChannelResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelResponse) | FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel | GET|/ibc/apps/fee/v1/fee_enabled/port/{port_id}/channel/{channel_id}| +| `FeeEnabledChannel` | [QueryFeeEnabledChannelRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelRequest) | [QueryFeeEnabledChannelResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelResponse) | FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel | GET|/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled| @@ -1314,6 +1316,34 @@ MsgRegisterCounterpartyAddressResponse defines the response type for the Registe + + + +### MsgRegisterPayee +MsgRegisterPayee defines the request type for the RegisterPayee rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | unique port identifier | +| `channel_id` | [string](#string) | | unique channel identifier | +| `relayer_address` | [string](#string) | | the relayer address | +| `payee` | [string](#string) | | the fee payee address | + + + + + + + + +### MsgRegisterPayeeResponse +MsgRegisterPayeeResponse defines the response type for the RegisterPayee rpc + + + + + @@ -1328,7 +1358,8 @@ Msg defines the ICS29 Msg service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `RegisterCounterpartyAddress` | [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress) | [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse) | RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying. This ensures they will be properly compensated for forward relaying since destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function may be called more than once by a relayer, in which case, latest counterparty address is always used. | | +| `RegisterPayee` | [MsgRegisterPayee](#ibc.applications.fee.v1.MsgRegisterPayee) | [MsgRegisterPayeeResponse](#ibc.applications.fee.v1.MsgRegisterPayeeResponse) | RegisterPayee defines a rpc handler method for MsgRegisterPayee RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which packets originate as this is where fee distribution takes place. This function may be called more than once by a relayer, in which case, the latest payee is always used. | | +| `RegisterCounterpartyAddress` | [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress) | [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse) | RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying. This ensures they will be properly compensated for forward relaying since destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function may be called more than once by a relayer, in which case, the latest counterparty address is always used. | | | `PayPacketFee` | [MsgPayPacketFee](#ibc.applications.fee.v1.MsgPayPacketFee) | [MsgPayPacketFeeResponse](#ibc.applications.fee.v1.MsgPayPacketFeeResponse) | PayPacketFee defines a rpc handler method for MsgPayPacketFee PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to incentivize the relaying of the packet at the next sequence NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows initiates the lifecycle of the incentivized packet | | | `PayPacketFeeAsync` | [MsgPayPacketFeeAsync](#ibc.applications.fee.v1.MsgPayPacketFeeAsync) | [MsgPayPacketFeeAsyncResponse](#ibc.applications.fee.v1.MsgPayPacketFeeAsyncResponse) | PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to incentivize the relaying of a known packet (i.e. at a particular sequence) | | diff --git a/modules/apps/29-fee/client/cli/cli.go b/modules/apps/29-fee/client/cli/cli.go index a0141c20f9a..1306efa84b9 100644 --- a/modules/apps/29-fee/client/cli/cli.go +++ b/modules/apps/29-fee/client/cli/cli.go @@ -40,8 +40,9 @@ func NewTxCmd() *cobra.Command { } txCmd.AddCommand( + NewRegisterPayeeCmd(), NewPayPacketFeeAsyncTxCmd(), - NewRegisterCounterpartyAddress(), + NewRegisterCounterpartyAddressCmd(), ) return txCmd diff --git a/modules/apps/29-fee/client/cli/tx.go b/modules/apps/29-fee/client/cli/tx.go index 9c972316d91..24f84731d88 100644 --- a/modules/apps/29-fee/client/cli/tx.go +++ b/modules/apps/29-fee/client/cli/tx.go @@ -22,6 +22,31 @@ const ( flagTimeoutFee = "timeout-fee" ) +// NewRegisterPayeeCmd returns the command to create a MsgRegisterPayee +func NewRegisterPayeeCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "register-payee [port-id] [channel-id] [relayer-address] [payee-address] ", + Short: "Register a payee on a given channel.", + Long: strings.TrimSpace(`Register a payee address on a given channel.`), + Example: fmt.Sprintf("%s tx ibc-fee register-payee transfer channel-0 cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5", version.AppName), + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgRegisterPayee(args[0], args[1], args[2], args[3]) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + // NewPayPacketFeeAsyncTxCmd returns the command to create a MsgPayPacketFeeAsync func NewPayPacketFeeAsyncTxCmd() *cobra.Command { cmd := &cobra.Command{ @@ -98,8 +123,8 @@ func NewPayPacketFeeAsyncTxCmd() *cobra.Command { return cmd } -// NewRegisterCounterpartyAddress returns the command to create a MsgRegisterCounterpartyAddress -func NewRegisterCounterpartyAddress() *cobra.Command { +// NewRegisterCounterpartyAddressCmd returns the command to create a MsgRegisterCounterpartyAddress +func NewRegisterCounterpartyAddressCmd() *cobra.Command { cmd := &cobra.Command{ Use: "register-counterparty [port-id] [channel-id] [address] [counterparty-address] ", Short: "Register a counterparty relayer address on a given channel.", diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index a4b5a153c33..15e9eb86f82 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -147,6 +147,24 @@ func (k Keeper) GetAllFeeEnabledChannels(ctx sdk.Context) []types.FeeEnabledChan return enabledChArr } +// GetPayeeAddress retrieves the fee payee address stored in state given the provided channel identifier and relayer address +func (k Keeper) GetPayeeAddress(ctx sdk.Context, relayerAddr, channelID string) (string, bool) { + store := ctx.KVStore(k.storeKey) + key := types.KeyPayeeAddress(relayerAddr, channelID) + + if !store.Has(key) { + return "", false + } + + return string(store.Get(key)), true +} + +// SetPayeeAddress stores the fee payee address in state keyed by the provided channel identifier and relayer address +func (k Keeper) SetPayeeAddress(ctx sdk.Context, relayerAddr, payeeAddr, channelID string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyPayeeAddress(relayerAddr, channelID), []byte(payeeAddr)) +} + // SetCounterpartyAddress maps the destination chain relayer address to the source relayer address // The receiving chain must store the mapping from: address -> counterpartyAddress for the given channel func (k Keeper) SetCounterpartyAddress(ctx sdk.Context, address, counterpartyAddress, channelID string) { diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index 7446ecbab64..d66f1284fe6 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -91,6 +91,25 @@ func (suite *KeeperTestSuite) TestEscrowAccountHasBalance() { suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.EscrowAccountHasBalance(suite.chainA.GetContext(), fee.Total())) } +func (suite *KeeperTestSuite) TestGetSetPayeeAddress() { + suite.coordinator.Setup(suite.path) + + payeeAddr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.path.EndpointA.ChannelID) + suite.Require().False(found) + suite.Require().Empty(payeeAddr) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), + suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), + suite.path.EndpointA.ChannelID, + ) + + payeeAddr, found = suite.chainA.GetSimApp().IBCFeeKeeper.GetPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.path.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), payeeAddr) +} + func (suite *KeeperTestSuite) TestFeesInEscrow() { suite.coordinator.Setup(suite.path) diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index e0c78028ea8..0dfc8cb9a10 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -12,6 +12,30 @@ import ( var _ types.MsgServer = Keeper{} +// RegisterPayee defines a rpc handler method for MsgRegisterPayee +// RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional +// payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which +// packets originate as this is where fee distribution takes place. This function may be called more than once by a relayer, +// in which case, the latest payee is always used. +func (k Keeper) RegisterPayee(goCtx context.Context, msg *types.MsgRegisterPayee) (*types.MsgRegisterPayeeResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // only register payee address if the channel exists and is fee enabled + if _, found := k.channelKeeper.GetChannel(ctx, msg.PortId, msg.ChannelId); !found { + return nil, channeltypes.ErrChannelNotFound + } + + if !k.IsFeeEnabled(ctx, msg.PortId, msg.ChannelId) { + return nil, types.ErrFeeNotEnabled + } + + k.SetPayeeAddress(ctx, msg.RelayerAddress, msg.Payee, msg.ChannelId) + + k.Logger(ctx).Info("registering payee address for relayer", "relayer address", msg.RelayerAddress, "payee address", msg.Payee, "channel", msg.ChannelId) + + return &types.MsgRegisterPayeeResponse{}, nil +} + // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying // This ensures they will be properly compensated for forward relaying on the source chain since the destination chain must send back relayer's source address (counterparty address) in acknowledgement // This function may be called more than once by relayers, in which case, the previous counterparty address will be overwritten by the new counterparty address @@ -27,9 +51,7 @@ func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.Ms return nil, types.ErrFeeNotEnabled } - k.SetCounterpartyAddress( - ctx, msg.Address, msg.CounterpartyAddress, msg.ChannelId, - ) + k.SetCounterpartyAddress(ctx, msg.Address, msg.CounterpartyAddress, msg.ChannelId) k.Logger(ctx).Info("registering counterparty address for relayer", "address", msg.Address, "counterparty address", msg.CounterpartyAddress, "channel", msg.ChannelId) diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index b4e665e56db..76179514943 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -9,6 +9,70 @@ import ( ibctesting "github.com/cosmos/ibc-go/v3/testing" ) +func (suite *KeeperTestSuite) TestRegisterPayee() { + var ( + msg *types.MsgRegisterPayee + ) + + testCases := []struct { + name string + expPass bool + malleate func() + }{ + { + "success", + true, + func() {}, + }, + { + "channel does not exist", + false, + func() { + msg.ChannelId = "channel-100" + }, + }, + { + "channel is not fee enabled", + false, + func() { + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + }, + }, + } + + for _, tc := range testCases { + suite.SetupTest() + suite.coordinator.Setup(suite.path) + + msg = types.NewMsgRegisterPayee( + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), + suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), + ) + + tc.malleate() + + res, err := suite.chainA.GetSimApp().IBCFeeKeeper.RegisterPayee(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + + payeeAddr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + suite.path.EndpointA.ChannelID, + ) + + suite.Require().True(found) + suite.Require().Equal(suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), payeeAddr) + } else { + suite.Require().Error(err) + } + } +} + func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() { var ( sender string diff --git a/modules/apps/29-fee/types/keys.go b/modules/apps/29-fee/types/keys.go index cf93967f84a..6cb6f53551c 100644 --- a/modules/apps/29-fee/types/keys.go +++ b/modules/apps/29-fee/types/keys.go @@ -28,6 +28,9 @@ const ( // FeeEnabledPrefix is the key prefix for storing fee enabled flag FeeEnabledKeyPrefix = "feeEnabled" + // PayeeAddressKeyPrefix is the key prefix for the fee payee address stored in state + PayeeAddressKeyPrefix = "payeeAddress" + // CounterpartyRelayerAddressKeyPrefix is the key prefix for relayer address mapping CounterpartyRelayerAddressKeyPrefix = "relayerAddress" @@ -70,6 +73,23 @@ func ParseKeyFeeEnabled(key string) (portID, channelID string, err error) { return portID, channelID, nil } +// KeyPayeeAddress returns the key for relayer address -> payee address mapping +func KeyPayeeAddress(relayerAddr, channelID string) []byte { + return []byte(fmt.Sprintf("%s/%s/%s", PayeeAddressKeyPrefix, relayerAddr, channelID)) +} + +// ParseKeyPayeeAddress returns the registered relayer addresss and channelID used to the store the fee payee address +func ParseKeyPayeeAddress(key string) (relayerAddr, channelID string, err error) { + keySplit := strings.Split(key, "/") + if len(keySplit) != 3 { + return "", "", sdkerrors.Wrapf( + sdkerrors.ErrLogic, "key provided is incorrect: the key split has incorrect length, expected %d, got %d", 3, len(keySplit), + ) + } + + return keySplit[1], keySplit[2], nil +} + // KeyCounterpartyRelayer returns the key for relayer address -> counterparty address mapping func KeyCounterpartyRelayer(address, channelID string) []byte { return []byte(fmt.Sprintf("%s/%s/%s", CounterpartyRelayerAddressKeyPrefix, address, channelID)) diff --git a/modules/apps/29-fee/types/keys_test.go b/modules/apps/29-fee/types/keys_test.go index 7cc0b4c9543..442c4a47634 100644 --- a/modules/apps/29-fee/types/keys_test.go +++ b/modules/apps/29-fee/types/keys_test.go @@ -13,6 +13,42 @@ import ( var validPacketID = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) +func TestKeyPayeeAddress(t *testing.T) { + key := types.KeyPayeeAddress("relayer-address", ibctesting.FirstChannelID) + require.Equal(t, string(key), fmt.Sprintf("%s/%s/%s", types.PayeeAddressKeyPrefix, "relayer-address", ibctesting.FirstChannelID)) +} + +func TestParseKeyPayeeAddress(t *testing.T) { + testCases := []struct { + name string + key string + expPass bool + }{ + { + "success", + string(types.KeyPayeeAddress("relayer-address", ibctesting.FirstChannelID)), + true, + }, + { + "incorrect key - key split has incorrect length", + "payeeAddress/relayer_address/transfer/channel-0", + false, + }, + } + + for _, tc := range testCases { + address, channelID, err := types.ParseKeyPayeeAddress(tc.key) + + if tc.expPass { + require.NoError(t, err) + require.Equal(t, "relayer-address", address) + require.Equal(t, ibctesting.FirstChannelID, channelID) + } else { + require.Error(t, err) + } + } +} + func TestKeyCounterpartyRelayer(t *testing.T) { var ( relayerAddress = "relayer_address" diff --git a/modules/apps/29-fee/types/msgs.go b/modules/apps/29-fee/types/msgs.go index 0e729edbd17..3d5520f3ff2 100644 --- a/modules/apps/29-fee/types/msgs.go +++ b/modules/apps/29-fee/types/msgs.go @@ -16,6 +16,53 @@ const ( TypeMsgPayPacketFeeAsync = "payPacketFeeAsync" ) +// NewMsgRegisterPayee creates a new instance of MsgRegisterPayee +func NewMsgRegisterPayee(portID, channelID, relayerAddr, payeeAddr string) *MsgRegisterPayee { + return &MsgRegisterPayee{ + PortId: portID, + ChannelId: channelID, + RelayerAddress: relayerAddr, + Payee: payeeAddr, + } +} + +// ValidateBasic implements sdk.Msg and performs basic stateless validation +func (msg MsgRegisterPayee) ValidateBasic() error { + if err := host.PortIdentifierValidator(msg.PortId); err != nil { + return err + } + + if err := host.ChannelIdentifierValidator(msg.ChannelId); err != nil { + return err + } + + if msg.RelayerAddress == msg.Payee { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "relayer address and payee must not be equal") + } + + _, err := sdk.AccAddressFromBech32(msg.RelayerAddress) + if err != nil { + return sdkerrors.Wrap(err, "failed to create sdk.AccAddress from relayer address") + } + + _, err = sdk.AccAddressFromBech32(msg.Payee) + if err != nil { + return sdkerrors.Wrap(err, "failed to create sdk.AccAddress from payee address") + } + + return nil +} + +// GetSigners implements sdk.Msg +func (msg MsgRegisterPayee) GetSigners() []sdk.AccAddress { + signer, err := sdk.AccAddressFromBech32(msg.RelayerAddress) + if err != nil { + panic(err) + } + + return []sdk.AccAddress{signer} +} + // NewMsgRegisterCounterpartyAddress creates a new instance of MsgRegisterCounterpartyAddress func NewMsgRegisterCounterpartyAddress(portID, channelID, address, counterpartyAddress string) *MsgRegisterCounterpartyAddress { return &MsgRegisterCounterpartyAddress{ diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go index 17452a64b45..4ca23fea458 100644 --- a/modules/apps/29-fee/types/msgs_test.go +++ b/modules/apps/29-fee/types/msgs_test.go @@ -12,6 +12,81 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" ) +func TestMsgRegisterPayeeValidation(t *testing.T) { + var msg *types.MsgRegisterPayee + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "invalid portID", + func() { + msg.PortId = "" + }, + false, + }, + { + "invalid channelID", + func() { + msg.ChannelId = "" + }, + false, + }, + { + "invalid request relayer and payee are equal", + func() { + msg.RelayerAddress = defaultAccAddress + msg.Payee = defaultAccAddress + }, + false, + }, + { + "invalid relayer address", + func() { + msg.RelayerAddress = "invalid-address" + }, + false, + }, + { + "invalid payee address", + func() { + msg.Payee = "invalid-address" + }, + false, + }, + } + + for i, tc := range testCases { + relayerAddr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + payeeAddr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + + msg = types.NewMsgRegisterPayee(ibctesting.MockPort, ibctesting.FirstChannelID, relayerAddr.String(), payeeAddr.String()) + + tc.malleate() + + err := msg.ValidateBasic() + + if tc.expPass { + require.NoError(t, err, "valid test case %d failed: %s", i, tc.name) + } else { + require.Error(t, err, "invalid test case %d passed: %s", i, tc.name) + } + } +} + +func TestRegisterPayeeGetSigners(t *testing.T) { + accAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + msg := types.NewMsgRegisterPayee(ibctesting.MockPort, ibctesting.FirstChannelID, accAddress.String(), defaultAccAddress) + require.Equal(t, []sdk.AccAddress{sdk.AccAddress(accAddress)}, msg.GetSigners()) +} + func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { var msg *types.MsgRegisterCounterpartyAddress diff --git a/modules/apps/29-fee/types/query.pb.go b/modules/apps/29-fee/types/query.pb.go index 32677378fe3..1a9eba1927f 100644 --- a/modules/apps/29-fee/types/query.pb.go +++ b/modules/apps/29-fee/types/query.pb.go @@ -966,88 +966,88 @@ func init() { } var fileDescriptor_0638a8a78ca2503c = []byte{ - // 1281 bytes of a gzipped FileDescriptorProto + // 1285 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x4f, 0x6f, 0x1b, 0x45, 0x1c, 0xcd, 0xa4, 0xa1, 0x4d, 0x26, 0xa1, 0x4d, 0xc7, 0xa1, 0x4d, 0x4d, 0x62, 0xa7, 0x53, 0x0a, - 0x21, 0x28, 0xbb, 0x8a, 0x43, 0x9b, 0x96, 0x53, 0x6b, 0x43, 0x68, 0x04, 0x82, 0x76, 0x95, 0x0b, - 0x08, 0xe4, 0xae, 0x77, 0xc7, 0xce, 0x2a, 0xce, 0xce, 0x76, 0x77, 0x6d, 0x70, 0xd3, 0x20, 0x35, - 0x52, 0x84, 0x04, 0x15, 0x42, 0x42, 0xe2, 0x80, 0xb8, 0x22, 0x24, 0x24, 0xb8, 0xf3, 0x0d, 0x7a, - 0xaa, 0x2a, 0x71, 0xe1, 0x64, 0xaa, 0x84, 0x4f, 0x60, 0x71, 0x40, 0xe2, 0x82, 0x76, 0x66, 0x76, - 0xbd, 0xee, 0xee, 0x26, 0xde, 0x92, 0x88, 0x53, 0xec, 0xf9, 0xfd, 0x99, 0xf7, 0xde, 0xfc, 0x3c, - 0xf3, 0x14, 0x78, 0xc1, 0xa8, 0x68, 0xb2, 0x6a, 0x59, 0x75, 0x43, 0x53, 0x5d, 0x83, 0x9a, 0x8e, - 0x5c, 0x25, 0x44, 0x6e, 0x2e, 0xc8, 0x77, 0x1a, 0xc4, 0x6e, 0x49, 0x96, 0x4d, 0x5d, 0x8a, 0xce, - 0x1a, 0x15, 0x4d, 0x0a, 0x27, 0x49, 0x55, 0x42, 0xa4, 0xe6, 0x42, 0x76, 0xa2, 0x46, 0x6b, 0x94, - 0xe5, 0xc8, 0xde, 0x27, 0x9e, 0x9e, 0x9d, 0xaa, 0x51, 0x5a, 0xab, 0x13, 0x59, 0xb5, 0x0c, 0x59, - 0x35, 0x4d, 0xea, 0x8a, 0x22, 0x1e, 0xcd, 0x69, 0xd4, 0xd9, 0xa0, 0x8e, 0x5c, 0x51, 0x1d, 0x6f, - 0xa3, 0x0a, 0x71, 0xd5, 0x05, 0x59, 0xa3, 0x86, 0x29, 0xe2, 0x73, 0xe1, 0x38, 0x43, 0x11, 0x64, - 0x59, 0x6a, 0xcd, 0x30, 0x59, 0x33, 0x91, 0x7b, 0x3e, 0x09, 0xbd, 0x87, 0x8f, 0xa7, 0x5c, 0x4c, - 0x4a, 0xa9, 0x11, 0x93, 0x38, 0x86, 0x13, 0xee, 0xa4, 0x51, 0x9b, 0xc8, 0xda, 0x9a, 0x6a, 0x9a, - 0xa4, 0xee, 0xa5, 0x88, 0x8f, 0x3c, 0x05, 0x3f, 0x00, 0x30, 0x7f, 0xcb, 0xc3, 0xb3, 0x62, 0x6a, - 0xc4, 0x74, 0x8d, 0xa6, 0x71, 0x97, 0xe8, 0x37, 0x55, 0x6d, 0x9d, 0xb8, 0x8e, 0x42, 0xee, 0x34, - 0x88, 0xe3, 0xa2, 0x65, 0x08, 0xbb, 0x20, 0x27, 0xc1, 0x0c, 0x98, 0x1d, 0x2d, 0xbc, 0x2c, 0x71, - 0x46, 0x92, 0xc7, 0x48, 0xe2, 0xba, 0x0a, 0x46, 0xd2, 0x4d, 0xb5, 0x46, 0x44, 0xad, 0x12, 0xaa, - 0x44, 0xe7, 0xe1, 0x18, 0x4b, 0x2c, 0xaf, 0x11, 0xa3, 0xb6, 0xe6, 0x4e, 0x0e, 0xce, 0x80, 0xd9, - 0x21, 0x65, 0x94, 0xad, 0xdd, 0x60, 0x4b, 0xf8, 0x0b, 0x00, 0x67, 0x92, 0xe1, 0x38, 0x16, 0x35, - 0x1d, 0x82, 0xaa, 0x70, 0xc2, 0x08, 0x85, 0xcb, 0x16, 0x8f, 0x4f, 0x82, 0x99, 0x63, 0xb3, 0xa3, - 0x85, 0x79, 0x29, 0xe1, 0x60, 0xa5, 0x15, 0xdd, 0xab, 0xa9, 0x1a, 0x7e, 0xc7, 0x65, 0x42, 0x9c, - 0xe2, 0xd0, 0xc3, 0x76, 0x7e, 0x40, 0xc9, 0x18, 0xd1, 0xfd, 0xf0, 0x0e, 0x80, 0xb9, 0x04, 0x30, - 0xbe, 0x34, 0xd7, 0xe0, 0x08, 0xdf, 0xbd, 0x6c, 0xe8, 0x42, 0x99, 0x69, 0xb6, 0xbf, 0xa7, 0xba, - 0xe4, 0x4b, 0xdd, 0xf4, 0x34, 0xf1, 0xb2, 0x56, 0x74, 0xb1, 0xdf, 0xb0, 0x25, 0xbe, 0xf7, 0x23, - 0xca, 0xe7, 0xc9, 0x67, 0x14, 0x68, 0xa2, 0xc3, 0x4c, 0x8c, 0x26, 0x02, 0xd2, 0x33, 0x49, 0x82, - 0xa2, 0x92, 0xe0, 0x47, 0x00, 0xbe, 0x9a, 0x74, 0x3c, 0xcb, 0xd4, 0x2e, 0x71, 0xbe, 0x87, 0x3d, - 0x37, 0x67, 0xe1, 0x09, 0x8b, 0xda, 0x4c, 0x62, 0x4f, 0x9d, 0x11, 0xe5, 0xb8, 0xf7, 0x75, 0x45, - 0x47, 0xd3, 0x10, 0x0a, 0x89, 0xbd, 0xd8, 0x31, 0x16, 0x1b, 0x11, 0x2b, 0x31, 0xd2, 0x0e, 0x45, - 0xa5, 0xfd, 0x0a, 0xc0, 0xb9, 0x7e, 0x08, 0x09, 0x95, 0x6f, 0x1f, 0xe2, 0xe4, 0xc5, 0xcf, 0xdc, - 0xc7, 0xf0, 0x1c, 0xc3, 0xb3, 0x4a, 0x5d, 0xb5, 0xae, 0x10, 0xad, 0xc9, 0x52, 0x0f, 0x6b, 0xda, - 0xf0, 0x77, 0x00, 0x66, 0xe3, 0xfa, 0x0b, 0x7e, 0xf7, 0xe0, 0x88, 0x4d, 0xb4, 0x66, 0xb9, 0x4a, - 0x88, 0x4f, 0xea, 0x5c, 0xcf, 0x81, 0xf9, 0x47, 0x55, 0xa2, 0x86, 0x59, 0x7c, 0xd3, 0x6b, 0xde, - 0x69, 0xe7, 0xc7, 0x5b, 0xea, 0x46, 0xfd, 0x0d, 0x1c, 0x54, 0xe2, 0x9f, 0xfe, 0xc8, 0xcf, 0xd6, - 0x0c, 0x77, 0xad, 0x51, 0x91, 0x34, 0xba, 0x21, 0x8b, 0xbb, 0x8f, 0xff, 0x99, 0x77, 0xf4, 0x75, - 0xd9, 0x6d, 0x59, 0xc4, 0x61, 0x4d, 0x1c, 0x65, 0xd8, 0x16, 0x28, 0xf0, 0x47, 0x70, 0xb2, 0x8b, - 0xed, 0xba, 0xb6, 0x7e, 0xb8, 0xd4, 0xbf, 0x05, 0x61, 0x69, 0x83, 0xf6, 0x82, 0x79, 0x0b, 0x0e, - 0xab, 0xda, 0x7a, 0x9f, 0xc4, 0x4b, 0x82, 0xf8, 0x29, 0x4e, 0xdc, 0x2f, 0x4c, 0xc7, 0xfb, 0x84, - 0xca, 0x21, 0xe0, 0xdb, 0x70, 0xaa, 0x8b, 0x6b, 0xd5, 0xd8, 0x20, 0xb4, 0xe1, 0x1e, 0x2e, 0xf5, - 0x1f, 0x01, 0x9c, 0x4e, 0xd8, 0x42, 0xd0, 0xdf, 0x01, 0x70, 0xcc, 0xe5, 0xeb, 0x7d, 0x6a, 0xf0, - 0xb6, 0xd0, 0x20, 0xc3, 0x35, 0x08, 0x17, 0xa7, 0xd3, 0x61, 0xd4, 0xed, 0xe2, 0xc1, 0xdf, 0xfb, - 0x57, 0x5d, 0x89, 0x36, 0x4c, 0x97, 0xd8, 0x96, 0x6a, 0xbb, 0xad, 0xeb, 0xba, 0x6e, 0x13, 0x27, - 0xd0, 0xe3, 0xf5, 0x9e, 0x5f, 0xbd, 0x27, 0xc8, 0x48, 0xf1, 0x85, 0x4e, 0x3b, 0x7f, 0x9a, 0x23, - 0xe9, 0xc6, 0x70, 0xf8, 0x32, 0x28, 0xc1, 0x53, 0x36, 0xa9, 0xab, 0x2d, 0x62, 0x97, 0x55, 0xde, - 0x8f, 0x5f, 0x26, 0xc5, 0x6c, 0xa7, 0x9d, 0x3f, 0xe3, 0x4f, 0x70, 0x4f, 0x02, 0x56, 0x4e, 0x8a, - 0x15, 0x81, 0x00, 0x37, 0xc5, 0xeb, 0x14, 0x8b, 0x4e, 0x48, 0xa9, 0xc0, 0x09, 0x2d, 0x14, 0x0e, - 0x76, 0xe3, 0x40, 0xf3, 0x9d, 0x76, 0xfe, 0x45, 0x01, 0x34, 0x26, 0x0b, 0x2b, 0x19, 0x2d, 0xda, - 0x1b, 0x7f, 0xe9, 0xbf, 0x44, 0xcb, 0x84, 0xbc, 0x65, 0xaa, 0x95, 0x3a, 0xd1, 0xc5, 0xd5, 0xf4, - 0x7f, 0x3c, 0xd2, 0x3f, 0xf8, 0x87, 0x14, 0x87, 0x46, 0xa8, 0x70, 0x1f, 0xc0, 0x89, 0x2a, 0x21, - 0x65, 0xc2, 0xe3, 0x65, 0x71, 0x10, 0xfe, 0x60, 0xcd, 0x25, 0x5e, 0x95, 0x91, 0x9e, 0xc5, 0x0b, - 0x62, 0xd2, 0x84, 0x6c, 0x71, 0x5d, 0xb1, 0x82, 0xaa, 0x11, 0x2c, 0x78, 0xdb, 0x1f, 0xfb, 0x48, - 0x4f, 0x5f, 0xb4, 0xd7, 0xba, 0x2f, 0x0b, 0x3f, 0x1e, 0xd4, 0x69, 0xe7, 0x4f, 0xf2, 0x7d, 0x44, - 0x00, 0x07, 0xaf, 0x4d, 0xef, 0xdc, 0x0d, 0xf6, 0x37, 0x77, 0xf8, 0x83, 0xa4, 0x93, 0x0b, 0xa4, - 0x5a, 0x82, 0xa3, 0x21, 0x4e, 0x0c, 0xc8, 0x70, 0xf1, 0x4c, 0xa7, 0x9d, 0x47, 0x11, 0xc2, 0x58, - 0x81, 0x5d, 0x9e, 0x85, 0x5f, 0xc6, 0xe1, 0x73, 0xac, 0x37, 0xfa, 0x15, 0xc0, 0x4c, 0xcc, 0x0b, - 0x86, 0xae, 0x24, 0xca, 0x7c, 0x80, 0xe7, 0xcb, 0x5e, 0x7d, 0x86, 0x4a, 0xce, 0x07, 0xcf, 0x6f, - 0xff, 0xf6, 0xe7, 0x37, 0x83, 0xaf, 0xa0, 0x8b, 0xb2, 0x70, 0xa9, 0x81, 0x3b, 0x8d, 0x7b, 0x3b, - 0xd1, 0x83, 0x41, 0x88, 0xa2, 0xed, 0xd0, 0x52, 0x5a, 0x00, 0x3e, 0xf2, 0x2b, 0xe9, 0x0b, 0x05, - 0xf0, 0x6d, 0xc0, 0x90, 0xdf, 0x43, 0x77, 0xfb, 0x41, 0x2e, 0x7b, 0x63, 0x21, 0x6f, 0x06, 0x57, - 0xb3, 0x24, 0x06, 0x66, 0x2b, 0x30, 0xdb, 0xa1, 0x58, 0x77, 0x38, 0xb6, 0x64, 0xc7, 0x03, 0x6a, - 0x6a, 0x24, 0x1c, 0xf7, 0xd7, 0xb6, 0xd0, 0x3f, 0x00, 0x4e, 0xef, 0x6b, 0x46, 0x50, 0x31, 0xf5, - 0xd1, 0x44, 0xac, 0x59, 0xb6, 0xf4, 0x9f, 0x7a, 0x08, 0xbd, 0x6e, 0x31, 0xb9, 0xde, 0x41, 0x2b, - 0x7d, 0x1d, 0xb4, 0xaf, 0x57, 0x44, 0xa5, 0x90, 0x36, 0xe8, 0x6f, 0x00, 0x9f, 0xef, 0xb1, 0x26, - 0xa8, 0xb0, 0x3f, 0xd2, 0x38, 0x9f, 0x94, 0x5d, 0x4c, 0x55, 0x23, 0xd8, 0x7c, 0xc6, 0xd8, 0x7c, - 0x8a, 0x9a, 0x11, 0x36, 0xae, 0x97, 0x5f, 0x0e, 0xec, 0xcd, 0x11, 0x1d, 0xfc, 0x5f, 0x00, 0x8e, - 0x85, 0xad, 0x09, 0x5a, 0xe8, 0x83, 0x45, 0xaf, 0x4b, 0xca, 0x16, 0xd2, 0x94, 0x08, 0xde, 0x5b, - 0x8c, 0xf7, 0x27, 0xa8, 0x91, 0xc0, 0xdb, 0x77, 0x37, 0x47, 0x44, 0x7b, 0x67, 0x10, 0x8e, 0x3f, - 0x6d, 0x4b, 0xd0, 0xa5, 0x3e, 0x78, 0x44, 0x9d, 0x52, 0xf6, 0x72, 0xda, 0x32, 0x21, 0xc1, 0x7d, - 0xfe, 0xc3, 0xdf, 0x44, 0xad, 0x04, 0x0d, 0xc2, 0xee, 0xe6, 0x88, 0x74, 0x78, 0x02, 0x60, 0x26, - 0xc6, 0x56, 0x1c, 0x74, 0x85, 0x27, 0xfb, 0xa4, 0x83, 0xae, 0xf0, 0x7d, 0x3c, 0x0c, 0x5e, 0x65, - 0x7a, 0xbc, 0x87, 0xde, 0x8d, 0xe8, 0x11, 0x67, 0x5a, 0xe4, 0xcd, 0xa7, 0x8c, 0x53, 0xc2, 0x8f, - 0xfb, 0x67, 0x00, 0x51, 0xd4, 0x32, 0x1c, 0x74, 0xd3, 0x27, 0x5a, 0x9e, 0x83, 0x6e, 0xfa, 0x64, - 0x77, 0x82, 0x5f, 0x62, 0xfc, 0x72, 0x68, 0x2a, 0xc2, 0x2f, 0xf4, 0xd8, 0xa2, 0x47, 0x00, 0x9e, - 0x8e, 0x34, 0x41, 0x97, 0x53, 0xee, 0xea, 0xa3, 0x5d, 0x4a, 0x5d, 0x27, 0xc0, 0xde, 0x60, 0x60, - 0x8b, 0xe8, 0xda, 0x7e, 0x60, 0xfb, 0xb9, 0x5d, 0x8b, 0xef, 0x3f, 0xdc, 0xcd, 0x81, 0xc7, 0xbb, - 0x39, 0xf0, 0x64, 0x37, 0x07, 0xbe, 0xde, 0xcb, 0x0d, 0x3c, 0xde, 0xcb, 0x0d, 0xfc, 0xbe, 0x97, - 0x1b, 0xf8, 0xf0, 0x52, 0xd4, 0xae, 0x1b, 0x15, 0x6d, 0xbe, 0x46, 0xe5, 0xe6, 0xa2, 0xbc, 0x41, - 0xf5, 0x46, 0x9d, 0x38, 0x7c, 0xeb, 0xc2, 0xd5, 0x79, 0x6f, 0x77, 0xe6, 0xe0, 0x2b, 0xc7, 0xd9, - 0x3f, 0x91, 0x16, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x61, 0x8e, 0x05, 0x2f, 0x71, 0x13, 0x00, - 0x00, + 0x21, 0x28, 0xbb, 0x8a, 0x43, 0x9b, 0x96, 0x13, 0xb5, 0x4b, 0x20, 0x20, 0x44, 0x59, 0x2a, 0x04, + 0x08, 0x70, 0xd7, 0xbb, 0x63, 0x67, 0x15, 0x67, 0x67, 0xbb, 0xbb, 0xb6, 0x70, 0xd3, 0x00, 0xad, + 0x88, 0x40, 0x80, 0x00, 0x09, 0x89, 0x03, 0xe2, 0x8a, 0x90, 0x90, 0xf8, 0x00, 0x7c, 0x83, 0x8a, + 0x03, 0x8a, 0xc4, 0x85, 0x93, 0x41, 0x09, 0x27, 0x8e, 0x3e, 0x71, 0x00, 0x09, 0xed, 0xcc, 0xec, + 0x7a, 0xdd, 0xdd, 0x4d, 0xec, 0x60, 0x85, 0x53, 0xec, 0xf9, 0xfd, 0x99, 0xf7, 0xde, 0xfc, 0x3c, + 0xf3, 0x14, 0x78, 0xce, 0x28, 0x69, 0xb2, 0x6a, 0x59, 0x55, 0x43, 0x53, 0x5d, 0x83, 0x9a, 0x8e, + 0x5c, 0x26, 0x44, 0xae, 0x2f, 0xc8, 0x37, 0x6b, 0xc4, 0x6e, 0x48, 0x96, 0x4d, 0x5d, 0x8a, 0x4e, + 0x1b, 0x25, 0x4d, 0x0a, 0x27, 0x49, 0x65, 0x42, 0xa4, 0xfa, 0x42, 0x7a, 0xa2, 0x42, 0x2b, 0x94, + 0xe5, 0xc8, 0xde, 0x27, 0x9e, 0x9e, 0x9e, 0xaa, 0x50, 0x5a, 0xa9, 0x12, 0x59, 0xb5, 0x0c, 0x59, + 0x35, 0x4d, 0xea, 0x8a, 0x22, 0x1e, 0xcd, 0x68, 0xd4, 0x59, 0xa7, 0x8e, 0x5c, 0x52, 0x1d, 0x6f, + 0xa3, 0x12, 0x71, 0xd5, 0x05, 0x59, 0xa3, 0x86, 0x29, 0xe2, 0x73, 0xe1, 0x38, 0x43, 0x11, 0x64, + 0x59, 0x6a, 0xc5, 0x30, 0x59, 0x33, 0x91, 0x7b, 0x36, 0x09, 0xbd, 0x87, 0x8f, 0xa7, 0x9c, 0x4f, + 0x4a, 0xa9, 0x10, 0x93, 0x38, 0x86, 0x13, 0xee, 0xa4, 0x51, 0x9b, 0xc8, 0xda, 0xaa, 0x6a, 0x9a, + 0xa4, 0xea, 0xa5, 0x88, 0x8f, 0x3c, 0x05, 0x7f, 0x0a, 0x60, 0xf6, 0x65, 0x0f, 0xcf, 0x8a, 0xa9, + 0x11, 0xd3, 0x35, 0xea, 0xc6, 0x2d, 0xa2, 0x5f, 0x53, 0xb5, 0x35, 0xe2, 0x3a, 0x0a, 0xb9, 0x59, + 0x23, 0x8e, 0x8b, 0x96, 0x21, 0x6c, 0x83, 0x9c, 0x04, 0x33, 0x60, 0x76, 0x34, 0xf7, 0xa8, 0xc4, + 0x19, 0x49, 0x1e, 0x23, 0x89, 0xeb, 0x2a, 0x18, 0x49, 0xd7, 0xd4, 0x0a, 0x11, 0xb5, 0x4a, 0xa8, + 0x12, 0x9d, 0x85, 0x63, 0x2c, 0xb1, 0xb8, 0x4a, 0x8c, 0xca, 0xaa, 0x3b, 0x39, 0x38, 0x03, 0x66, + 0x87, 0x94, 0x51, 0xb6, 0xf6, 0x1c, 0x5b, 0xc2, 0x1f, 0x03, 0x38, 0x93, 0x0c, 0xc7, 0xb1, 0xa8, + 0xe9, 0x10, 0x54, 0x86, 0x13, 0x46, 0x28, 0x5c, 0xb4, 0x78, 0x7c, 0x12, 0xcc, 0x1c, 0x99, 0x1d, + 0xcd, 0xcd, 0x4b, 0x09, 0x07, 0x2b, 0xad, 0xe8, 0x5e, 0x4d, 0xd9, 0xf0, 0x3b, 0x2e, 0x13, 0xe2, + 0xe4, 0x87, 0xee, 0x35, 0xb3, 0x03, 0x4a, 0xca, 0x88, 0xee, 0x87, 0xb7, 0x00, 0xcc, 0x24, 0x80, + 0xf1, 0xa5, 0x79, 0x1a, 0x8e, 0xf0, 0xdd, 0x8b, 0x86, 0x2e, 0x94, 0x99, 0x66, 0xfb, 0x7b, 0xaa, + 0x4b, 0xbe, 0xd4, 0x75, 0x4f, 0x13, 0x2f, 0x6b, 0x45, 0x17, 0xfb, 0x0d, 0x5b, 0xe2, 0x7b, 0x37, + 0xa2, 0x7c, 0x98, 0x7c, 0x46, 0x81, 0x26, 0x3a, 0x4c, 0xc5, 0x68, 0x22, 0x20, 0x1d, 0x48, 0x12, + 0x14, 0x95, 0x04, 0xff, 0x0c, 0xe0, 0xe3, 0x49, 0xc7, 0xb3, 0x4c, 0xed, 0x02, 0xe7, 0xdb, 0xef, + 0xb9, 0x39, 0x0d, 0x8f, 0x59, 0xd4, 0x66, 0x12, 0x7b, 0xea, 0x8c, 0x28, 0x47, 0xbd, 0xaf, 0x2b, + 0x3a, 0x9a, 0x86, 0x50, 0x48, 0xec, 0xc5, 0x8e, 0xb0, 0xd8, 0x88, 0x58, 0x89, 0x91, 0x76, 0x28, + 0x2a, 0xed, 0x67, 0x00, 0xce, 0x75, 0x43, 0x48, 0xa8, 0x7c, 0xa3, 0x8f, 0x93, 0x17, 0x3f, 0x73, + 0x6f, 0xc1, 0x33, 0x0c, 0xcf, 0x75, 0xea, 0xaa, 0x55, 0x85, 0x68, 0x75, 0x96, 0xda, 0xaf, 0x69, + 0xc3, 0x5f, 0x03, 0x98, 0x8e, 0xeb, 0x2f, 0xf8, 0xdd, 0x86, 0x23, 0x36, 0xd1, 0xea, 0xc5, 0x32, + 0x21, 0x3e, 0xa9, 0x33, 0x1d, 0x07, 0xe6, 0x1f, 0x55, 0x81, 0x1a, 0x66, 0xfe, 0xaa, 0xd7, 0xbc, + 0xd5, 0xcc, 0x8e, 0x37, 0xd4, 0xf5, 0xea, 0x53, 0x38, 0xa8, 0xc4, 0xdf, 0xff, 0x96, 0x9d, 0xad, + 0x18, 0xee, 0x6a, 0xad, 0x24, 0x69, 0x74, 0x5d, 0x16, 0x77, 0x1f, 0xff, 0x33, 0xef, 0xe8, 0x6b, + 0xb2, 0xdb, 0xb0, 0x88, 0xc3, 0x9a, 0x38, 0xca, 0xb0, 0x2d, 0x50, 0xe0, 0x37, 0xe1, 0x64, 0x1b, + 0xdb, 0x15, 0x6d, 0xad, 0xbf, 0xd4, 0xbf, 0x02, 0x61, 0x69, 0x83, 0xf6, 0x82, 0x79, 0x03, 0x0e, + 0xab, 0xda, 0x5a, 0x97, 0xc4, 0x0b, 0x82, 0xf8, 0x09, 0x4e, 0xdc, 0x2f, 0xec, 0x8d, 0xf7, 0x31, + 0x95, 0x43, 0xc0, 0x37, 0xe0, 0x54, 0x1b, 0xd7, 0x75, 0x63, 0x9d, 0xd0, 0x9a, 0xdb, 0x5f, 0xea, + 0xdf, 0x01, 0x38, 0x9d, 0xb0, 0x85, 0xa0, 0xbf, 0x05, 0xe0, 0x98, 0xcb, 0xd7, 0xbb, 0xd4, 0xe0, + 0x59, 0xa1, 0x41, 0x8a, 0x6b, 0x10, 0x2e, 0xee, 0x4d, 0x87, 0x51, 0xb7, 0x8d, 0x07, 0x7f, 0xe3, + 0x5f, 0x75, 0x05, 0x5a, 0x33, 0x5d, 0x62, 0x5b, 0xaa, 0xed, 0x36, 0xae, 0xe8, 0xba, 0x4d, 0x9c, + 0x40, 0x8f, 0x27, 0x3b, 0x7e, 0xf5, 0x9e, 0x20, 0x23, 0xf9, 0x87, 0x5a, 0xcd, 0xec, 0x49, 0x8e, + 0xa4, 0x1d, 0xc3, 0xe1, 0xcb, 0xa0, 0x00, 0x4f, 0xd8, 0xa4, 0xaa, 0x36, 0x88, 0x5d, 0x54, 0x79, + 0x3f, 0x7e, 0x99, 0xe4, 0xd3, 0xad, 0x66, 0xf6, 0x94, 0x3f, 0xc1, 0x1d, 0x09, 0x58, 0x39, 0x2e, + 0x56, 0x04, 0x02, 0x5c, 0x17, 0xaf, 0x53, 0x2c, 0x3a, 0x21, 0xa5, 0x02, 0x27, 0xb4, 0x50, 0x38, + 0xd8, 0x8d, 0x03, 0xcd, 0xb6, 0x9a, 0xd9, 0x87, 0x05, 0xd0, 0x98, 0x2c, 0xac, 0xa4, 0xb4, 0x68, + 0x6f, 0xfc, 0x89, 0xff, 0x12, 0x2d, 0x13, 0xf2, 0x8c, 0xa9, 0x96, 0xaa, 0x44, 0x17, 0x57, 0xd3, + 0xff, 0xf1, 0x48, 0x7f, 0xeb, 0x1f, 0x52, 0x1c, 0x1a, 0xa1, 0xc2, 0x1d, 0x00, 0x27, 0xca, 0x84, + 0x14, 0x09, 0x8f, 0x17, 0xc5, 0x41, 0xf8, 0x83, 0x35, 0x97, 0x78, 0x55, 0x46, 0x7a, 0xe6, 0xcf, + 0x89, 0x49, 0x13, 0xb2, 0xc5, 0x75, 0xc5, 0x0a, 0x2a, 0x47, 0xb0, 0xe0, 0xbb, 0xfe, 0xd8, 0x47, + 0x7a, 0xfa, 0xa2, 0x3d, 0xd1, 0x7e, 0x59, 0xf8, 0xf1, 0xa0, 0x56, 0x33, 0x7b, 0x9c, 0xef, 0x23, + 0x02, 0x38, 0x78, 0x6d, 0x3a, 0xe7, 0x6e, 0xb0, 0xbb, 0xb9, 0xc3, 0xaf, 0x27, 0x9d, 0x5c, 0x20, + 0xd5, 0x12, 0x1c, 0x0d, 0x71, 0x62, 0x40, 0x86, 0xf3, 0xa7, 0x5a, 0xcd, 0x2c, 0x8a, 0x10, 0xc6, + 0x0a, 0x6c, 0xf3, 0xcc, 0xfd, 0x34, 0x0e, 0x1f, 0x60, 0xbd, 0xd1, 0x8f, 0x00, 0xa6, 0x62, 0x5e, + 0x30, 0x74, 0x29, 0x51, 0xe6, 0x7d, 0x3c, 0x5f, 0xfa, 0xf2, 0x01, 0x2a, 0x39, 0x1f, 0x3c, 0x7f, + 0xf7, 0x97, 0x3f, 0xbe, 0x1c, 0x7c, 0x0c, 0x9d, 0x97, 0x85, 0x4b, 0x0d, 0xdc, 0x69, 0xdc, 0xdb, + 0x89, 0x3e, 0x1f, 0x84, 0x28, 0xda, 0x0e, 0x2d, 0xf5, 0x0a, 0xc0, 0x47, 0x7e, 0xa9, 0xf7, 0x42, + 0x01, 0x7c, 0x0b, 0x30, 0xe4, 0xef, 0xa1, 0xcd, 0x08, 0x72, 0x7f, 0xd0, 0xe4, 0x8d, 0xe0, 0x2a, + 0x96, 0xda, 0x07, 0xbe, 0x29, 0x7b, 0x23, 0xd2, 0x11, 0x14, 0xd3, 0xb3, 0x29, 0x3b, 0x1e, 0x2c, + 0x53, 0x23, 0x1d, 0x51, 0x7f, 0x71, 0x33, 0x4e, 0x12, 0xf4, 0x0f, 0x80, 0xd3, 0x7b, 0xfa, 0x11, + 0x94, 0xef, 0xf9, 0x74, 0x22, 0xee, 0x2c, 0x5d, 0xf8, 0x4f, 0x3d, 0x84, 0x64, 0xaf, 0x30, 0xc5, + 0x5e, 0x44, 0x2f, 0xec, 0xa1, 0x58, 0x9c, 0x4e, 0xbe, 0x3a, 0xb1, 0x13, 0xf1, 0x37, 0x80, 0x0f, + 0x76, 0xf8, 0x13, 0x94, 0xdb, 0x1b, 0x6b, 0x9c, 0x59, 0x4a, 0x2f, 0xf6, 0x54, 0x23, 0xf8, 0xdc, + 0xe1, 0x23, 0xb0, 0x81, 0x1a, 0x87, 0x37, 0x02, 0xae, 0x87, 0xa4, 0x18, 0xb8, 0x27, 0xf4, 0x17, + 0x80, 0x63, 0x61, 0x8f, 0x82, 0x16, 0xba, 0x60, 0xd2, 0x69, 0x97, 0xd2, 0xb9, 0x5e, 0x4a, 0x04, + 0xf7, 0xf7, 0x39, 0xf7, 0x5b, 0xe8, 0x9d, 0xc3, 0xe6, 0xee, 0x1b, 0x28, 0xf4, 0xd1, 0x20, 0x1c, + 0xbf, 0xdf, 0xa3, 0xa0, 0x0b, 0x5d, 0x70, 0x89, 0xda, 0xa6, 0xf4, 0xc5, 0x5e, 0xcb, 0x84, 0x0c, + 0x1f, 0x70, 0x19, 0xde, 0x45, 0xb7, 0x0f, 0x5b, 0x86, 0xb0, 0x87, 0x42, 0x7f, 0x02, 0x98, 0x8a, + 0xb1, 0x19, 0xfb, 0x5d, 0xe9, 0xc9, 0xbe, 0x69, 0xbf, 0x2b, 0x7d, 0x0f, 0x4f, 0x83, 0xdf, 0x66, + 0x92, 0xbc, 0x86, 0x5e, 0xed, 0xf2, 0x67, 0x2e, 0x6c, 0x93, 0x23, 0x6f, 0xdc, 0x67, 0xa9, 0x36, + 0xe5, 0x38, 0xd7, 0x83, 0x7e, 0x00, 0x10, 0x45, 0xcd, 0xc4, 0x7e, 0x6f, 0x40, 0xa2, 0x19, 0xda, + 0xef, 0x0d, 0x48, 0xf6, 0x2d, 0xf8, 0x11, 0xc6, 0x34, 0x83, 0xa6, 0x22, 0x4c, 0x43, 0xcf, 0x30, + 0xda, 0x06, 0xf0, 0x64, 0xa4, 0x09, 0xba, 0xd8, 0xe3, 0xae, 0x3e, 0xda, 0xa5, 0x9e, 0xeb, 0x04, + 0xd8, 0xe7, 0x19, 0xd8, 0xab, 0x28, 0x7f, 0xc0, 0xdb, 0x37, 0x44, 0x29, 0xff, 0xd2, 0xbd, 0x9d, + 0x0c, 0xd8, 0xde, 0xc9, 0x80, 0xdf, 0x77, 0x32, 0xe0, 0x8b, 0xdd, 0xcc, 0xc0, 0xf6, 0x6e, 0x66, + 0xe0, 0xd7, 0xdd, 0xcc, 0xc0, 0x1b, 0x17, 0xa2, 0x56, 0xde, 0x28, 0x69, 0xf3, 0x15, 0x2a, 0xd7, + 0x17, 0xe5, 0x75, 0xaa, 0xd7, 0xaa, 0xc4, 0xe1, 0x9b, 0xe7, 0x2e, 0xcf, 0x7b, 0xfb, 0x33, 0x77, + 0x5f, 0x3a, 0xca, 0xfe, 0xc1, 0xb4, 0xf8, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x50, 0x32, 0x7d, + 0x07, 0x8d, 0x13, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/apps/29-fee/types/query.pb.gw.go b/modules/apps/29-fee/types/query.pb.gw.go index 9b9e47c5939..712c7f32727 100644 --- a/modules/apps/29-fee/types/query.pb.gw.go +++ b/modules/apps/29-fee/types/query.pb.gw.go @@ -68,7 +68,7 @@ func local_request_Query_IncentivizedPackets_0(ctx context.Context, marshaler ru } var ( - filter_Query_IncentivizedPacket_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "port_id": 1, "channel_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} + filter_Query_IncentivizedPacket_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "channel_id": 1, "port_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} ) func request_Query_IncentivizedPacket_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -82,26 +82,26 @@ func request_Query_IncentivizedPacket_0(ctx context.Context, marshaler runtime.M _ = err ) - val, ok = pathParams["packet_id.port_id"] + val, ok = pathParams["packet_id.channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) } - val, ok = pathParams["packet_id.channel_id"] + val, ok = pathParams["packet_id.port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) } val, ok = pathParams["packet_id.sequence"] @@ -138,26 +138,26 @@ func local_request_Query_IncentivizedPacket_0(ctx context.Context, marshaler run _ = err ) - val, ok = pathParams["packet_id.port_id"] + val, ok = pathParams["packet_id.channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) } - val, ok = pathParams["packet_id.channel_id"] + val, ok = pathParams["packet_id.port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) } val, ok = pathParams["packet_id.sequence"] @@ -184,7 +184,7 @@ func local_request_Query_IncentivizedPacket_0(ctx context.Context, marshaler run } var ( - filter_Query_IncentivizedPacketsForChannel_0 = &utilities.DoubleArray{Encoding: map[string]int{"port_id": 0, "channel_id": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} + filter_Query_IncentivizedPacketsForChannel_0 = &utilities.DoubleArray{Encoding: map[string]int{"channel_id": 0, "port_id": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} ) func request_Query_IncentivizedPacketsForChannel_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -198,26 +198,26 @@ func request_Query_IncentivizedPacketsForChannel_0(ctx context.Context, marshale _ = err ) - val, ok = pathParams["port_id"] + val, ok = pathParams["channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") } - protoReq.PortId, err = runtime.String(val) + protoReq.ChannelId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["channel_id"] + val, ok = pathParams["port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") } - protoReq.ChannelId, err = runtime.String(val) + protoReq.PortId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) } if err := req.ParseForm(); err != nil { @@ -243,26 +243,26 @@ func local_request_Query_IncentivizedPacketsForChannel_0(ctx context.Context, ma _ = err ) - val, ok = pathParams["port_id"] + val, ok = pathParams["channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") } - protoReq.PortId, err = runtime.String(val) + protoReq.ChannelId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["channel_id"] + val, ok = pathParams["port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") } - protoReq.ChannelId, err = runtime.String(val) + protoReq.PortId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) } if err := req.ParseForm(); err != nil { @@ -278,7 +278,7 @@ func local_request_Query_IncentivizedPacketsForChannel_0(ctx context.Context, ma } var ( - filter_Query_TotalRecvFees_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "port_id": 1, "channel_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} + filter_Query_TotalRecvFees_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "channel_id": 1, "port_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} ) func request_Query_TotalRecvFees_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -292,26 +292,26 @@ func request_Query_TotalRecvFees_0(ctx context.Context, marshaler runtime.Marsha _ = err ) - val, ok = pathParams["packet_id.port_id"] + val, ok = pathParams["packet_id.channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) } - val, ok = pathParams["packet_id.channel_id"] + val, ok = pathParams["packet_id.port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) } val, ok = pathParams["packet_id.sequence"] @@ -348,26 +348,26 @@ func local_request_Query_TotalRecvFees_0(ctx context.Context, marshaler runtime. _ = err ) - val, ok = pathParams["packet_id.port_id"] + val, ok = pathParams["packet_id.channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) } - val, ok = pathParams["packet_id.channel_id"] + val, ok = pathParams["packet_id.port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) } val, ok = pathParams["packet_id.sequence"] @@ -394,7 +394,7 @@ func local_request_Query_TotalRecvFees_0(ctx context.Context, marshaler runtime. } var ( - filter_Query_TotalAckFees_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "port_id": 1, "channel_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} + filter_Query_TotalAckFees_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "channel_id": 1, "port_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} ) func request_Query_TotalAckFees_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -408,26 +408,26 @@ func request_Query_TotalAckFees_0(ctx context.Context, marshaler runtime.Marshal _ = err ) - val, ok = pathParams["packet_id.port_id"] + val, ok = pathParams["packet_id.channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) } - val, ok = pathParams["packet_id.channel_id"] + val, ok = pathParams["packet_id.port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) } val, ok = pathParams["packet_id.sequence"] @@ -464,26 +464,26 @@ func local_request_Query_TotalAckFees_0(ctx context.Context, marshaler runtime.M _ = err ) - val, ok = pathParams["packet_id.port_id"] + val, ok = pathParams["packet_id.channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) } - val, ok = pathParams["packet_id.channel_id"] + val, ok = pathParams["packet_id.port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) } val, ok = pathParams["packet_id.sequence"] @@ -510,7 +510,7 @@ func local_request_Query_TotalAckFees_0(ctx context.Context, marshaler runtime.M } var ( - filter_Query_TotalTimeoutFees_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "port_id": 1, "channel_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} + filter_Query_TotalTimeoutFees_0 = &utilities.DoubleArray{Encoding: map[string]int{"packet_id": 0, "channel_id": 1, "port_id": 2, "sequence": 3}, Base: []int{1, 1, 1, 2, 3, 0, 0, 0}, Check: []int{0, 1, 2, 2, 2, 3, 4, 5}} ) func request_Query_TotalTimeoutFees_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { @@ -524,26 +524,26 @@ func request_Query_TotalTimeoutFees_0(ctx context.Context, marshaler runtime.Mar _ = err ) - val, ok = pathParams["packet_id.port_id"] + val, ok = pathParams["packet_id.channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) } - val, ok = pathParams["packet_id.channel_id"] + val, ok = pathParams["packet_id.port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) } val, ok = pathParams["packet_id.sequence"] @@ -580,26 +580,26 @@ func local_request_Query_TotalTimeoutFees_0(ctx context.Context, marshaler runti _ = err ) - val, ok = pathParams["packet_id.port_id"] + val, ok = pathParams["packet_id.channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) } - val, ok = pathParams["packet_id.channel_id"] + val, ok = pathParams["packet_id.port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "packet_id.port_id") } - err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.channel_id", val) + err = runtime.PopulateFieldFromPath(&protoReq, "packet_id.port_id", val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "packet_id.port_id", err) } val, ok = pathParams["packet_id.sequence"] @@ -636,26 +636,26 @@ func request_Query_CounterpartyAddress_0(ctx context.Context, marshaler runtime. _ = err ) - val, ok = pathParams["relayer_address"] + val, ok = pathParams["channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") } - protoReq.RelayerAddress, err = runtime.String(val) + protoReq.ChannelId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["channel_id"] + val, ok = pathParams["relayer_address"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") } - protoReq.ChannelId, err = runtime.String(val) + protoReq.RelayerAddress, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) } msg, err := client.CounterpartyAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -674,26 +674,26 @@ func local_request_Query_CounterpartyAddress_0(ctx context.Context, marshaler ru _ = err ) - val, ok = pathParams["relayer_address"] + val, ok = pathParams["channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") } - protoReq.RelayerAddress, err = runtime.String(val) + protoReq.ChannelId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["channel_id"] + val, ok = pathParams["relayer_address"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") } - protoReq.ChannelId, err = runtime.String(val) + protoReq.RelayerAddress, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) } msg, err := server.CounterpartyAddress(ctx, &protoReq) @@ -748,26 +748,26 @@ func request_Query_FeeEnabledChannel_0(ctx context.Context, marshaler runtime.Ma _ = err ) - val, ok = pathParams["port_id"] + val, ok = pathParams["channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") } - protoReq.PortId, err = runtime.String(val) + protoReq.ChannelId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["channel_id"] + val, ok = pathParams["port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") } - protoReq.ChannelId, err = runtime.String(val) + protoReq.PortId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) } msg, err := client.FeeEnabledChannel(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -786,26 +786,26 @@ func local_request_Query_FeeEnabledChannel_0(ctx context.Context, marshaler runt _ = err ) - val, ok = pathParams["port_id"] + val, ok = pathParams["channel_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") } - protoReq.PortId, err = runtime.String(val) + protoReq.ChannelId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["channel_id"] + val, ok = pathParams["port_id"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "port_id") } - protoReq.ChannelId, err = runtime.String(val) + protoReq.PortId, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "port_id", err) } msg, err := server.FeeEnabledChannel(ctx, &protoReq) @@ -1226,21 +1226,21 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie var ( pattern_Query_IncentivizedPackets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "apps", "fee", "v1", "incentivized_packets"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_IncentivizedPacket_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "incentivized_packet", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_IncentivizedPacket_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "apps", "fee", "v1", "channels", "packet_id.channel_id", "ports", "packet_id.port_id", "sequences", "packet_id.sequence", "incentivized_packet"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_IncentivizedPacketsForChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8}, []string{"ibc", "apps", "fee", "v1", "incentivized_packets", "port", "port_id", "channel", "channel_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_IncentivizedPacketsForChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "fee", "v1", "channels", "channel_id", "ports", "port_id", "incentivized_packets"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_TotalRecvFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_recv_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_TotalRecvFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "apps", "fee", "v1", "channels", "packet_id.channel_id", "ports", "packet_id.port_id", "sequences", "packet_id.sequence", "total_recv_fees"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_TotalAckFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_ack_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_TotalAckFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "apps", "fee", "v1", "channels", "packet_id.channel_id", "ports", "packet_id.port_id", "sequences", "packet_id.sequence", "total_ack_fees"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_TotalTimeoutFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8, 2, 9, 1, 0, 4, 1, 5, 10}, []string{"ibc", "apps", "fee", "v1", "total_timeout_fees", "port", "packet_id.port_id", "channel", "packet_id.channel_id", "sequence", "packet_id.sequence"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_TotalTimeoutFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "apps", "fee", "v1", "channels", "packet_id.channel_id", "ports", "packet_id.port_id", "sequences", "packet_id.sequence", "total_timeout_fees"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_CounterpartyAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7}, []string{"ibc", "apps", "fee", "v1", "counterparty_address", "relayer_address", "channel", "channel_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_CounterpartyAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "fee", "v1", "channels", "channel_id", "relayers", "relayer_address", "counterparty_address"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_FeeEnabledChannels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "apps", "fee", "v1", "fee_enabled"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_FeeEnabledChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6, 2, 7, 1, 0, 4, 1, 5, 8}, []string{"ibc", "apps", "fee", "v1", "fee_enabled", "port", "port_id", "channel", "channel_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_FeeEnabledChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "fee", "v1", "channels", "channel_id", "ports", "port_id", "fee_enabled"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( diff --git a/modules/apps/29-fee/types/tx.pb.go b/modules/apps/29-fee/types/tx.pb.go index 66827e58cc6..7c941f44c9c 100644 --- a/modules/apps/29-fee/types/tx.pb.go +++ b/modules/apps/29-fee/types/tx.pb.go @@ -29,6 +29,88 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// MsgRegisterPayee defines the request type for the RegisterPayee rpc +type MsgRegisterPayee struct { + // unique port identifier + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + // unique channel identifier + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + // the relayer address + RelayerAddress string `protobuf:"bytes,3,opt,name=relayer_address,json=relayerAddress,proto3" json:"relayer_address,omitempty" yaml:"relayer_address"` + // the fee payee address + Payee string `protobuf:"bytes,4,opt,name=payee,proto3" json:"payee,omitempty"` +} + +func (m *MsgRegisterPayee) Reset() { *m = MsgRegisterPayee{} } +func (m *MsgRegisterPayee) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterPayee) ProtoMessage() {} +func (*MsgRegisterPayee) Descriptor() ([]byte, []int) { + return fileDescriptor_05c93128649f1b96, []int{0} +} +func (m *MsgRegisterPayee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterPayee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterPayee.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRegisterPayee) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterPayee.Merge(m, src) +} +func (m *MsgRegisterPayee) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterPayee) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterPayee.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterPayee proto.InternalMessageInfo + +// MsgRegisterPayeeResponse defines the response type for the RegisterPayee rpc +type MsgRegisterPayeeResponse struct { +} + +func (m *MsgRegisterPayeeResponse) Reset() { *m = MsgRegisterPayeeResponse{} } +func (m *MsgRegisterPayeeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterPayeeResponse) ProtoMessage() {} +func (*MsgRegisterPayeeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_05c93128649f1b96, []int{1} +} +func (m *MsgRegisterPayeeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterPayeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterPayeeResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRegisterPayeeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterPayeeResponse.Merge(m, src) +} +func (m *MsgRegisterPayeeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterPayeeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterPayeeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterPayeeResponse proto.InternalMessageInfo + // MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc type MsgRegisterCounterpartyAddress struct { // the relayer address @@ -45,7 +127,7 @@ func (m *MsgRegisterCounterpartyAddress) Reset() { *m = MsgRegisterCount func (m *MsgRegisterCounterpartyAddress) String() string { return proto.CompactTextString(m) } func (*MsgRegisterCounterpartyAddress) ProtoMessage() {} func (*MsgRegisterCounterpartyAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_05c93128649f1b96, []int{0} + return fileDescriptor_05c93128649f1b96, []int{2} } func (m *MsgRegisterCounterpartyAddress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -84,7 +166,7 @@ func (m *MsgRegisterCounterpartyAddressResponse) Reset() { func (m *MsgRegisterCounterpartyAddressResponse) String() string { return proto.CompactTextString(m) } func (*MsgRegisterCounterpartyAddressResponse) ProtoMessage() {} func (*MsgRegisterCounterpartyAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_05c93128649f1b96, []int{1} + return fileDescriptor_05c93128649f1b96, []int{3} } func (m *MsgRegisterCounterpartyAddressResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -133,7 +215,7 @@ func (m *MsgPayPacketFee) Reset() { *m = MsgPayPacketFee{} } func (m *MsgPayPacketFee) String() string { return proto.CompactTextString(m) } func (*MsgPayPacketFee) ProtoMessage() {} func (*MsgPayPacketFee) Descriptor() ([]byte, []int) { - return fileDescriptor_05c93128649f1b96, []int{2} + return fileDescriptor_05c93128649f1b96, []int{4} } func (m *MsgPayPacketFee) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -170,7 +252,7 @@ func (m *MsgPayPacketFeeResponse) Reset() { *m = MsgPayPacketFeeResponse func (m *MsgPayPacketFeeResponse) String() string { return proto.CompactTextString(m) } func (*MsgPayPacketFeeResponse) ProtoMessage() {} func (*MsgPayPacketFeeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_05c93128649f1b96, []int{3} + return fileDescriptor_05c93128649f1b96, []int{5} } func (m *MsgPayPacketFeeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -212,7 +294,7 @@ func (m *MsgPayPacketFeeAsync) Reset() { *m = MsgPayPacketFeeAsync{} } func (m *MsgPayPacketFeeAsync) String() string { return proto.CompactTextString(m) } func (*MsgPayPacketFeeAsync) ProtoMessage() {} func (*MsgPayPacketFeeAsync) Descriptor() ([]byte, []int) { - return fileDescriptor_05c93128649f1b96, []int{4} + return fileDescriptor_05c93128649f1b96, []int{6} } func (m *MsgPayPacketFeeAsync) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -249,7 +331,7 @@ func (m *MsgPayPacketFeeAsyncResponse) Reset() { *m = MsgPayPacketFeeAsy func (m *MsgPayPacketFeeAsyncResponse) String() string { return proto.CompactTextString(m) } func (*MsgPayPacketFeeAsyncResponse) ProtoMessage() {} func (*MsgPayPacketFeeAsyncResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_05c93128649f1b96, []int{5} + return fileDescriptor_05c93128649f1b96, []int{7} } func (m *MsgPayPacketFeeAsyncResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -279,6 +361,8 @@ func (m *MsgPayPacketFeeAsyncResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgPayPacketFeeAsyncResponse proto.InternalMessageInfo func init() { + proto.RegisterType((*MsgRegisterPayee)(nil), "ibc.applications.fee.v1.MsgRegisterPayee") + proto.RegisterType((*MsgRegisterPayeeResponse)(nil), "ibc.applications.fee.v1.MsgRegisterPayeeResponse") proto.RegisterType((*MsgRegisterCounterpartyAddress)(nil), "ibc.applications.fee.v1.MsgRegisterCounterpartyAddress") proto.RegisterType((*MsgRegisterCounterpartyAddressResponse)(nil), "ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse") proto.RegisterType((*MsgPayPacketFee)(nil), "ibc.applications.fee.v1.MsgPayPacketFee") @@ -290,48 +374,53 @@ func init() { func init() { proto.RegisterFile("ibc/applications/fee/v1/tx.proto", fileDescriptor_05c93128649f1b96) } var fileDescriptor_05c93128649f1b96 = []byte{ - // 650 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xbf, 0x4f, 0xdb, 0x40, - 0x14, 0xc7, 0x63, 0x42, 0x81, 0x5c, 0x11, 0x34, 0x57, 0x28, 0x21, 0x50, 0x9b, 0x7a, 0xa8, 0x22, - 0x55, 0xd8, 0xe5, 0x97, 0xaa, 0xb2, 0x20, 0x82, 0x84, 0xca, 0x80, 0x8a, 0x4e, 0x9d, 0xaa, 0x4a, - 0xc8, 0x39, 0xbf, 0x18, 0xb7, 0x89, 0xcf, 0xf2, 0x39, 0x51, 0xfd, 0x0f, 0x54, 0x1d, 0xd9, 0xba, - 0xf2, 0xe7, 0x30, 0x32, 0x74, 0xe8, 0x64, 0x55, 0xb0, 0x74, 0xf6, 0xda, 0xa5, 0x3a, 0x9f, 0x1d, - 0x39, 0x94, 0x44, 0xb4, 0xdb, 0xdd, 0xbd, 0xcf, 0xfb, 0xde, 0x7b, 0x5f, 0x3f, 0x1f, 0x5a, 0x73, - 0x5b, 0xd4, 0xb4, 0x7c, 0xbf, 0xe3, 0x52, 0x2b, 0x74, 0x99, 0xc7, 0xcd, 0x36, 0x80, 0xd9, 0xdf, - 0x30, 0xc3, 0xcf, 0x86, 0x1f, 0xb0, 0x90, 0xe1, 0x25, 0xb7, 0x45, 0x8d, 0x22, 0x61, 0xb4, 0x01, - 0x8c, 0xfe, 0x46, 0x7d, 0xc1, 0x61, 0x0e, 0x4b, 0x19, 0x53, 0xac, 0x24, 0x5e, 0x7f, 0x36, 0x4a, - 0x50, 0x64, 0x15, 0x10, 0xca, 0x02, 0x30, 0xe9, 0x99, 0xe5, 0x79, 0xd0, 0x11, 0xe1, 0x6c, 0x29, - 0x11, 0xfd, 0xb7, 0x82, 0xd4, 0x63, 0xee, 0x10, 0x70, 0x5c, 0x1e, 0x42, 0x70, 0xc0, 0x7a, 0x5e, - 0x08, 0x81, 0x6f, 0x05, 0x61, 0xb4, 0x6f, 0xdb, 0x01, 0x70, 0x8e, 0x6b, 0x68, 0xda, 0x92, 0xcb, - 0x9a, 0xb2, 0xa6, 0x34, 0x2a, 0x24, 0xdf, 0x62, 0x82, 0x16, 0x68, 0x21, 0xe1, 0x34, 0xc7, 0x26, - 0x04, 0xd6, 0xd4, 0x92, 0x58, 0x5b, 0x89, 0xac, 0x6e, 0x67, 0x57, 0xbf, 0x8b, 0xd2, 0xc9, 0x63, - 0x7a, 0xc7, 0x6d, 0x2f, 0xd0, 0xb4, 0xcf, 0x82, 0xf0, 0xd4, 0xb5, 0x6b, 0xe5, 0x54, 0x06, 0x27, - 0xb1, 0x36, 0x27, 0x65, 0xb2, 0x80, 0x4e, 0xa6, 0xc4, 0xea, 0xc8, 0xc6, 0xdb, 0x08, 0x65, 0xed, - 0x08, 0x7e, 0x32, 0xe5, 0x17, 0x93, 0x58, 0xab, 0x66, 0xd7, 0x0e, 0x62, 0x3a, 0xa9, 0x64, 0x9b, - 0x23, 0x7b, 0x77, 0xe6, 0xeb, 0x85, 0x56, 0xfa, 0x75, 0xa1, 0x95, 0xf4, 0x06, 0x7a, 0x3e, 0xbe, - 0x79, 0x02, 0xdc, 0x67, 0x1e, 0x07, 0xfd, 0x7c, 0x02, 0xcd, 0x1f, 0x73, 0xe7, 0xc4, 0x8a, 0x4e, - 0x2c, 0xfa, 0x09, 0xc2, 0x43, 0x00, 0xbc, 0x8d, 0xca, 0x6d, 0x80, 0xd4, 0x94, 0x87, 0x9b, 0xab, - 0xc6, 0x88, 0xcf, 0x67, 0x1c, 0x02, 0x34, 0x27, 0x2f, 0x63, 0xad, 0x44, 0x04, 0x8e, 0xf7, 0xd0, - 0x1c, 0x67, 0xbd, 0x80, 0xc2, 0x69, 0xde, 0xa7, 0xb4, 0x6b, 0x39, 0x89, 0xb5, 0x45, 0x59, 0xf7, - 0x70, 0x5c, 0x27, 0xb3, 0xf2, 0xe0, 0x44, 0x36, 0xfd, 0x06, 0x55, 0x33, 0xa0, 0xd0, 0xbb, 0xf4, - 0x6a, 0x35, 0x89, 0xb5, 0xda, 0x90, 0x46, 0xd1, 0x82, 0x79, 0x79, 0x76, 0x90, 0x1b, 0x81, 0x9f, - 0xa0, 0x29, 0xee, 0x3a, 0x1e, 0x04, 0xd2, 0x3a, 0x92, 0xed, 0x70, 0x1d, 0xcd, 0x04, 0xd0, 0xb1, - 0x22, 0x08, 0x78, 0xed, 0xc1, 0x5a, 0xb9, 0x51, 0x21, 0x83, 0x7d, 0xc1, 0xbc, 0x65, 0xb4, 0x74, - 0xcb, 0x91, 0x81, 0x5b, 0xdf, 0x15, 0xb4, 0x70, 0x2b, 0xb6, 0xcf, 0x23, 0x8f, 0xe2, 0x77, 0xa8, - 0xe2, 0xa7, 0x27, 0xa2, 0x66, 0x69, 0xdc, 0xd3, 0xd4, 0x38, 0x31, 0xa5, 0x46, 0x3e, 0x9a, 0xfd, - 0x0d, 0x43, 0xe6, 0x1d, 0xd9, 0xcd, 0x9a, 0x70, 0x2e, 0x89, 0xb5, 0x47, 0xd9, 0x08, 0xe4, 0xd9, - 0x3a, 0x99, 0xf1, 0x33, 0x06, 0x7f, 0x40, 0x28, 0x3b, 0x17, 0xdf, 0x63, 0x22, 0x95, 0xd5, 0x47, - 0x7e, 0x8f, 0x41, 0x49, 0xcd, 0xe5, 0x4c, 0xbb, 0x3a, 0xa4, 0xdd, 0x06, 0xd0, 0x49, 0x56, 0xe6, - 0x21, 0x40, 0xa1, 0x63, 0x15, 0xad, 0xde, 0xd5, 0x55, 0xde, 0xf6, 0xe6, 0x97, 0x32, 0x2a, 0x1f, - 0x73, 0x07, 0x7f, 0x53, 0xd0, 0xca, 0xb8, 0x3f, 0xea, 0xd5, 0xc8, 0xda, 0xc6, 0x4f, 0x63, 0x7d, - 0xef, 0x3f, 0x13, 0xf3, 0x0a, 0xf1, 0x47, 0x34, 0x3b, 0x34, 0xc2, 0x8d, 0x71, 0x82, 0x45, 0xb2, - 0xfe, 0xf2, 0xbe, 0xe4, 0xe0, 0xae, 0x08, 0x55, 0xff, 0x1e, 0x80, 0xf5, 0xfb, 0xca, 0xa4, 0x78, - 0x7d, 0xe7, 0x9f, 0xf0, 0xfc, 0xea, 0xe6, 0xdb, 0xcb, 0x6b, 0x55, 0xb9, 0xba, 0x56, 0x95, 0x9f, - 0xd7, 0xaa, 0x72, 0x7e, 0xa3, 0x96, 0xae, 0x6e, 0xd4, 0xd2, 0x8f, 0x1b, 0xb5, 0xf4, 0x7e, 0xc7, - 0x71, 0xc3, 0xb3, 0x5e, 0xcb, 0xa0, 0xac, 0x6b, 0x52, 0xc6, 0xbb, 0x8c, 0x9b, 0x6e, 0x8b, 0xae, - 0x3b, 0xcc, 0xec, 0x6f, 0x99, 0x5d, 0x66, 0xf7, 0x3a, 0xc0, 0xc5, 0xab, 0xca, 0xcd, 0xcd, 0xd7, - 0xeb, 0xe2, 0x41, 0x0d, 0x23, 0x1f, 0x78, 0x6b, 0x2a, 0x7d, 0x2d, 0xb7, 0xfe, 0x04, 0x00, 0x00, - 0xff, 0xff, 0xcb, 0x30, 0xa1, 0x30, 0xc6, 0x05, 0x00, 0x00, + // 732 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcf, 0x4f, 0xdb, 0x58, + 0x10, 0x8e, 0x09, 0xbf, 0x32, 0xb0, 0x40, 0xbc, 0x01, 0x8c, 0x61, 0x6d, 0xd6, 0x87, 0x55, 0x56, + 0x2b, 0xec, 0x4d, 0x00, 0xad, 0x96, 0x0b, 0x22, 0x48, 0xa8, 0x1c, 0x50, 0x23, 0xab, 0xa7, 0xaa, + 0x12, 0x72, 0x9c, 0x89, 0x71, 0x9b, 0xe4, 0x59, 0x7e, 0x4e, 0x54, 0xff, 0x07, 0x3d, 0x72, 0xeb, + 0x95, 0x3f, 0x87, 0x23, 0x87, 0x1e, 0xaa, 0x1e, 0xac, 0x0a, 0x2e, 0x3d, 0x47, 0xea, 0xa9, 0x97, + 0xca, 0xf6, 0xb3, 0xeb, 0xa4, 0x09, 0x0a, 0xbd, 0xbd, 0x99, 0xf9, 0x66, 0xde, 0x7c, 0x9f, 0x67, + 0xfc, 0x60, 0xd7, 0x6e, 0x98, 0x9a, 0xe1, 0x38, 0x6d, 0xdb, 0x34, 0x3c, 0x9b, 0x74, 0xa9, 0xd6, + 0x42, 0xd4, 0xfa, 0x15, 0xcd, 0x7b, 0xab, 0x3a, 0x2e, 0xf1, 0x08, 0xbf, 0x69, 0x37, 0x4c, 0x35, + 0x8b, 0x50, 0x5b, 0x88, 0x6a, 0xbf, 0x22, 0x96, 0x2c, 0x62, 0x91, 0x08, 0xa3, 0x85, 0xa7, 0x18, + 0x2e, 0xfe, 0x39, 0xa9, 0x60, 0x98, 0x95, 0x81, 0x98, 0xc4, 0x45, 0xcd, 0xbc, 0x32, 0xba, 0x5d, + 0x6c, 0x87, 0x61, 0x76, 0x8c, 0x21, 0xca, 0x27, 0x0e, 0xd6, 0x2e, 0xa8, 0xa5, 0xa3, 0x65, 0x53, + 0x0f, 0xdd, 0xba, 0xe1, 0x23, 0xf2, 0xff, 0xc0, 0x82, 0x43, 0x5c, 0xef, 0xd2, 0x6e, 0x0a, 0xdc, + 0x2e, 0x57, 0x2e, 0xd4, 0xf8, 0x41, 0x20, 0xaf, 0xf8, 0x46, 0xa7, 0x7d, 0xa4, 0xb0, 0x80, 0xa2, + 0xcf, 0x87, 0xa7, 0xf3, 0x26, 0x7f, 0x00, 0xc0, 0x4a, 0x86, 0xf8, 0x99, 0x08, 0xbf, 0x3e, 0x08, + 0xe4, 0x62, 0x8c, 0xff, 0x11, 0x53, 0xf4, 0x02, 0x33, 0xce, 0x9b, 0xfc, 0x29, 0xac, 0xba, 0xd8, + 0x36, 0x7c, 0x74, 0x2f, 0x8d, 0x66, 0xd3, 0x45, 0x4a, 0x85, 0x7c, 0x94, 0x2a, 0x0e, 0x02, 0x79, + 0x23, 0x4e, 0x1d, 0x01, 0x28, 0xfa, 0x0a, 0xf3, 0x9c, 0xc4, 0x0e, 0xbe, 0x04, 0x73, 0x4e, 0xd8, + 0xb0, 0x30, 0x1b, 0xa6, 0xea, 0xb1, 0x71, 0xb4, 0xf8, 0xee, 0x46, 0xce, 0x7d, 0xb9, 0x91, 0x73, + 0x8a, 0x08, 0xc2, 0x28, 0x37, 0x1d, 0xa9, 0x43, 0xba, 0x14, 0x95, 0x6f, 0x1c, 0x48, 0x99, 0xe0, + 0x29, 0xe9, 0x75, 0x3d, 0x74, 0x1d, 0xc3, 0xf5, 0xfc, 0xa4, 0xbc, 0x00, 0x0b, 0x49, 0x6f, 0x91, + 0x0c, 0x7a, 0x62, 0xf2, 0x3a, 0x94, 0xcc, 0x4c, 0x42, 0x4a, 0x21, 0x66, 0x2f, 0x0f, 0x02, 0x79, + 0x9b, 0xb1, 0x1f, 0x83, 0x52, 0xf4, 0xdf, 0xcd, 0x31, 0xb7, 0x65, 0x44, 0xcf, 0x3f, 0x51, 0xf4, + 0xd9, 0xe9, 0x44, 0xcf, 0x28, 0x53, 0x86, 0xbf, 0x1e, 0x27, 0x9f, 0xea, 0x74, 0x3d, 0x03, 0xab, + 0x17, 0xd4, 0xaa, 0x1b, 0x7e, 0xdd, 0x30, 0xdf, 0xa0, 0x77, 0x86, 0xc8, 0x1f, 0x40, 0xbe, 0x85, + 0x18, 0x89, 0xb2, 0x54, 0xdd, 0x51, 0x27, 0xcc, 0xad, 0x7a, 0x86, 0x58, 0x9b, 0xbd, 0x0d, 0xe4, + 0x9c, 0x1e, 0xc2, 0xf9, 0x63, 0x58, 0xa1, 0xa4, 0xe7, 0x9a, 0x78, 0x99, 0xf0, 0x8c, 0xe5, 0xda, + 0x1a, 0x04, 0xf2, 0x7a, 0xdc, 0xf7, 0x70, 0x5c, 0xd1, 0x97, 0x63, 0x47, 0x3d, 0x26, 0xfd, 0x0c, + 0x8a, 0x0c, 0x90, 0xe1, 0x1e, 0x6b, 0xb5, 0x33, 0x08, 0x64, 0x61, 0xa8, 0x46, 0x56, 0x82, 0xd5, + 0xd8, 0x77, 0x9a, 0x4e, 0xdf, 0x06, 0xcc, 0x53, 0xdb, 0xea, 0xa2, 0xcb, 0x26, 0x87, 0x59, 0xbc, + 0x08, 0x8b, 0x6c, 0xc4, 0xa8, 0x30, 0xb7, 0x9b, 0x2f, 0x17, 0xf4, 0xd4, 0xce, 0x88, 0xb7, 0x05, + 0x9b, 0x23, 0x8a, 0xa4, 0x6a, 0x7d, 0xe0, 0xa0, 0x34, 0x12, 0x3b, 0xa1, 0x7e, 0xd7, 0xe4, 0x5f, + 0x40, 0xc1, 0x89, 0x3c, 0xc9, 0x52, 0x2d, 0x55, 0xff, 0x88, 0x84, 0x0b, 0xd7, 0x53, 0x4d, 0x76, + 0xb2, 0x5f, 0x51, 0xe3, 0xbc, 0xf3, 0x66, 0x4d, 0x08, 0x95, 0x1b, 0x04, 0xf2, 0x1a, 0x1b, 0x81, + 0x24, 0x5b, 0xd1, 0x17, 0x1d, 0x86, 0xe1, 0x5f, 0x01, 0x30, 0x7f, 0xf8, 0x3d, 0x66, 0xa2, 0xb2, + 0xca, 0xc4, 0xef, 0x91, 0xb6, 0x54, 0xdb, 0x62, 0xb5, 0x8b, 0x43, 0xb5, 0x5b, 0x88, 0x8a, 0xce, + 0xda, 0x3c, 0x1b, 0x5a, 0x24, 0x09, 0x76, 0xc6, 0xb1, 0x4a, 0x68, 0x57, 0xbf, 0xe6, 0x21, 0x7f, + 0x41, 0x2d, 0xbe, 0x03, 0xbf, 0x0d, 0xff, 0x49, 0xfe, 0x9e, 0xd8, 0xcc, 0xe8, 0x62, 0x8a, 0x95, + 0xa9, 0xa1, 0xc9, 0xb5, 0xfc, 0x7b, 0x0e, 0xb6, 0x1f, 0x5b, 0xe0, 0xff, 0xa6, 0x29, 0x39, 0x26, + 0x51, 0x3c, 0xfe, 0xc5, 0xc4, 0xb4, 0xb3, 0xd7, 0xb0, 0x3c, 0xb4, 0x31, 0xe5, 0xc7, 0x0a, 0x66, + 0x91, 0xe2, 0xbf, 0xd3, 0x22, 0xd3, 0xbb, 0x7c, 0x28, 0xfe, 0x3c, 0x6f, 0x7b, 0xd3, 0x96, 0x89, + 0xe0, 0xe2, 0xe1, 0x93, 0xe0, 0xc9, 0xd5, 0xb5, 0xe7, 0xb7, 0xf7, 0x12, 0x77, 0x77, 0x2f, 0x71, + 0x9f, 0xef, 0x25, 0xee, 0xfa, 0x41, 0xca, 0xdd, 0x3d, 0x48, 0xb9, 0x8f, 0x0f, 0x52, 0xee, 0xe5, + 0xa1, 0x65, 0x7b, 0x57, 0xbd, 0x86, 0x6a, 0x92, 0x8e, 0x66, 0x12, 0xda, 0x21, 0x54, 0xb3, 0x1b, + 0xe6, 0x9e, 0x45, 0xb4, 0xfe, 0xbe, 0xd6, 0x21, 0xcd, 0x5e, 0x1b, 0x69, 0xf8, 0x7a, 0x51, 0xad, + 0xfa, 0xff, 0x5e, 0xf8, 0x70, 0x79, 0xbe, 0x83, 0xb4, 0x31, 0x1f, 0xbd, 0x4a, 0xfb, 0xdf, 0x03, + 0x00, 0x00, 0xff, 0xff, 0x8c, 0x56, 0x8c, 0xfd, 0x2e, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -346,11 +435,17 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MsgClient interface { + // RegisterPayee defines a rpc handler method for MsgRegisterPayee + // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional + // payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which + // packets originate as this is where fee distribution takes place. This function may be called more than once by a + // relayer, in which case, the latest payee is always used. + RegisterPayee(ctx context.Context, in *MsgRegisterPayee, opts ...grpc.CallOption) (*MsgRegisterPayeeResponse, error) // RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their // counterparty address before relaying. This ensures they will be properly compensated for forward relaying since // destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function - // may be called more than once by a relayer, in which case, latest counterparty address is always used. + // may be called more than once by a relayer, in which case, the latest counterparty address is always used. RegisterCounterpartyAddress(ctx context.Context, in *MsgRegisterCounterpartyAddress, opts ...grpc.CallOption) (*MsgRegisterCounterpartyAddressResponse, error) // PayPacketFee defines a rpc handler method for MsgPayPacketFee // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to @@ -372,6 +467,15 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { return &msgClient{cc} } +func (c *msgClient) RegisterPayee(ctx context.Context, in *MsgRegisterPayee, opts ...grpc.CallOption) (*MsgRegisterPayeeResponse, error) { + out := new(MsgRegisterPayeeResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Msg/RegisterPayee", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) RegisterCounterpartyAddress(ctx context.Context, in *MsgRegisterCounterpartyAddress, opts ...grpc.CallOption) (*MsgRegisterCounterpartyAddressResponse, error) { out := new(MsgRegisterCounterpartyAddressResponse) err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Msg/RegisterCounterpartyAddress", in, out, opts...) @@ -401,11 +505,17 @@ func (c *msgClient) PayPacketFeeAsync(ctx context.Context, in *MsgPayPacketFeeAs // MsgServer is the server API for Msg service. type MsgServer interface { + // RegisterPayee defines a rpc handler method for MsgRegisterPayee + // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional + // payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which + // packets originate as this is where fee distribution takes place. This function may be called more than once by a + // relayer, in which case, the latest payee is always used. + RegisterPayee(context.Context, *MsgRegisterPayee) (*MsgRegisterPayeeResponse, error) // RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their // counterparty address before relaying. This ensures they will be properly compensated for forward relaying since // destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function - // may be called more than once by a relayer, in which case, latest counterparty address is always used. + // may be called more than once by a relayer, in which case, the latest counterparty address is always used. RegisterCounterpartyAddress(context.Context, *MsgRegisterCounterpartyAddress) (*MsgRegisterCounterpartyAddressResponse, error) // PayPacketFee defines a rpc handler method for MsgPayPacketFee // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to @@ -423,6 +533,9 @@ type MsgServer interface { type UnimplementedMsgServer struct { } +func (*UnimplementedMsgServer) RegisterPayee(ctx context.Context, req *MsgRegisterPayee) (*MsgRegisterPayeeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterPayee not implemented") +} func (*UnimplementedMsgServer) RegisterCounterpartyAddress(ctx context.Context, req *MsgRegisterCounterpartyAddress) (*MsgRegisterCounterpartyAddressResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RegisterCounterpartyAddress not implemented") } @@ -437,6 +550,24 @@ func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } +func _Msg_RegisterPayee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRegisterPayee) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RegisterPayee(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Msg/RegisterPayee", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RegisterPayee(ctx, req.(*MsgRegisterPayee)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_RegisterCounterpartyAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgRegisterCounterpartyAddress) if err := dec(in); err != nil { @@ -495,6 +626,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "ibc.applications.fee.v1.Msg", HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "RegisterPayee", + Handler: _Msg_RegisterPayee_Handler, + }, { MethodName: "RegisterCounterpartyAddress", Handler: _Msg_RegisterCounterpartyAddress_Handler, @@ -512,6 +647,80 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Metadata: "ibc/applications/fee/v1/tx.proto", } +func (m *MsgRegisterPayee) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRegisterPayee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterPayee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Payee) > 0 { + i -= len(m.Payee) + copy(dAtA[i:], m.Payee) + i = encodeVarintTx(dAtA, i, uint64(len(m.Payee))) + i-- + dAtA[i] = 0x22 + } + if len(m.RelayerAddress) > 0 { + i -= len(m.RelayerAddress) + copy(dAtA[i:], m.RelayerAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.RelayerAddress))) + i-- + dAtA[i] = 0x1a + } + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRegisterPayeeResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRegisterPayeeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterPayeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgRegisterCounterpartyAddress) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -749,6 +958,40 @@ func encodeVarintTx(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *MsgRegisterPayee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.RelayerAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Payee) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRegisterPayeeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgRegisterCounterpartyAddress) Size() (n int) { if m == nil { return 0 @@ -849,6 +1092,234 @@ func sovTx(x uint64) (n int) { func sozTx(x uint64) (n int) { return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (m *MsgRegisterPayee) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRegisterPayee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterPayee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RelayerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RelayerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Payee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Payee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRegisterPayeeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRegisterPayeeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterPayeeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/proto/ibc/applications/fee/v1/query.proto b/proto/ibc/applications/fee/v1/query.proto index 0e1caa5d0f7..5f648107323 100644 --- a/proto/ibc/applications/fee/v1/query.proto +++ b/proto/ibc/applications/fee/v1/query.proto @@ -52,7 +52,8 @@ service Query { // CounterpartyAddress returns the registered counterparty address for forward relaying rpc CounterpartyAddress(QueryCounterpartyAddressRequest) returns (QueryCounterpartyAddressResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address"; + option (google.api.http).get = + "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address"; } // FeeEnabledChannels returns a list of all fee enabled channels diff --git a/proto/ibc/applications/fee/v1/tx.proto b/proto/ibc/applications/fee/v1/tx.proto index ca8397e74fd..f7c4618f54c 100644 --- a/proto/ibc/applications/fee/v1/tx.proto +++ b/proto/ibc/applications/fee/v1/tx.proto @@ -10,11 +10,18 @@ import "ibc/core/channel/v1/channel.proto"; // Msg defines the ICS29 Msg service. service Msg { + // RegisterPayee defines a rpc handler method for MsgRegisterPayee + // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional + // payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which + // packets originate as this is where fee distribution takes place. This function may be called more than once by a + // relayer, in which case, the latest payee is always used. + rpc RegisterPayee(MsgRegisterPayee) returns (MsgRegisterPayeeResponse); + // RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their // counterparty address before relaying. This ensures they will be properly compensated for forward relaying since // destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function - // may be called more than once by a relayer, in which case, latest counterparty address is always used. + // may be called more than once by a relayer, in which case, the latest counterparty address is always used. rpc RegisterCounterpartyAddress(MsgRegisterCounterpartyAddress) returns (MsgRegisterCounterpartyAddressResponse); // PayPacketFee defines a rpc handler method for MsgPayPacketFee @@ -30,6 +37,24 @@ service Msg { rpc PayPacketFeeAsync(MsgPayPacketFeeAsync) returns (MsgPayPacketFeeAsyncResponse); } +// MsgRegisterPayee defines the request type for the RegisterPayee rpc +message MsgRegisterPayee { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // unique port identifier + string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + // unique channel identifier + string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + // the relayer address + string relayer_address = 3 [(gogoproto.moretags) = "yaml:\"relayer_address\""]; + // the fee payee address + string payee = 4; +} + +// MsgRegisterPayeeResponse defines the response type for the RegisterPayee rpc +message MsgRegisterPayeeResponse {} + // MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc message MsgRegisterCounterpartyAddress { option (gogoproto.equal) = false; From 57aa5ecd928053f9a5df9043731fd0810371db23 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 8 Jun 2022 17:18:02 +0200 Subject: [PATCH 147/275] feat: adding RegisteredPayees to ics29 genesis state (#1492) * [WIP] adding RegisterDistributionAddress rpc endpoint and implementation. Store funcs, keys.. * updating tests * adding registered distribution addresses to genesis state * refactor and update validate genesis tests * adding cli for register distribution address rpc * renaming RegisterDistributionAddress rpc to RegisterPayee * renaming RegisterDistributionAddress to RegisterPayee * updating godocs and field ordering * updating inline comment * renaming to regsitered payees and propagating changes in genesis * updating godoc in keeper.go * Update modules/apps/29-fee/keeper/keeper_test.go Co-authored-by: Aditya Co-authored-by: Aditya --- docs/ibc/proto-docs.md | 19 + modules/apps/29-fee/keeper/genesis.go | 5 + modules/apps/29-fee/keeper/genesis_test.go | 50 ++- modules/apps/29-fee/keeper/keeper.go | 25 ++ modules/apps/29-fee/keeper/keeper_test.go | 25 ++ modules/apps/29-fee/types/genesis.go | 29 +- modules/apps/29-fee/types/genesis.pb.go | 431 ++++++++++++++++++-- modules/apps/29-fee/types/genesis_test.go | 171 +++----- proto/ibc/applications/fee/v1/genesis.proto | 17 +- 9 files changed, 599 insertions(+), 173 deletions(-) diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 577dad6af8d..fe55e9c32be 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -38,6 +38,7 @@ - [FeeEnabledChannel](#ibc.applications.fee.v1.FeeEnabledChannel) - [ForwardRelayerAddress](#ibc.applications.fee.v1.ForwardRelayerAddress) - [GenesisState](#ibc.applications.fee.v1.GenesisState) + - [RegisteredPayee](#ibc.applications.fee.v1.RegisteredPayee) - [RegisteredRelayerAddress](#ibc.applications.fee.v1.RegisteredRelayerAddress) - [ibc/applications/fee/v1/metadata.proto](#ibc/applications/fee/v1/metadata.proto) @@ -844,6 +845,7 @@ GenesisState defines the ICS29 fee middleware genesis state | ----- | ---- | ----- | ----------- | | `identified_fees` | [IdentifiedPacketFees](#ibc.applications.fee.v1.IdentifiedPacketFees) | repeated | list of identified packet fees | | `fee_enabled_channels` | [FeeEnabledChannel](#ibc.applications.fee.v1.FeeEnabledChannel) | repeated | list of fee enabled channels | +| `registered_payees` | [RegisteredPayee](#ibc.applications.fee.v1.RegisteredPayee) | repeated | list of registered payees | | `registered_relayers` | [RegisteredRelayerAddress](#ibc.applications.fee.v1.RegisteredRelayerAddress) | repeated | list of registered relayer addresses | | `forward_relayers` | [ForwardRelayerAddress](#ibc.applications.fee.v1.ForwardRelayerAddress) | repeated | list of forward relayer addresses | @@ -852,6 +854,23 @@ GenesisState defines the ICS29 fee middleware genesis state + + +### RegisteredPayee +RegisteredPayee contains the relayer address and payee address for a specific channel + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `relayer_address` | [string](#string) | | the relayer address | +| `payee` | [string](#string) | | the payee address | +| `channel_id` | [string](#string) | | unique channel identifier | + + + + + + ### RegisteredRelayerAddress diff --git a/modules/apps/29-fee/keeper/genesis.go b/modules/apps/29-fee/keeper/genesis.go index 70b6a5012a2..c4be3a9d027 100644 --- a/modules/apps/29-fee/keeper/genesis.go +++ b/modules/apps/29-fee/keeper/genesis.go @@ -23,6 +23,10 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { for _, enabledChan := range state.FeeEnabledChannels { k.SetFeeEnabled(ctx, enabledChan.PortId, enabledChan.ChannelId) } + + for _, registeredPayee := range state.RegisteredPayees { + k.SetPayeeAddress(ctx, registeredPayee.RelayerAddress, registeredPayee.Payee, registeredPayee.ChannelId) + } } // ExportGenesis returns the fee middleware application exported genesis @@ -32,5 +36,6 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { FeeEnabledChannels: k.GetAllFeeEnabledChannels(ctx), RegisteredRelayers: k.GetAllRelayerAddresses(ctx), ForwardRelayers: k.GetAllForwardRelayerAddresses(ctx), + RegisteredPayees: k.GetAllPayeeAddresses(ctx), } } diff --git a/modules/apps/29-fee/keeper/genesis_test.go b/modules/apps/29-fee/keeper/genesis_test.go index 8aa30385e58..7cd2e5bd1a6 100644 --- a/modules/apps/29-fee/keeper/genesis_test.go +++ b/modules/apps/29-fee/keeper/genesis_test.go @@ -7,18 +7,7 @@ import ( ) func (suite *KeeperTestSuite) TestInitGenesis() { - // build PacketId & Fee - refundAcc := suite.chainA.SenderAccount.GetAddress() packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) - fee := types.Fee{ - RecvFee: defaultRecvFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, - } - - // relayer addresses - sender := suite.chainA.SenderAccount.GetAddress().String() - counterparty := suite.chainB.SenderAccount.GetAddress().String() genesisState := types.GenesisState{ IdentifiedFees: []types.IdentifiedPacketFees{ @@ -26,8 +15,8 @@ func (suite *KeeperTestSuite) TestInitGenesis() { PacketId: packetID, PacketFees: []types.PacketFee{ { - Fee: fee, - RefundAddress: refundAcc.String(), + Fee: types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee), + RefundAddress: suite.chainA.SenderAccount.GetAddress().String(), Relayers: nil, }, }, @@ -41,11 +30,18 @@ func (suite *KeeperTestSuite) TestInitGenesis() { }, RegisteredRelayers: []types.RegisteredRelayerAddress{ { - Address: sender, - CounterpartyAddress: counterparty, + Address: suite.chainA.SenderAccount.GetAddress().String(), + CounterpartyAddress: suite.chainB.SenderAccount.GetAddress().String(), ChannelId: ibctesting.FirstChannelID, }, }, + RegisteredPayees: []types.RegisteredPayee{ + { + RelayerAddress: suite.chainA.SenderAccount.GetAddress().String(), + Payee: suite.chainB.SenderAccount.GetAddress().String(), + ChannelId: ibctesting.FirstChannelID, + }, + }, } suite.chainA.GetSimApp().IBCFeeKeeper.InitGenesis(suite.chainA.GetContext(), genesisState) @@ -60,9 +56,14 @@ func (suite *KeeperTestSuite) TestInitGenesis() { suite.Require().True(isEnabled) // check relayers - addr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(suite.chainA.GetContext(), sender, ibctesting.FirstChannelID) + addr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) suite.Require().True(found) suite.Require().Equal(genesisState.RegisteredRelayers[0].CounterpartyAddress, addr) + + // check payee addresses + payeeAddr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) + suite.Require().True(found) + suite.Require().Equal(genesisState.RegisteredPayees[0].Payee, payeeAddr) } func (suite *KeeperTestSuite) TestExportGenesis() { @@ -72,11 +73,7 @@ func (suite *KeeperTestSuite) TestExportGenesis() { // setup & escrow the packet fee refundAcc := suite.chainA.SenderAccount.GetAddress() packetID := channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) - fee := types.Fee{ - RecvFee: defaultRecvFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, - } + fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) @@ -90,6 +87,9 @@ func (suite *KeeperTestSuite) TestExportGenesis() { // set forward relayer address suite.chainA.GetSimApp().IBCFeeKeeper.SetRelayerAddressForAsyncAck(suite.chainA.GetContext(), packetID, sender) + // set payee address + suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) + // export genesis genesisState := suite.chainA.GetSimApp().IBCFeeKeeper.ExportGenesis(suite.chainA.GetContext()) @@ -106,8 +106,14 @@ func (suite *KeeperTestSuite) TestExportGenesis() { // check registered relayer addresses suite.Require().Equal(sender, genesisState.RegisteredRelayers[0].Address) suite.Require().Equal(counterparty, genesisState.RegisteredRelayers[0].CounterpartyAddress) + suite.Require().Equal(ibctesting.FirstChannelID, genesisState.RegisteredRelayers[0].ChannelId) - // check registered relayer addresses + // check forward relayer addresses suite.Require().Equal(sender, genesisState.ForwardRelayers[0].Address) suite.Require().Equal(packetID, genesisState.ForwardRelayers[0].PacketId) + + // check payee addresses + suite.Require().Equal(suite.chainA.SenderAccount.GetAddress().String(), genesisState.RegisteredPayees[0].RelayerAddress) + suite.Require().Equal(suite.chainB.SenderAccount.GetAddress().String(), genesisState.RegisteredPayees[0].Payee) + suite.Require().Equal(ibctesting.FirstChannelID, genesisState.RegisteredPayees[0].ChannelId) } diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index 15e9eb86f82..311bee5eb69 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -165,6 +165,31 @@ func (k Keeper) SetPayeeAddress(ctx sdk.Context, relayerAddr, payeeAddr, channel store.Set(types.KeyPayeeAddress(relayerAddr, channelID), []byte(payeeAddr)) } +// GetAllPayeeAddresses returns all registered payees +func (k Keeper) GetAllPayeeAddresses(ctx sdk.Context) []types.RegisteredPayee { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.PayeeAddressKeyPrefix)) + defer iterator.Close() + + var registeredPayees []types.RegisteredPayee + for ; iterator.Valid(); iterator.Next() { + addr, channelID, err := types.ParseKeyPayeeAddress(string(iterator.Key())) + if err != nil { + panic(err) + } + + payee := types.RegisteredPayee{ + RelayerAddress: addr, + Payee: string(iterator.Value()), + ChannelId: channelID, + } + + registeredPayees = append(registeredPayees, payee) + } + + return registeredPayees +} + // SetCounterpartyAddress maps the destination chain relayer address to the source relayer address // The receiving chain must store the mapping from: address -> counterpartyAddress for the given channel func (k Keeper) SetCounterpartyAddress(ctx sdk.Context, address, counterpartyAddress, channelID string) { diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index d66f1284fe6..1b26fe6ac5e 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -276,3 +276,28 @@ func (suite *KeeperTestSuite) TestGetAllRelayerAddresses() { suite.Require().Len(addr, len(expectedAddr)) suite.Require().Equal(addr, expectedAddr) } + +func (suite *KeeperTestSuite) TestGetAllPayeeAddresses() { + var expectedPayees []types.RegisteredPayee + + for i := 0; i < 3; i++ { + suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccounts[i].SenderAccount.GetAddress().String(), + suite.chainB.SenderAccounts[i].SenderAccount.GetAddress().String(), + ibctesting.FirstChannelID, + ) + + registeredPayee := types.RegisteredPayee{ + RelayerAddress: suite.chainA.SenderAccounts[i].SenderAccount.GetAddress().String(), + Payee: suite.chainB.SenderAccounts[i].SenderAccount.GetAddress().String(), + ChannelId: ibctesting.FirstChannelID, + } + + expectedPayees = append(expectedPayees, registeredPayee) + } + + registeredPayees := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllPayeeAddresses(suite.chainA.GetContext()) + suite.Require().Len(registeredPayees, len(expectedPayees)) + suite.Require().ElementsMatch(expectedPayees, registeredPayees) +} diff --git a/modules/apps/29-fee/types/genesis.go b/modules/apps/29-fee/types/genesis.go index be9299fcd94..db406c3fefb 100644 --- a/modules/apps/29-fee/types/genesis.go +++ b/modules/apps/29-fee/types/genesis.go @@ -10,12 +10,19 @@ import ( ) // NewGenesisState creates a 29-fee GenesisState instance. -func NewGenesisState(identifiedFees []IdentifiedPacketFees, feeEnabledChannels []FeeEnabledChannel, registeredRelayers []RegisteredRelayerAddress, forwardRelayers []ForwardRelayerAddress) *GenesisState { +func NewGenesisState( + identifiedFees []IdentifiedPacketFees, + feeEnabledChannels []FeeEnabledChannel, + registeredRelayers []RegisteredRelayerAddress, + forwardRelayers []ForwardRelayerAddress, + registeredPayees []RegisteredPayee, +) *GenesisState { return &GenesisState{ IdentifiedFees: identifiedFees, FeeEnabledChannels: feeEnabledChannels, RegisteredRelayers: registeredRelayers, ForwardRelayers: forwardRelayers, + RegisteredPayees: registeredPayees, } } @@ -26,6 +33,7 @@ func DefaultGenesisState() *GenesisState { ForwardRelayers: []ForwardRelayerAddress{}, FeeEnabledChannels: []FeeEnabledChannel{}, RegisteredRelayers: []RegisteredRelayerAddress{}, + RegisteredPayees: []RegisteredPayee{}, } } @@ -55,6 +63,25 @@ func (gs GenesisState) Validate() error { } } + // Validate RegisteredPayees + for _, registeredPayee := range gs.RegisteredPayees { + if registeredPayee.RelayerAddress == registeredPayee.Payee { + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "relayer address and payee address must not be equal") + } + + if _, err := sdk.AccAddressFromBech32(registeredPayee.RelayerAddress); err != nil { + return sdkerrors.Wrap(err, "failed to convert relayer address into sdk.AccAddress") + } + + if _, err := sdk.AccAddressFromBech32(registeredPayee.Payee); err != nil { + return sdkerrors.Wrap(err, "failed to convert payee address into sdk.AccAddress") + } + + if err := host.ChannelIdentifierValidator(registeredPayee.ChannelId); err != nil { + return sdkerrors.Wrapf(err, "invalid channel identifier: %s", registeredPayee.ChannelId) + } + } + // Validate RegisteredRelayers for _, rel := range gs.RegisteredRelayers { if _, err := sdk.AccAddressFromBech32(rel.Address); err != nil { diff --git a/modules/apps/29-fee/types/genesis.pb.go b/modules/apps/29-fee/types/genesis.pb.go index af78add463e..bd2fd2083f0 100644 --- a/modules/apps/29-fee/types/genesis.pb.go +++ b/modules/apps/29-fee/types/genesis.pb.go @@ -30,10 +30,12 @@ type GenesisState struct { IdentifiedFees []IdentifiedPacketFees `protobuf:"bytes,1,rep,name=identified_fees,json=identifiedFees,proto3" json:"identified_fees" yaml:"identified_fees"` // list of fee enabled channels FeeEnabledChannels []FeeEnabledChannel `protobuf:"bytes,2,rep,name=fee_enabled_channels,json=feeEnabledChannels,proto3" json:"fee_enabled_channels" yaml:"fee_enabled_channels"` + // list of registered payees + RegisteredPayees []RegisteredPayee `protobuf:"bytes,3,rep,name=registered_payees,json=registeredPayees,proto3" json:"registered_payees" yaml:"registered_payees"` // list of registered relayer addresses - RegisteredRelayers []RegisteredRelayerAddress `protobuf:"bytes,3,rep,name=registered_relayers,json=registeredRelayers,proto3" json:"registered_relayers" yaml:"registered_relayers"` + RegisteredRelayers []RegisteredRelayerAddress `protobuf:"bytes,4,rep,name=registered_relayers,json=registeredRelayers,proto3" json:"registered_relayers" yaml:"registered_relayers"` // list of forward relayer addresses - ForwardRelayers []ForwardRelayerAddress `protobuf:"bytes,4,rep,name=forward_relayers,json=forwardRelayers,proto3" json:"forward_relayers" yaml:"forward_relayers"` + ForwardRelayers []ForwardRelayerAddress `protobuf:"bytes,5,rep,name=forward_relayers,json=forwardRelayers,proto3" json:"forward_relayers" yaml:"forward_relayers"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -83,6 +85,13 @@ func (m *GenesisState) GetFeeEnabledChannels() []FeeEnabledChannel { return nil } +func (m *GenesisState) GetRegisteredPayees() []RegisteredPayee { + if m != nil { + return m.RegisteredPayees + } + return nil +} + func (m *GenesisState) GetRegisteredRelayers() []RegisteredRelayerAddress { if m != nil { return m.RegisteredRelayers @@ -152,6 +161,70 @@ func (m *FeeEnabledChannel) GetChannelId() string { return "" } +// RegisteredPayee contains the relayer address and payee address for a specific channel +type RegisteredPayee struct { + // the relayer address + RelayerAddress string `protobuf:"bytes,1,opt,name=relayer_address,json=relayerAddress,proto3" json:"relayer_address,omitempty" yaml:"relayer_address"` + // the payee address + Payee string `protobuf:"bytes,2,opt,name=payee,proto3" json:"payee,omitempty"` + // unique channel identifier + ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` +} + +func (m *RegisteredPayee) Reset() { *m = RegisteredPayee{} } +func (m *RegisteredPayee) String() string { return proto.CompactTextString(m) } +func (*RegisteredPayee) ProtoMessage() {} +func (*RegisteredPayee) Descriptor() ([]byte, []int) { + return fileDescriptor_7191992e856dff95, []int{2} +} +func (m *RegisteredPayee) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RegisteredPayee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RegisteredPayee.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RegisteredPayee) XXX_Merge(src proto.Message) { + xxx_messageInfo_RegisteredPayee.Merge(m, src) +} +func (m *RegisteredPayee) XXX_Size() int { + return m.Size() +} +func (m *RegisteredPayee) XXX_DiscardUnknown() { + xxx_messageInfo_RegisteredPayee.DiscardUnknown(m) +} + +var xxx_messageInfo_RegisteredPayee proto.InternalMessageInfo + +func (m *RegisteredPayee) GetRelayerAddress() string { + if m != nil { + return m.RelayerAddress + } + return "" +} + +func (m *RegisteredPayee) GetPayee() string { + if m != nil { + return m.Payee + } + return "" +} + +func (m *RegisteredPayee) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + // RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) type RegisteredRelayerAddress struct { // the relayer address @@ -166,7 +239,7 @@ func (m *RegisteredRelayerAddress) Reset() { *m = RegisteredRelayerAddre func (m *RegisteredRelayerAddress) String() string { return proto.CompactTextString(m) } func (*RegisteredRelayerAddress) ProtoMessage() {} func (*RegisteredRelayerAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_7191992e856dff95, []int{2} + return fileDescriptor_7191992e856dff95, []int{3} } func (m *RegisteredRelayerAddress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -228,7 +301,7 @@ func (m *ForwardRelayerAddress) Reset() { *m = ForwardRelayerAddress{} } func (m *ForwardRelayerAddress) String() string { return proto.CompactTextString(m) } func (*ForwardRelayerAddress) ProtoMessage() {} func (*ForwardRelayerAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_7191992e856dff95, []int{3} + return fileDescriptor_7191992e856dff95, []int{4} } func (m *ForwardRelayerAddress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -274,6 +347,7 @@ func (m *ForwardRelayerAddress) GetPacketId() types.PacketId { func init() { proto.RegisterType((*GenesisState)(nil), "ibc.applications.fee.v1.GenesisState") proto.RegisterType((*FeeEnabledChannel)(nil), "ibc.applications.fee.v1.FeeEnabledChannel") + proto.RegisterType((*RegisteredPayee)(nil), "ibc.applications.fee.v1.RegisteredPayee") proto.RegisterType((*RegisteredRelayerAddress)(nil), "ibc.applications.fee.v1.RegisteredRelayerAddress") proto.RegisterType((*ForwardRelayerAddress)(nil), "ibc.applications.fee.v1.ForwardRelayerAddress") } @@ -283,44 +357,48 @@ func init() { } var fileDescriptor_7191992e856dff95 = []byte{ - // 579 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x4d, 0x6f, 0xd4, 0x30, - 0x14, 0xdc, 0xb4, 0x55, 0x4b, 0x5d, 0xd4, 0x0f, 0xb7, 0xa5, 0x51, 0x11, 0x49, 0x31, 0x42, 0xaa, - 0x40, 0x4d, 0xb4, 0x2d, 0x1c, 0xe0, 0xc6, 0x22, 0x8a, 0xf6, 0x04, 0x32, 0x9c, 0xb8, 0x44, 0xf9, - 0x78, 0x49, 0x2d, 0xb2, 0x71, 0x64, 0xbb, 0x41, 0xcb, 0x8d, 0x0b, 0x1c, 0xe1, 0x17, 0x71, 0xee, - 0xb1, 0x47, 0x4e, 0x2b, 0xd4, 0xfe, 0x83, 0xfe, 0x02, 0x94, 0x38, 0xe9, 0x6e, 0x97, 0x0d, 0xe2, - 0xf6, 0x62, 0xcf, 0xbc, 0x19, 0x8f, 0xf3, 0x8c, 0x1e, 0xb2, 0x20, 0x74, 0xfd, 0x3c, 0x4f, 0x59, - 0xe8, 0x2b, 0xc6, 0x33, 0xe9, 0xc6, 0x00, 0x6e, 0xd1, 0x75, 0x13, 0xc8, 0x40, 0x32, 0xe9, 0xe4, - 0x82, 0x2b, 0x8e, 0x77, 0x58, 0x10, 0x3a, 0x93, 0x30, 0x27, 0x06, 0x70, 0x8a, 0xee, 0xee, 0x56, - 0xc2, 0x13, 0x5e, 0x61, 0xdc, 0xb2, 0xd2, 0xf0, 0xdd, 0xfb, 0x6d, 0x5d, 0x4b, 0xd6, 0x04, 0x24, - 0xe4, 0x02, 0xdc, 0xf0, 0xc4, 0xcf, 0x32, 0x48, 0xcb, 0xed, 0xba, 0xd4, 0x10, 0xf2, 0x7d, 0x01, - 0xdd, 0x7e, 0xad, 0x6d, 0xbc, 0x53, 0xbe, 0x02, 0x5c, 0xa0, 0x35, 0x16, 0x41, 0xa6, 0x58, 0xcc, - 0x20, 0xf2, 0x62, 0x00, 0x69, 0x1a, 0x7b, 0xf3, 0xfb, 0x2b, 0x87, 0x07, 0x4e, 0x8b, 0x3f, 0xa7, - 0x7f, 0x8d, 0x7f, 0xeb, 0x87, 0x1f, 0x41, 0x1d, 0x03, 0xc8, 0x9e, 0x75, 0x36, 0xb2, 0x3b, 0x57, - 0x23, 0xfb, 0xce, 0xd0, 0x1f, 0xa4, 0xcf, 0xc9, 0x54, 0x4f, 0x42, 0x57, 0xc7, 0x2b, 0x25, 0x1e, - 0x7f, 0x31, 0xd0, 0x56, 0x0c, 0xe0, 0x41, 0xe6, 0x07, 0x29, 0x44, 0x5e, 0x6d, 0x53, 0x9a, 0x73, - 0x95, 0xfa, 0xa3, 0x56, 0xf5, 0x63, 0x80, 0x57, 0x9a, 0xf3, 0x52, 0x53, 0x7a, 0x0f, 0x6a, 0xe9, - 0xbb, 0x5a, 0x7a, 0x56, 0x57, 0x42, 0x71, 0x3c, 0xcd, 0x93, 0xf8, 0xab, 0x81, 0x36, 0x05, 0x24, - 0x4c, 0x2a, 0x10, 0x10, 0x79, 0x02, 0x52, 0x7f, 0x08, 0x42, 0x9a, 0xf3, 0x95, 0x85, 0x6e, 0xab, - 0x05, 0x7a, 0xcd, 0xa1, 0x9a, 0xf2, 0x22, 0x8a, 0x04, 0x48, 0xd9, 0x23, 0xb5, 0x93, 0x5d, 0xed, - 0x64, 0x46, 0x6f, 0x42, 0xb1, 0x98, 0x66, 0x4b, 0xfc, 0x19, 0xad, 0xc7, 0x5c, 0x7c, 0xf2, 0xc5, - 0x84, 0x89, 0x85, 0xca, 0x84, 0xd3, 0x9e, 0x83, 0x26, 0x4c, 0x39, 0xb0, 0x6b, 0x07, 0x3b, 0x75, - 0x16, 0x53, 0x5d, 0x09, 0x5d, 0x8b, 0x6f, 0xf0, 0x24, 0x29, 0xd0, 0xc6, 0x5f, 0x91, 0xe2, 0xc7, - 0x68, 0x29, 0xe7, 0x42, 0x79, 0x2c, 0x32, 0x8d, 0x3d, 0x63, 0x7f, 0xb9, 0x87, 0xaf, 0x46, 0xf6, - 0xaa, 0xee, 0x59, 0x6f, 0x10, 0xba, 0x58, 0x56, 0xfd, 0x08, 0x3f, 0x41, 0xa8, 0xce, 0xb9, 0xc4, - 0xcf, 0x55, 0xf8, 0xed, 0xab, 0x91, 0xbd, 0xa1, 0xf1, 0xe3, 0x3d, 0x42, 0x97, 0xeb, 0x8f, 0x7e, - 0x44, 0x7e, 0x1a, 0xc8, 0x6c, 0x0b, 0x12, 0x9b, 0x68, 0xc9, 0xd7, 0xa5, 0xd6, 0xa7, 0xcd, 0x27, - 0xa6, 0x68, 0x2b, 0xe4, 0xa7, 0x99, 0x02, 0x91, 0xfb, 0x42, 0x0d, 0xbd, 0x06, 0xa6, 0x65, 0xed, - 0xf1, 0x6f, 0x30, 0x0b, 0x45, 0xe8, 0xe6, 0xe4, 0x72, 0xa3, 0x76, 0xf3, 0x00, 0xf3, 0xff, 0x79, - 0x80, 0x6f, 0x06, 0xda, 0x9e, 0x79, 0x09, 0xff, 0x70, 0xff, 0x1e, 0x2d, 0xe7, 0xd5, 0xcc, 0x34, - 0x49, 0xad, 0x1c, 0xde, 0xab, 0x6e, 0xb8, 0x9c, 0x5a, 0xa7, 0x19, 0xd5, 0xa2, 0xeb, 0xe8, 0xc9, - 0xea, 0x47, 0x3d, 0xb3, 0xbe, 0xd0, 0xf5, 0x3a, 0xfc, 0x86, 0x4d, 0xe8, 0xad, 0xbc, 0xc1, 0xbc, - 0x39, 0xbb, 0xb0, 0x8c, 0xf3, 0x0b, 0xcb, 0xf8, 0x7d, 0x61, 0x19, 0x3f, 0x2e, 0xad, 0xce, 0xf9, - 0xa5, 0xd5, 0xf9, 0x75, 0x69, 0x75, 0x3e, 0x3c, 0x4d, 0x98, 0x3a, 0x39, 0x0d, 0x9c, 0x90, 0x0f, - 0xdc, 0x90, 0xcb, 0x01, 0x97, 0x2e, 0x0b, 0xc2, 0x83, 0x84, 0xbb, 0xc5, 0x91, 0x3b, 0xe0, 0xd1, - 0x69, 0x0a, 0xb2, 0x7c, 0x54, 0xa4, 0x7b, 0xf8, 0xec, 0xa0, 0x7c, 0x4f, 0xd4, 0x30, 0x07, 0x19, - 0x2c, 0x56, 0x8f, 0xc5, 0xd1, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x33, 0x0f, 0x78, 0xca, - 0x04, 0x00, 0x00, + // 652 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x41, 0x6f, 0xd3, 0x30, + 0x18, 0x6d, 0x36, 0xb6, 0x31, 0x0f, 0xad, 0x9b, 0xd7, 0xb1, 0xa8, 0x88, 0x74, 0x18, 0x21, 0x4d, + 0xa0, 0x25, 0xea, 0x06, 0x07, 0xb8, 0xd1, 0x89, 0xa1, 0x9e, 0x98, 0x0c, 0x27, 0x2e, 0x55, 0x9a, + 0x7c, 0xe9, 0x2c, 0xda, 0x38, 0xb2, 0xbd, 0x4e, 0xe5, 0xc6, 0x05, 0x38, 0xf2, 0x1b, 0xf8, 0x21, + 0x9c, 0x77, 0xdc, 0x91, 0x53, 0x85, 0xb6, 0x7f, 0xb0, 0x5f, 0x80, 0x12, 0x3b, 0x6b, 0x9b, 0xb5, + 0x68, 0xe2, 0x66, 0xc7, 0xef, 0x7d, 0xef, 0xd9, 0xef, 0xcb, 0x87, 0x9e, 0xb0, 0x76, 0xe0, 0xf9, + 0x49, 0xd2, 0x65, 0x81, 0xaf, 0x18, 0x8f, 0xa5, 0x17, 0x01, 0x78, 0xfd, 0xba, 0xd7, 0x81, 0x18, + 0x24, 0x93, 0x6e, 0x22, 0xb8, 0xe2, 0x78, 0x8b, 0xb5, 0x03, 0x77, 0x1c, 0xe6, 0x46, 0x00, 0x6e, + 0xbf, 0x5e, 0xad, 0x74, 0x78, 0x87, 0x67, 0x18, 0x2f, 0x5d, 0x69, 0x78, 0xf5, 0xd1, 0xac, 0xaa, + 0x29, 0x6b, 0x0c, 0x12, 0x70, 0x01, 0x5e, 0x70, 0xec, 0xc7, 0x31, 0x74, 0xd3, 0x63, 0xb3, 0xd4, + 0x10, 0xf2, 0x7d, 0x01, 0xdd, 0x7b, 0xab, 0x6d, 0xbc, 0x57, 0xbe, 0x02, 0xdc, 0x47, 0x65, 0x16, + 0x42, 0xac, 0x58, 0xc4, 0x20, 0x6c, 0x45, 0x00, 0xd2, 0xb6, 0xb6, 0xe7, 0x77, 0x56, 0xf6, 0x76, + 0xdd, 0x19, 0xfe, 0xdc, 0xe6, 0x35, 0xfe, 0xc8, 0x0f, 0x3e, 0x81, 0x3a, 0x04, 0x90, 0x0d, 0xe7, + 0x6c, 0x58, 0x2b, 0x5d, 0x0d, 0x6b, 0xf7, 0x07, 0x7e, 0xaf, 0xfb, 0x8a, 0x14, 0x6a, 0x12, 0xba, + 0x3a, 0xfa, 0x92, 0xe2, 0xf1, 0x17, 0x0b, 0x55, 0x22, 0x80, 0x16, 0xc4, 0x7e, 0xbb, 0x0b, 0x61, + 0xcb, 0xd8, 0x94, 0xf6, 0x5c, 0xa6, 0xfe, 0x74, 0xa6, 0xfa, 0x21, 0xc0, 0x1b, 0xcd, 0x39, 0xd0, + 0x94, 0xc6, 0x63, 0x23, 0xfd, 0x40, 0x4b, 0x4f, 0xab, 0x4a, 0x28, 0x8e, 0x8a, 0x3c, 0x89, 0x4f, + 0xd1, 0xba, 0x80, 0x0e, 0x93, 0x0a, 0x04, 0x84, 0xad, 0xc4, 0x1f, 0xa4, 0xb7, 0x9f, 0xcf, 0xf4, + 0x77, 0x66, 0xea, 0xd3, 0x6b, 0xc6, 0x51, 0x4a, 0x68, 0x6c, 0x1b, 0x75, 0x5b, 0xab, 0xdf, 0x28, + 0x48, 0xe8, 0x9a, 0x98, 0xa4, 0x48, 0xfc, 0xd5, 0x42, 0x1b, 0x63, 0x40, 0x01, 0x5d, 0x7f, 0x00, + 0x42, 0xda, 0x77, 0x32, 0xed, 0xfa, 0x2d, 0xb4, 0xa9, 0xa6, 0xbc, 0x0e, 0x43, 0x01, 0x52, 0x36, + 0x88, 0x31, 0x51, 0xbd, 0x61, 0x22, 0xaf, 0x4d, 0x28, 0x16, 0x45, 0xb6, 0xc4, 0x9f, 0xd1, 0x5a, + 0xc4, 0xc5, 0xa9, 0x2f, 0xc6, 0x4c, 0x2c, 0x64, 0x26, 0xdc, 0xd9, 0x01, 0x68, 0x42, 0xc1, 0x41, + 0xcd, 0x38, 0xd8, 0x32, 0x21, 0x14, 0xaa, 0x12, 0x5a, 0x8e, 0x26, 0x78, 0x92, 0xf4, 0xd1, 0xfa, + 0x8d, 0x2c, 0xf1, 0x33, 0xb4, 0x94, 0x70, 0xa1, 0x5a, 0x2c, 0xb4, 0xad, 0x6d, 0x6b, 0x67, 0xb9, + 0x81, 0xaf, 0x86, 0xb5, 0x55, 0x5d, 0xd3, 0x1c, 0x10, 0xba, 0x98, 0xae, 0x9a, 0x21, 0x7e, 0x8e, + 0x90, 0x09, 0x38, 0xc5, 0xcf, 0x65, 0xf8, 0xcd, 0xab, 0x61, 0x6d, 0x5d, 0xe3, 0x47, 0x67, 0x84, + 0x2e, 0x9b, 0x4d, 0x33, 0x24, 0x3f, 0x2d, 0x54, 0x2e, 0x84, 0x88, 0x0f, 0x50, 0xd9, 0x38, 0x6d, + 0xf9, 0xfa, 0x42, 0x46, 0xbe, 0x3a, 0x6a, 0xe9, 0x02, 0x80, 0xd0, 0x55, 0x31, 0xf1, 0x04, 0xb8, + 0x82, 0x16, 0xb2, 0xc8, 0xb5, 0x13, 0xaa, 0x37, 0x05, 0x93, 0xf3, 0xb7, 0x34, 0xf9, 0xcb, 0x42, + 0xf6, 0xac, 0xb4, 0xb1, 0x8d, 0x96, 0x26, 0x5c, 0xd2, 0x7c, 0x8b, 0x29, 0xaa, 0x04, 0xfc, 0x24, + 0x56, 0x20, 0x12, 0x5f, 0xa8, 0xc1, 0xf5, 0x65, 0xf4, 0xdb, 0xd4, 0x46, 0x3f, 0xc9, 0x34, 0x14, + 0xa1, 0x1b, 0xe3, 0x9f, 0x73, 0xb5, 0xff, 0xbb, 0xc0, 0x37, 0x0b, 0x6d, 0x4e, 0xed, 0x94, 0x7f, + 0xb8, 0xff, 0x80, 0x96, 0x93, 0x6c, 0xa2, 0xe4, 0x71, 0xae, 0xec, 0x3d, 0xcc, 0xda, 0x30, 0x9d, + 0x69, 0x6e, 0x3e, 0xc8, 0xfa, 0x75, 0x57, 0xcf, 0x9d, 0x66, 0xd8, 0xb0, 0x4d, 0xd7, 0xad, 0x99, + 0x0e, 0xc9, 0xd9, 0x84, 0xde, 0x4d, 0x72, 0xcc, 0xbb, 0xb3, 0x0b, 0xc7, 0x3a, 0xbf, 0x70, 0xac, + 0x3f, 0x17, 0x8e, 0xf5, 0xe3, 0xd2, 0x29, 0x9d, 0x5f, 0x3a, 0xa5, 0xdf, 0x97, 0x4e, 0xe9, 0xe3, + 0x8b, 0x0e, 0x53, 0xc7, 0x27, 0x6d, 0x37, 0xe0, 0x3d, 0x2f, 0xe0, 0xb2, 0xc7, 0xa5, 0xc7, 0xda, + 0xc1, 0x6e, 0x87, 0x7b, 0xfd, 0x7d, 0xaf, 0xc7, 0xc3, 0x93, 0x2e, 0xc8, 0x74, 0xe4, 0x4a, 0x6f, + 0xef, 0xe5, 0x6e, 0x3a, 0x6d, 0xd5, 0x20, 0x01, 0xd9, 0x5e, 0xcc, 0x46, 0xe9, 0xfe, 0xdf, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xb6, 0xf7, 0x84, 0x44, 0xe8, 0x05, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -354,7 +432,7 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x22 + dAtA[i] = 0x2a } } if len(m.RegisteredRelayers) > 0 { @@ -368,6 +446,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- + dAtA[i] = 0x22 + } + } + if len(m.RegisteredPayees) > 0 { + for iNdEx := len(m.RegisteredPayees) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RegisteredPayees[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- dAtA[i] = 0x1a } } @@ -439,6 +531,50 @@ func (m *FeeEnabledChannel) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *RegisteredPayee) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RegisteredPayee) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RegisteredPayee) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x1a + } + if len(m.Payee) > 0 { + i -= len(m.Payee) + copy(dAtA[i:], m.Payee) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Payee))) + i-- + dAtA[i] = 0x12 + } + if len(m.RelayerAddress) > 0 { + i -= len(m.RelayerAddress) + copy(dAtA[i:], m.RelayerAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.RelayerAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *RegisteredRelayerAddress) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -552,6 +688,12 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.RegisteredPayees) > 0 { + for _, e := range m.RegisteredPayees { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } if len(m.RegisteredRelayers) > 0 { for _, e := range m.RegisteredRelayers { l = e.Size() @@ -584,6 +726,27 @@ func (m *FeeEnabledChannel) Size() (n int) { return n } +func (m *RegisteredPayee) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RelayerAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Payee) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + func (m *RegisteredRelayerAddress) Size() (n int) { if m == nil { return 0 @@ -724,6 +887,40 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RegisteredPayees", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RegisteredPayees = append(m.RegisteredPayees, RegisteredPayee{}) + if err := m.RegisteredPayees[len(m.RegisteredPayees)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field RegisteredRelayers", wireType) } @@ -757,7 +954,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 4: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ForwardRelayers", wireType) } @@ -926,6 +1123,152 @@ func (m *FeeEnabledChannel) Unmarshal(dAtA []byte) error { } return nil } +func (m *RegisteredPayee) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RegisteredPayee: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RegisteredPayee: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RelayerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RelayerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Payee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Payee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *RegisteredRelayerAddress) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/29-fee/types/genesis_test.go b/modules/apps/29-fee/types/genesis_test.go index d574257e706..fa6ca6d1dd2 100644 --- a/modules/apps/29-fee/types/genesis_test.go +++ b/modules/apps/29-fee/types/genesis_test.go @@ -8,32 +8,17 @@ import ( "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" ) -var ( - addr1 = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - addr2 = sdk.AccAddress("testaddr2").String() - validCoins = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}} - validCoins2 = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}} - validCoins3 = sdk.Coins{sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(300)}} -) +func TestValidateDefaultGenesis(t *testing.T) { + err := types.DefaultGenesisState().Validate() + require.NoError(t, err) +} func TestValidateGenesis(t *testing.T) { - var ( - packetID channeltypes.PacketId - fee types.Fee - refundAcc string - sender string - forwardAddr string - counterparty string - portID string - channelID string - packetChannelID string - seq uint64 - ) + var genState *types.GenesisState testCases := []struct { name string @@ -41,166 +26,149 @@ func TestValidateGenesis(t *testing.T) { expPass bool }{ { - "valid genesis", + "success - valid genesis", func() {}, true, }, { - "invalid packetID: invalid channel", + "invalid packetID: invalid port ID", func() { - packetID = channeltypes.NewPacketId( - portID, - "", - seq, - ) + genState.IdentifiedFees[0].PacketId = channeltypes.NewPacketId("", ibctesting.FirstChannelID, 1) }, false, }, { - "invalid packetID: invalid port", + "invalid packetID: invalid channel ID", func() { - packetID = channeltypes.NewPacketId( - "", - channelID, - seq, - ) + genState.IdentifiedFees[0].PacketId = channeltypes.NewPacketId(ibctesting.MockFeePort, "", 1) }, false, }, { "invalid packetID: invalid sequence", func() { - packetID = channeltypes.NewPacketId( - portID, - channelID, - 0, - ) + genState.IdentifiedFees[0].PacketId = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 0) + }, + false, + }, + { + "invalid packet fee: invalid fee", + func() { + genState.IdentifiedFees[0].PacketFees[0].Fee = types.NewFee(sdk.Coins{}, sdk.Coins{}, sdk.Coins{}) + }, + false, + }, + { + "invalid packet fee: invalid refund address", + func() { + genState.IdentifiedFees[0].PacketFees[0].RefundAddress = "" + }, + false, + }, + { + "invalid fee enabled channel: invalid port ID", + func() { + genState.FeeEnabledChannels[0].PortId = "" }, false, }, { - "invalid packetID: invalid fee", + "invalid fee enabled channel: invalid channel ID", func() { - fee = types.Fee{ - sdk.Coins{}, - sdk.Coins{}, - sdk.Coins{}, - } + genState.FeeEnabledChannels[0].ChannelId = "" }, false, }, { - "invalid packetID: invalid refundAcc", + "invalid registered payee: invalid relayer address", func() { - refundAcc = "" + genState.RegisteredPayees[0].RelayerAddress = "" }, false, }, { - "invalid FeeEnabledChannel: invalid ChannelID", + "invalid registered payee: invalid payee address", func() { - channelID = "" + genState.RegisteredPayees[0].Payee = "" }, false, }, { - "invalid FeeEnabledChannel: invalid PortID", + "invalid registered payee: invalid channel ID", func() { - portID = "" + genState.RegisteredPayees[0].ChannelId = "" }, false, }, { - "invalid RegisteredRelayers: invalid sender", + "invalid registered relayers: invalid sender", func() { - sender = "" + genState.RegisteredRelayers[0].Address = "" }, false, }, { - "invalid RegisteredRelayers: invalid counterparty", + "invalid registered relayers: invalid counterparty", func() { - counterparty = " " + genState.RegisteredRelayers[0].CounterpartyAddress = "" }, false, }, { - "invalid ForwardRelayerAddress: invalid forwardAddr", + "invalid forward relayer address: invalid forward address", func() { - forwardAddr = "" + genState.ForwardRelayers[0].Address = "" }, false, }, { - "invalid ForwardRelayerAddress: invalid packet", + "invalid forward relayer address: invalid packet", func() { - packetChannelID = "1" + genState.ForwardRelayers[0].PacketId = channeltypes.PacketId{} }, false, }, } for _, tc := range testCases { - portID = transfertypes.PortID - channelID = ibctesting.FirstChannelID - packetChannelID = ibctesting.FirstChannelID - seq = uint64(1) - - // build PacketId & Fee - packetID = channeltypes.NewPacketId( - portID, - channelID, - seq, - ) - fee = types.Fee{ - validCoins, - validCoins2, - validCoins3, - } - - refundAcc = addr1 - - // relayer addresses - sender = addr1 - counterparty = addr2 - forwardAddr = addr2 - - tc.malleate() - - genState := types.GenesisState{ + genState = &types.GenesisState{ IdentifiedFees: []types.IdentifiedPacketFees{ { - PacketId: packetID, - PacketFees: []types.PacketFee{ - { - Fee: fee, - RefundAddress: refundAcc, - Relayers: nil, - }, - }, + PacketId: channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1), + PacketFees: []types.PacketFee{types.NewPacketFee(types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee), defaultAccAddress, nil)}, }, }, FeeEnabledChannels: []types.FeeEnabledChannel{ { - PortId: portID, - ChannelId: channelID, + PortId: ibctesting.MockFeePort, + ChannelId: ibctesting.FirstChannelID, }, }, RegisteredRelayers: []types.RegisteredRelayerAddress{ { - Address: sender, - CounterpartyAddress: counterparty, + Address: defaultAccAddress, + CounterpartyAddress: defaultAccAddress, }, }, ForwardRelayers: []types.ForwardRelayerAddress{ { - Address: forwardAddr, - PacketId: channeltypes.NewPacketId(portID, packetChannelID, 1), + Address: defaultAccAddress, + PacketId: channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1), + }, + }, + RegisteredPayees: []types.RegisteredPayee{ + { + RelayerAddress: sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String(), + Payee: sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String(), + ChannelId: ibctesting.FirstChannelID, }, }, } + tc.malleate() + err := genState.Validate() + if tc.expPass { require.NoError(t, err, tc.name) } else { @@ -208,8 +176,3 @@ func TestValidateGenesis(t *testing.T) { } } } - -func TestValidateDefaultGenesis(t *testing.T) { - err := types.DefaultGenesisState().Validate() - require.NoError(t, err) -} diff --git a/proto/ibc/applications/fee/v1/genesis.proto b/proto/ibc/applications/fee/v1/genesis.proto index cae132239d6..57af52f32d9 100644 --- a/proto/ibc/applications/fee/v1/genesis.proto +++ b/proto/ibc/applications/fee/v1/genesis.proto @@ -16,11 +16,14 @@ message GenesisState { // list of fee enabled channels repeated FeeEnabledChannel fee_enabled_channels = 2 [(gogoproto.moretags) = "yaml:\"fee_enabled_channels\"", (gogoproto.nullable) = false]; + // list of registered payees + repeated RegisteredPayee registered_payees = 3 + [(gogoproto.moretags) = "yaml:\"registered_payees\"", (gogoproto.nullable) = false]; // list of registered relayer addresses - repeated RegisteredRelayerAddress registered_relayers = 3 + repeated RegisteredRelayerAddress registered_relayers = 4 [(gogoproto.moretags) = "yaml:\"registered_relayers\"", (gogoproto.nullable) = false]; // list of forward relayer addresses - repeated ForwardRelayerAddress forward_relayers = 4 + repeated ForwardRelayerAddress forward_relayers = 5 [(gogoproto.moretags) = "yaml:\"forward_relayers\"", (gogoproto.nullable) = false]; } @@ -32,6 +35,16 @@ message FeeEnabledChannel { string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; } +// RegisteredPayee contains the relayer address and payee address for a specific channel +message RegisteredPayee { + // the relayer address + string relayer_address = 1 [(gogoproto.moretags) = "yaml:\"relayer_address\""]; + // the payee address + string payee = 2; + // unique channel identifier + string channel_id = 3 [(gogoproto.moretags) = "yaml:\"channel_id\""]; +} + // RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) message RegisteredRelayerAddress { // the relayer address From 187772b4ed3c7d7ccf4bde93fb3a5c1bd39548d9 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 8 Jun 2022 23:07:12 +0200 Subject: [PATCH 148/275] fix typo --- docs/migrations/v3-to-v4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index a6a90055a69..49f311a844e 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -28,7 +28,7 @@ The return signature now includes the application version as detailed in the lat ### ICS27 - Interchain Accounts -The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middelware, for relayer incentivization of ICS27 packets. +The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. From 2c7697348d30a833634069df9392bd0d2618a597 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 9 Jun 2022 14:18:26 +0200 Subject: [PATCH 149/275] feat: adding Payee grpc query and CLI (#1493) * [WIP] adding RegisterDistributionAddress rpc endpoint and implementation. Store funcs, keys.. * updating tests * adding registered distribution addresses to genesis state * refactor and update validate genesis tests * adding grpc query and cli for distribution address rpc endpoint * adding cli for register distribution address rpc * renaming RegisterDistributionAddress rpc to RegisterPayee * renaming RegisterDistributionAddress to RegisterPayee * updating godocs and field ordering * updating inline comment * renaming to regsitered payees and propagating changes in genesis * updating godoc in keeper.go * Update modules/apps/29-fee/keeper/keeper_test.go Co-authored-by: Aditya * renaming query and types to align with payee address naming convention Co-authored-by: Aditya --- docs/client/swagger-ui/swagger.yaml | 225 +++++++ docs/ibc/proto-docs.md | 34 + modules/apps/29-fee/client/cli/cli.go | 1 + modules/apps/29-fee/client/cli/query.go | 39 ++ modules/apps/29-fee/keeper/grpc_query.go | 18 + modules/apps/29-fee/keeper/grpc_query_test.go | 63 ++ modules/apps/29-fee/types/query.pb.go | 614 +++++++++++++++--- modules/apps/29-fee/types/query.pb.gw.go | 120 ++++ proto/ibc/applications/fee/v1/query.proto | 19 + 9 files changed, 1045 insertions(+), 88 deletions(-) diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml index 084cc498a5d..5299015bfff 100644 --- a/docs/client/swagger-ui/swagger.yaml +++ b/docs/client/swagger-ui/swagger.yaml @@ -1266,6 +1266,224 @@ paths: type: string tags: - Query + '/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/payee': + get: + summary: >- + Payee returns the registered payee address for a specific channel given + the relayer address + operationId: Payee + responses: + '200': + description: A successful response. + schema: + type: object + properties: + payee_address: + type: string + title: the payee address to which packet fees are paid out + title: QueryPayeeResponse defines the response type for the Payee rpc + default: + description: An unexpected error response + schema: + type: object + properties: + error: + type: string + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the type of + the serialized + + protocol buffer message. This string must contain at + least + + one "/" character. The last segment of the URL's path + must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be in + a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the binary + all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can optionally + set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based + on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in + the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty scheme) + might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the above + specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any values + in the form + + of utility functions or additional generated methods of the + Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and the + unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will yield + type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the regular + + representation of the deserialized, embedded message, with + an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom + JSON + + representation, that representation will be embedded adding + a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + parameters: + - name: channel_id + description: unique channel identifier + in: path + required: true + type: string + - name: relayer_address + description: the relayer address to which the distribution address is registered + in: path + required: true + type: string + tags: + - Query '/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/incentivized_packet': get: summary: >- @@ -13682,6 +13900,13 @@ definitions: title: >- QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPackets rpc + ibc.applications.fee.v1.QueryPayeeResponse: + type: object + properties: + payee_address: + type: string + title: the payee address to which packet fees are paid out + title: QueryPayeeResponse defines the response type for the Payee rpc ibc.applications.fee.v1.QueryTotalAckFeesResponse: type: object properties: diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index fe55e9c32be..396b5d37f9d 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -57,6 +57,8 @@ - [QueryIncentivizedPacketsForChannelResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse) - [QueryIncentivizedPacketsRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsRequest) - [QueryIncentivizedPacketsResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsResponse) + - [QueryPayeeRequest](#ibc.applications.fee.v1.QueryPayeeRequest) + - [QueryPayeeResponse](#ibc.applications.fee.v1.QueryPayeeResponse) - [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) - [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) - [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) @@ -1126,6 +1128,37 @@ QueryIncentivizedPacketsResponse defines the response type for the IncentivizedP + + +### QueryPayeeRequest +QueryPayeeRequest defines the request type for the Payee rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `channel_id` | [string](#string) | | unique channel identifier | +| `relayer_address` | [string](#string) | | the relayer address to which the distribution address is registered | + + + + + + + + +### QueryPayeeResponse +QueryPayeeResponse defines the response type for the Payee rpc + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `payee_address` | [string](#string) | | the payee address to which packet fees are paid out | + + + + + + ### QueryTotalAckFeesRequest @@ -1235,6 +1268,7 @@ Query defines the ICS29 gRPC querier service. | `TotalRecvFees` | [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) | [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) | TotalRecvFees returns the total receive fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_recv_fees| | `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_ack_fees| | `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_timeout_fees| +| `Payee` | [QueryPayeeRequest](#ibc.applications.fee.v1.QueryPayeeRequest) | [QueryPayeeResponse](#ibc.applications.fee.v1.QueryPayeeResponse) | Payee returns the registered payee address for a specific channel given the relayer address | GET|/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/payee| | `CounterpartyAddress` | [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) | [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) | CounterpartyAddress returns the registered counterparty address for forward relaying | GET|/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address| | `FeeEnabledChannels` | [QueryFeeEnabledChannelsRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest) | [QueryFeeEnabledChannelsResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse) | FeeEnabledChannels returns a list of all fee enabled channels | GET|/ibc/apps/fee/v1/fee_enabled| | `FeeEnabledChannel` | [QueryFeeEnabledChannelRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelRequest) | [QueryFeeEnabledChannelResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelResponse) | FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel | GET|/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled| diff --git a/modules/apps/29-fee/client/cli/cli.go b/modules/apps/29-fee/client/cli/cli.go index 1306efa84b9..fdf5d3ffbb9 100644 --- a/modules/apps/29-fee/client/cli/cli.go +++ b/modules/apps/29-fee/client/cli/cli.go @@ -21,6 +21,7 @@ func GetQueryCmd() *cobra.Command { GetCmdTotalAckFees(), GetCmdTotalTimeoutFees(), GetCmdIncentivizedPacketsForChannel(), + GetCmdPayee(), GetCmdCounterpartyAddress(), GetCmdFeeEnabledChannel(), GetCmdFeeEnabledChannels(), diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index ccf05b61b23..3cfdcb27b33 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -239,6 +239,45 @@ func GetCmdTotalTimeoutFees() *cobra.Command { return cmd } +// GetCmdPayee returns the command handler for the Query/Payee rpc. +func GetCmdPayee() *cobra.Command { + cmd := &cobra.Command{ + Use: "payee [channel-id] [relayer-address]", + Short: "Query the relayer payee address on a given channel", + Long: "Query the relayer payee address on a given channel", + Args: cobra.ExactArgs(2), + Example: fmt.Sprintf("%s query ibc-fee payee channel-5 cosmos1layxcsmyye0dc0har9sdfzwckaz8sjwlfsj8zs", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + if _, err := sdk.AccAddressFromBech32(args[1]); err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryPayeeRequest{ + ChannelId: args[0], + RelayerAddress: args[1], + } + + res, err := queryClient.Payee(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + // GetCmdCounterpartyAddress returns the command handler for the Query/CounterpartyAddress rpc. func GetCmdCounterpartyAddress() *cobra.Command { cmd := &cobra.Command{ diff --git a/modules/apps/29-fee/keeper/grpc_query.go b/modules/apps/29-fee/keeper/grpc_query.go index 9b95753f25c..2df2b1823c9 100644 --- a/modules/apps/29-fee/keeper/grpc_query.go +++ b/modules/apps/29-fee/keeper/grpc_query.go @@ -171,6 +171,24 @@ func (k Keeper) TotalTimeoutFees(goCtx context.Context, req *types.QueryTotalTim }, nil } +// Payee implements the Query/Payee gRPC method and returns the registered payee address to which packet fees are paid out +func (k Keeper) Payee(goCtx context.Context, req *types.QueryPayeeRequest) (*types.QueryPayeeResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + payeeAddr, found := k.GetPayeeAddress(ctx, req.RelayerAddress, req.ChannelId) + if !found { + return nil, status.Errorf(codes.NotFound, "payee address not found for address: %s on channel: %s", req.RelayerAddress, req.ChannelId) + } + + return &types.QueryPayeeResponse{ + PayeeAddress: payeeAddr, + }, nil +} + // CounterpartyAddress implements the Query/CounterpartyAddress gRPC method and returns the registered counterparty address for forward relaying func (k Keeper) CounterpartyAddress(goCtx context.Context, req *types.QueryCounterpartyAddressRequest) (*types.QueryCounterpartyAddressResponse, error) { if req == nil { diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index 5850a3be3ba..dc345fa06eb 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -409,6 +409,69 @@ func (suite *KeeperTestSuite) TestQueryTotalTimeoutFees() { } } +func (suite *KeeperTestSuite) TestQueryPayee() { + var req *types.QueryPayeeRequest + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "payee address not found: invalid channel", + func() { + req.ChannelId = "invalid-channel-id" + }, + false, + }, + { + "payee address not found: invalid relayer address", + func() { + req.RelayerAddress = "invalid-addr" + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + pk := secp256k1.GenPrivKey().PubKey() + expPayeeAddr := sdk.AccAddress(pk.Address()) + + suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + expPayeeAddr.String(), + suite.path.EndpointA.ChannelID, + ) + + req = &types.QueryPayeeRequest{ + ChannelId: suite.path.EndpointA.ChannelID, + RelayerAddress: suite.chainA.SenderAccount.GetAddress().String(), + } + + tc.malleate() + + ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) + res, err := suite.queryClient.Payee(ctx, req) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expPayeeAddr.String(), res.PayeeAddress) + } else { + suite.Require().Error(err) + } + }) + } +} + func (suite *KeeperTestSuite) TestQueryCounterpartyAddress() { var req *types.QueryCounterpartyAddressRequest diff --git a/modules/apps/29-fee/types/query.pb.go b/modules/apps/29-fee/types/query.pb.go index 1a9eba1927f..9d0de9110a5 100644 --- a/modules/apps/29-fee/types/query.pb.go +++ b/modules/apps/29-fee/types/query.pb.go @@ -637,6 +637,107 @@ func (m *QueryTotalTimeoutFeesResponse) GetTimeoutFees() github_com_cosmos_cosmo return nil } +// QueryPayeeRequest defines the request type for the Payee rpc +type QueryPayeeRequest struct { + // unique channel identifier + ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + // the relayer address to which the distribution address is registered + RelayerAddress string `protobuf:"bytes,2,opt,name=relayer_address,json=relayerAddress,proto3" json:"relayer_address,omitempty" yaml:"relayer_address"` +} + +func (m *QueryPayeeRequest) Reset() { *m = QueryPayeeRequest{} } +func (m *QueryPayeeRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPayeeRequest) ProtoMessage() {} +func (*QueryPayeeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{12} +} +func (m *QueryPayeeRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPayeeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPayeeRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryPayeeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPayeeRequest.Merge(m, src) +} +func (m *QueryPayeeRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPayeeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPayeeRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPayeeRequest proto.InternalMessageInfo + +func (m *QueryPayeeRequest) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + +func (m *QueryPayeeRequest) GetRelayerAddress() string { + if m != nil { + return m.RelayerAddress + } + return "" +} + +// QueryPayeeResponse defines the response type for the Payee rpc +type QueryPayeeResponse struct { + // the payee address to which packet fees are paid out + PayeeAddress string `protobuf:"bytes,1,opt,name=payee_address,json=payeeAddress,proto3" json:"payee_address,omitempty" yaml:"payee_address"` +} + +func (m *QueryPayeeResponse) Reset() { *m = QueryPayeeResponse{} } +func (m *QueryPayeeResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPayeeResponse) ProtoMessage() {} +func (*QueryPayeeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0638a8a78ca2503c, []int{13} +} +func (m *QueryPayeeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPayeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPayeeResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryPayeeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPayeeResponse.Merge(m, src) +} +func (m *QueryPayeeResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPayeeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPayeeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPayeeResponse proto.InternalMessageInfo + +func (m *QueryPayeeResponse) GetPayeeAddress() string { + if m != nil { + return m.PayeeAddress + } + return "" +} + // QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc type QueryCounterpartyAddressRequest struct { // unique channel identifier @@ -649,7 +750,7 @@ func (m *QueryCounterpartyAddressRequest) Reset() { *m = QueryCounterpar func (m *QueryCounterpartyAddressRequest) String() string { return proto.CompactTextString(m) } func (*QueryCounterpartyAddressRequest) ProtoMessage() {} func (*QueryCounterpartyAddressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0638a8a78ca2503c, []int{12} + return fileDescriptor_0638a8a78ca2503c, []int{14} } func (m *QueryCounterpartyAddressRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -702,7 +803,7 @@ func (m *QueryCounterpartyAddressResponse) Reset() { *m = QueryCounterpa func (m *QueryCounterpartyAddressResponse) String() string { return proto.CompactTextString(m) } func (*QueryCounterpartyAddressResponse) ProtoMessage() {} func (*QueryCounterpartyAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0638a8a78ca2503c, []int{13} + return fileDescriptor_0638a8a78ca2503c, []int{15} } func (m *QueryCounterpartyAddressResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -750,7 +851,7 @@ func (m *QueryFeeEnabledChannelsRequest) Reset() { *m = QueryFeeEnabledC func (m *QueryFeeEnabledChannelsRequest) String() string { return proto.CompactTextString(m) } func (*QueryFeeEnabledChannelsRequest) ProtoMessage() {} func (*QueryFeeEnabledChannelsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0638a8a78ca2503c, []int{14} + return fileDescriptor_0638a8a78ca2503c, []int{16} } func (m *QueryFeeEnabledChannelsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -803,7 +904,7 @@ func (m *QueryFeeEnabledChannelsResponse) Reset() { *m = QueryFeeEnabled func (m *QueryFeeEnabledChannelsResponse) String() string { return proto.CompactTextString(m) } func (*QueryFeeEnabledChannelsResponse) ProtoMessage() {} func (*QueryFeeEnabledChannelsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0638a8a78ca2503c, []int{15} + return fileDescriptor_0638a8a78ca2503c, []int{17} } func (m *QueryFeeEnabledChannelsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -851,7 +952,7 @@ func (m *QueryFeeEnabledChannelRequest) Reset() { *m = QueryFeeEnabledCh func (m *QueryFeeEnabledChannelRequest) String() string { return proto.CompactTextString(m) } func (*QueryFeeEnabledChannelRequest) ProtoMessage() {} func (*QueryFeeEnabledChannelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0638a8a78ca2503c, []int{16} + return fileDescriptor_0638a8a78ca2503c, []int{18} } func (m *QueryFeeEnabledChannelRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -904,7 +1005,7 @@ func (m *QueryFeeEnabledChannelResponse) Reset() { *m = QueryFeeEnabledC func (m *QueryFeeEnabledChannelResponse) String() string { return proto.CompactTextString(m) } func (*QueryFeeEnabledChannelResponse) ProtoMessage() {} func (*QueryFeeEnabledChannelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0638a8a78ca2503c, []int{17} + return fileDescriptor_0638a8a78ca2503c, []int{19} } func (m *QueryFeeEnabledChannelResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -953,6 +1054,8 @@ func init() { proto.RegisterType((*QueryTotalAckFeesResponse)(nil), "ibc.applications.fee.v1.QueryTotalAckFeesResponse") proto.RegisterType((*QueryTotalTimeoutFeesRequest)(nil), "ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest") proto.RegisterType((*QueryTotalTimeoutFeesResponse)(nil), "ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse") + proto.RegisterType((*QueryPayeeRequest)(nil), "ibc.applications.fee.v1.QueryPayeeRequest") + proto.RegisterType((*QueryPayeeResponse)(nil), "ibc.applications.fee.v1.QueryPayeeResponse") proto.RegisterType((*QueryCounterpartyAddressRequest)(nil), "ibc.applications.fee.v1.QueryCounterpartyAddressRequest") proto.RegisterType((*QueryCounterpartyAddressResponse)(nil), "ibc.applications.fee.v1.QueryCounterpartyAddressResponse") proto.RegisterType((*QueryFeeEnabledChannelsRequest)(nil), "ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest") @@ -966,88 +1069,92 @@ func init() { } var fileDescriptor_0638a8a78ca2503c = []byte{ - // 1285 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x4f, 0x6f, 0x1b, 0x45, - 0x1c, 0xcd, 0xa4, 0xa1, 0x4d, 0x26, 0xa1, 0x4d, 0xc7, 0xa1, 0x4d, 0x4d, 0x62, 0xa7, 0x53, 0x0a, - 0x21, 0x28, 0xbb, 0x8a, 0x43, 0x9b, 0x96, 0x13, 0xb5, 0x4b, 0x20, 0x20, 0x44, 0x59, 0x2a, 0x04, - 0x08, 0x70, 0xd7, 0xbb, 0x63, 0x67, 0x15, 0x67, 0x67, 0xbb, 0xbb, 0xb6, 0x70, 0xd3, 0x00, 0xad, - 0x88, 0x40, 0x80, 0x00, 0x09, 0x89, 0x03, 0xe2, 0x8a, 0x90, 0x90, 0xf8, 0x00, 0x7c, 0x83, 0x8a, - 0x03, 0x8a, 0xc4, 0x85, 0x93, 0x41, 0x09, 0x27, 0x8e, 0x3e, 0x71, 0x00, 0x09, 0xed, 0xcc, 0xec, - 0x7a, 0xdd, 0xdd, 0x4d, 0xec, 0x60, 0x85, 0x53, 0xec, 0xf9, 0xfd, 0x99, 0xf7, 0xde, 0xfc, 0x3c, - 0xf3, 0x14, 0x78, 0xce, 0x28, 0x69, 0xb2, 0x6a, 0x59, 0x55, 0x43, 0x53, 0x5d, 0x83, 0x9a, 0x8e, - 0x5c, 0x26, 0x44, 0xae, 0x2f, 0xc8, 0x37, 0x6b, 0xc4, 0x6e, 0x48, 0x96, 0x4d, 0x5d, 0x8a, 0x4e, - 0x1b, 0x25, 0x4d, 0x0a, 0x27, 0x49, 0x65, 0x42, 0xa4, 0xfa, 0x42, 0x7a, 0xa2, 0x42, 0x2b, 0x94, - 0xe5, 0xc8, 0xde, 0x27, 0x9e, 0x9e, 0x9e, 0xaa, 0x50, 0x5a, 0xa9, 0x12, 0x59, 0xb5, 0x0c, 0x59, - 0x35, 0x4d, 0xea, 0x8a, 0x22, 0x1e, 0xcd, 0x68, 0xd4, 0x59, 0xa7, 0x8e, 0x5c, 0x52, 0x1d, 0x6f, - 0xa3, 0x12, 0x71, 0xd5, 0x05, 0x59, 0xa3, 0x86, 0x29, 0xe2, 0x73, 0xe1, 0x38, 0x43, 0x11, 0x64, - 0x59, 0x6a, 0xc5, 0x30, 0x59, 0x33, 0x91, 0x7b, 0x36, 0x09, 0xbd, 0x87, 0x8f, 0xa7, 0x9c, 0x4f, - 0x4a, 0xa9, 0x10, 0x93, 0x38, 0x86, 0x13, 0xee, 0xa4, 0x51, 0x9b, 0xc8, 0xda, 0xaa, 0x6a, 0x9a, - 0xa4, 0xea, 0xa5, 0x88, 0x8f, 0x3c, 0x05, 0x7f, 0x0a, 0x60, 0xf6, 0x65, 0x0f, 0xcf, 0x8a, 0xa9, - 0x11, 0xd3, 0x35, 0xea, 0xc6, 0x2d, 0xa2, 0x5f, 0x53, 0xb5, 0x35, 0xe2, 0x3a, 0x0a, 0xb9, 0x59, - 0x23, 0x8e, 0x8b, 0x96, 0x21, 0x6c, 0x83, 0x9c, 0x04, 0x33, 0x60, 0x76, 0x34, 0xf7, 0xa8, 0xc4, - 0x19, 0x49, 0x1e, 0x23, 0x89, 0xeb, 0x2a, 0x18, 0x49, 0xd7, 0xd4, 0x0a, 0x11, 0xb5, 0x4a, 0xa8, - 0x12, 0x9d, 0x85, 0x63, 0x2c, 0xb1, 0xb8, 0x4a, 0x8c, 0xca, 0xaa, 0x3b, 0x39, 0x38, 0x03, 0x66, - 0x87, 0x94, 0x51, 0xb6, 0xf6, 0x1c, 0x5b, 0xc2, 0x1f, 0x03, 0x38, 0x93, 0x0c, 0xc7, 0xb1, 0xa8, - 0xe9, 0x10, 0x54, 0x86, 0x13, 0x46, 0x28, 0x5c, 0xb4, 0x78, 0x7c, 0x12, 0xcc, 0x1c, 0x99, 0x1d, - 0xcd, 0xcd, 0x4b, 0x09, 0x07, 0x2b, 0xad, 0xe8, 0x5e, 0x4d, 0xd9, 0xf0, 0x3b, 0x2e, 0x13, 0xe2, - 0xe4, 0x87, 0xee, 0x35, 0xb3, 0x03, 0x4a, 0xca, 0x88, 0xee, 0x87, 0xb7, 0x00, 0xcc, 0x24, 0x80, - 0xf1, 0xa5, 0x79, 0x1a, 0x8e, 0xf0, 0xdd, 0x8b, 0x86, 0x2e, 0x94, 0x99, 0x66, 0xfb, 0x7b, 0xaa, - 0x4b, 0xbe, 0xd4, 0x75, 0x4f, 0x13, 0x2f, 0x6b, 0x45, 0x17, 0xfb, 0x0d, 0x5b, 0xe2, 0x7b, 0x37, - 0xa2, 0x7c, 0x98, 0x7c, 0x46, 0x81, 0x26, 0x3a, 0x4c, 0xc5, 0x68, 0x22, 0x20, 0x1d, 0x48, 0x12, - 0x14, 0x95, 0x04, 0xff, 0x0c, 0xe0, 0xe3, 0x49, 0xc7, 0xb3, 0x4c, 0xed, 0x02, 0xe7, 0xdb, 0xef, - 0xb9, 0x39, 0x0d, 0x8f, 0x59, 0xd4, 0x66, 0x12, 0x7b, 0xea, 0x8c, 0x28, 0x47, 0xbd, 0xaf, 0x2b, - 0x3a, 0x9a, 0x86, 0x50, 0x48, 0xec, 0xc5, 0x8e, 0xb0, 0xd8, 0x88, 0x58, 0x89, 0x91, 0x76, 0x28, - 0x2a, 0xed, 0x67, 0x00, 0xce, 0x75, 0x43, 0x48, 0xa8, 0x7c, 0xa3, 0x8f, 0x93, 0x17, 0x3f, 0x73, - 0x6f, 0xc1, 0x33, 0x0c, 0xcf, 0x75, 0xea, 0xaa, 0x55, 0x85, 0x68, 0x75, 0x96, 0xda, 0xaf, 0x69, - 0xc3, 0x5f, 0x03, 0x98, 0x8e, 0xeb, 0x2f, 0xf8, 0xdd, 0x86, 0x23, 0x36, 0xd1, 0xea, 0xc5, 0x32, - 0x21, 0x3e, 0xa9, 0x33, 0x1d, 0x07, 0xe6, 0x1f, 0x55, 0x81, 0x1a, 0x66, 0xfe, 0xaa, 0xd7, 0xbc, - 0xd5, 0xcc, 0x8e, 0x37, 0xd4, 0xf5, 0xea, 0x53, 0x38, 0xa8, 0xc4, 0xdf, 0xff, 0x96, 0x9d, 0xad, - 0x18, 0xee, 0x6a, 0xad, 0x24, 0x69, 0x74, 0x5d, 0x16, 0x77, 0x1f, 0xff, 0x33, 0xef, 0xe8, 0x6b, - 0xb2, 0xdb, 0xb0, 0x88, 0xc3, 0x9a, 0x38, 0xca, 0xb0, 0x2d, 0x50, 0xe0, 0x37, 0xe1, 0x64, 0x1b, - 0xdb, 0x15, 0x6d, 0xad, 0xbf, 0xd4, 0xbf, 0x02, 0x61, 0x69, 0x83, 0xf6, 0x82, 0x79, 0x03, 0x0e, - 0xab, 0xda, 0x5a, 0x97, 0xc4, 0x0b, 0x82, 0xf8, 0x09, 0x4e, 0xdc, 0x2f, 0xec, 0x8d, 0xf7, 0x31, - 0x95, 0x43, 0xc0, 0x37, 0xe0, 0x54, 0x1b, 0xd7, 0x75, 0x63, 0x9d, 0xd0, 0x9a, 0xdb, 0x5f, 0xea, - 0xdf, 0x01, 0x38, 0x9d, 0xb0, 0x85, 0xa0, 0xbf, 0x05, 0xe0, 0x98, 0xcb, 0xd7, 0xbb, 0xd4, 0xe0, - 0x59, 0xa1, 0x41, 0x8a, 0x6b, 0x10, 0x2e, 0xee, 0x4d, 0x87, 0x51, 0xb7, 0x8d, 0x07, 0x7f, 0xe3, - 0x5f, 0x75, 0x05, 0x5a, 0x33, 0x5d, 0x62, 0x5b, 0xaa, 0xed, 0x36, 0xae, 0xe8, 0xba, 0x4d, 0x9c, - 0x40, 0x8f, 0x27, 0x3b, 0x7e, 0xf5, 0x9e, 0x20, 0x23, 0xf9, 0x87, 0x5a, 0xcd, 0xec, 0x49, 0x8e, - 0xa4, 0x1d, 0xc3, 0xe1, 0xcb, 0xa0, 0x00, 0x4f, 0xd8, 0xa4, 0xaa, 0x36, 0x88, 0x5d, 0x54, 0x79, - 0x3f, 0x7e, 0x99, 0xe4, 0xd3, 0xad, 0x66, 0xf6, 0x94, 0x3f, 0xc1, 0x1d, 0x09, 0x58, 0x39, 0x2e, - 0x56, 0x04, 0x02, 0x5c, 0x17, 0xaf, 0x53, 0x2c, 0x3a, 0x21, 0xa5, 0x02, 0x27, 0xb4, 0x50, 0x38, - 0xd8, 0x8d, 0x03, 0xcd, 0xb6, 0x9a, 0xd9, 0x87, 0x05, 0xd0, 0x98, 0x2c, 0xac, 0xa4, 0xb4, 0x68, - 0x6f, 0xfc, 0x89, 0xff, 0x12, 0x2d, 0x13, 0xf2, 0x8c, 0xa9, 0x96, 0xaa, 0x44, 0x17, 0x57, 0xd3, - 0xff, 0xf1, 0x48, 0x7f, 0xeb, 0x1f, 0x52, 0x1c, 0x1a, 0xa1, 0xc2, 0x1d, 0x00, 0x27, 0xca, 0x84, - 0x14, 0x09, 0x8f, 0x17, 0xc5, 0x41, 0xf8, 0x83, 0x35, 0x97, 0x78, 0x55, 0x46, 0x7a, 0xe6, 0xcf, - 0x89, 0x49, 0x13, 0xb2, 0xc5, 0x75, 0xc5, 0x0a, 0x2a, 0x47, 0xb0, 0xe0, 0xbb, 0xfe, 0xd8, 0x47, - 0x7a, 0xfa, 0xa2, 0x3d, 0xd1, 0x7e, 0x59, 0xf8, 0xf1, 0xa0, 0x56, 0x33, 0x7b, 0x9c, 0xef, 0x23, - 0x02, 0x38, 0x78, 0x6d, 0x3a, 0xe7, 0x6e, 0xb0, 0xbb, 0xb9, 0xc3, 0xaf, 0x27, 0x9d, 0x5c, 0x20, - 0xd5, 0x12, 0x1c, 0x0d, 0x71, 0x62, 0x40, 0x86, 0xf3, 0xa7, 0x5a, 0xcd, 0x2c, 0x8a, 0x10, 0xc6, - 0x0a, 0x6c, 0xf3, 0xcc, 0xfd, 0x34, 0x0e, 0x1f, 0x60, 0xbd, 0xd1, 0x8f, 0x00, 0xa6, 0x62, 0x5e, - 0x30, 0x74, 0x29, 0x51, 0xe6, 0x7d, 0x3c, 0x5f, 0xfa, 0xf2, 0x01, 0x2a, 0x39, 0x1f, 0x3c, 0x7f, - 0xf7, 0x97, 0x3f, 0xbe, 0x1c, 0x7c, 0x0c, 0x9d, 0x97, 0x85, 0x4b, 0x0d, 0xdc, 0x69, 0xdc, 0xdb, - 0x89, 0x3e, 0x1f, 0x84, 0x28, 0xda, 0x0e, 0x2d, 0xf5, 0x0a, 0xc0, 0x47, 0x7e, 0xa9, 0xf7, 0x42, - 0x01, 0x7c, 0x0b, 0x30, 0xe4, 0xef, 0xa1, 0xcd, 0x08, 0x72, 0x7f, 0xd0, 0xe4, 0x8d, 0xe0, 0x2a, - 0x96, 0xda, 0x07, 0xbe, 0x29, 0x7b, 0x23, 0xd2, 0x11, 0x14, 0xd3, 0xb3, 0x29, 0x3b, 0x1e, 0x2c, - 0x53, 0x23, 0x1d, 0x51, 0x7f, 0x71, 0x33, 0x4e, 0x12, 0xf4, 0x0f, 0x80, 0xd3, 0x7b, 0xfa, 0x11, - 0x94, 0xef, 0xf9, 0x74, 0x22, 0xee, 0x2c, 0x5d, 0xf8, 0x4f, 0x3d, 0x84, 0x64, 0xaf, 0x30, 0xc5, - 0x5e, 0x44, 0x2f, 0xec, 0xa1, 0x58, 0x9c, 0x4e, 0xbe, 0x3a, 0xb1, 0x13, 0xf1, 0x37, 0x80, 0x0f, - 0x76, 0xf8, 0x13, 0x94, 0xdb, 0x1b, 0x6b, 0x9c, 0x59, 0x4a, 0x2f, 0xf6, 0x54, 0x23, 0xf8, 0xdc, - 0xe1, 0x23, 0xb0, 0x81, 0x1a, 0x87, 0x37, 0x02, 0xae, 0x87, 0xa4, 0x18, 0xb8, 0x27, 0xf4, 0x17, - 0x80, 0x63, 0x61, 0x8f, 0x82, 0x16, 0xba, 0x60, 0xd2, 0x69, 0x97, 0xd2, 0xb9, 0x5e, 0x4a, 0x04, - 0xf7, 0xf7, 0x39, 0xf7, 0x5b, 0xe8, 0x9d, 0xc3, 0xe6, 0xee, 0x1b, 0x28, 0xf4, 0xd1, 0x20, 0x1c, - 0xbf, 0xdf, 0xa3, 0xa0, 0x0b, 0x5d, 0x70, 0x89, 0xda, 0xa6, 0xf4, 0xc5, 0x5e, 0xcb, 0x84, 0x0c, - 0x1f, 0x70, 0x19, 0xde, 0x45, 0xb7, 0x0f, 0x5b, 0x86, 0xb0, 0x87, 0x42, 0x7f, 0x02, 0x98, 0x8a, - 0xb1, 0x19, 0xfb, 0x5d, 0xe9, 0xc9, 0xbe, 0x69, 0xbf, 0x2b, 0x7d, 0x0f, 0x4f, 0x83, 0xdf, 0x66, - 0x92, 0xbc, 0x86, 0x5e, 0xed, 0xf2, 0x67, 0x2e, 0x6c, 0x93, 0x23, 0x6f, 0xdc, 0x67, 0xa9, 0x36, - 0xe5, 0x38, 0xd7, 0x83, 0x7e, 0x00, 0x10, 0x45, 0xcd, 0xc4, 0x7e, 0x6f, 0x40, 0xa2, 0x19, 0xda, - 0xef, 0x0d, 0x48, 0xf6, 0x2d, 0xf8, 0x11, 0xc6, 0x34, 0x83, 0xa6, 0x22, 0x4c, 0x43, 0xcf, 0x30, - 0xda, 0x06, 0xf0, 0x64, 0xa4, 0x09, 0xba, 0xd8, 0xe3, 0xae, 0x3e, 0xda, 0xa5, 0x9e, 0xeb, 0x04, - 0xd8, 0xe7, 0x19, 0xd8, 0xab, 0x28, 0x7f, 0xc0, 0xdb, 0x37, 0x44, 0x29, 0xff, 0xd2, 0xbd, 0x9d, - 0x0c, 0xd8, 0xde, 0xc9, 0x80, 0xdf, 0x77, 0x32, 0xe0, 0x8b, 0xdd, 0xcc, 0xc0, 0xf6, 0x6e, 0x66, - 0xe0, 0xd7, 0xdd, 0xcc, 0xc0, 0x1b, 0x17, 0xa2, 0x56, 0xde, 0x28, 0x69, 0xf3, 0x15, 0x2a, 0xd7, - 0x17, 0xe5, 0x75, 0xaa, 0xd7, 0xaa, 0xc4, 0xe1, 0x9b, 0xe7, 0x2e, 0xcf, 0x7b, 0xfb, 0x33, 0x77, - 0x5f, 0x3a, 0xca, 0xfe, 0xc1, 0xb4, 0xf8, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x50, 0x32, 0x7d, - 0x07, 0x8d, 0x13, 0x00, 0x00, + // 1358 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcd, 0x6f, 0x1b, 0x45, + 0x1c, 0xcd, 0xa4, 0x5f, 0xc9, 0x24, 0xfd, 0xc8, 0x38, 0xb4, 0xa9, 0x49, 0xec, 0x74, 0x4a, 0x21, + 0xa4, 0xca, 0xae, 0xe2, 0xd0, 0xa6, 0x45, 0x42, 0xa2, 0x76, 0x49, 0x09, 0x08, 0x35, 0x6c, 0x2b, + 0x04, 0x08, 0x70, 0xd7, 0xbb, 0x63, 0x67, 0x15, 0x67, 0x67, 0xbb, 0xbb, 0xb6, 0x70, 0xd3, 0x00, + 0xad, 0x88, 0x40, 0x80, 0x00, 0x09, 0x89, 0x03, 0xe2, 0x8a, 0x90, 0x90, 0x38, 0x70, 0xe4, 0x3f, + 0xe8, 0x09, 0x45, 0xe2, 0xc2, 0xc9, 0xa0, 0x84, 0x13, 0x47, 0x9f, 0x38, 0x00, 0x42, 0x3b, 0x33, + 0x6b, 0xaf, 0xb3, 0xbb, 0x89, 0x9d, 0x46, 0x81, 0x53, 0xec, 0xf9, 0x7d, 0xcc, 0x7b, 0x6f, 0x7e, + 0xbb, 0xf3, 0x1c, 0x78, 0xd6, 0x28, 0x68, 0xb2, 0x6a, 0x59, 0x65, 0x43, 0x53, 0x5d, 0x83, 0x9a, + 0x8e, 0x5c, 0x24, 0x44, 0xae, 0x4e, 0xcb, 0xb7, 0x2b, 0xc4, 0xae, 0x49, 0x96, 0x4d, 0x5d, 0x8a, + 0x4e, 0x19, 0x05, 0x4d, 0x0a, 0x26, 0x49, 0x45, 0x42, 0xa4, 0xea, 0x74, 0x72, 0xb8, 0x44, 0x4b, + 0x94, 0xe5, 0xc8, 0xde, 0x27, 0x9e, 0x9e, 0x1c, 0x2d, 0x51, 0x5a, 0x2a, 0x13, 0x59, 0xb5, 0x0c, + 0x59, 0x35, 0x4d, 0xea, 0x8a, 0x22, 0x1e, 0x4d, 0x69, 0xd4, 0x59, 0xa6, 0x8e, 0x5c, 0x50, 0x1d, + 0x6f, 0xa3, 0x02, 0x71, 0xd5, 0x69, 0x59, 0xa3, 0x86, 0x29, 0xe2, 0x93, 0xc1, 0x38, 0x43, 0xd1, + 0xcc, 0xb2, 0xd4, 0x92, 0x61, 0xb2, 0x66, 0x22, 0xf7, 0x4c, 0x1c, 0x7a, 0x0f, 0x1f, 0x4f, 0x39, + 0x17, 0x97, 0x52, 0x22, 0x26, 0x71, 0x0c, 0x27, 0xd8, 0x49, 0xa3, 0x36, 0x91, 0xb5, 0x45, 0xd5, + 0x34, 0x49, 0xd9, 0x4b, 0x11, 0x1f, 0x79, 0x0a, 0xfe, 0x04, 0xc0, 0xf4, 0xcb, 0x1e, 0x9e, 0x79, + 0x53, 0x23, 0xa6, 0x6b, 0x54, 0x8d, 0x3b, 0x44, 0x5f, 0x50, 0xb5, 0x25, 0xe2, 0x3a, 0x0a, 0xb9, + 0x5d, 0x21, 0x8e, 0x8b, 0xe6, 0x20, 0x6c, 0x81, 0x1c, 0x01, 0xe3, 0x60, 0x62, 0x20, 0xf3, 0xb8, + 0xc4, 0x19, 0x49, 0x1e, 0x23, 0x89, 0xeb, 0x2a, 0x18, 0x49, 0x0b, 0x6a, 0x89, 0x88, 0x5a, 0x25, + 0x50, 0x89, 0xce, 0xc0, 0x41, 0x96, 0x98, 0x5f, 0x24, 0x46, 0x69, 0xd1, 0x1d, 0xe9, 0x1d, 0x07, + 0x13, 0x07, 0x95, 0x01, 0xb6, 0xf6, 0x3c, 0x5b, 0xc2, 0x1f, 0x01, 0x38, 0x1e, 0x0f, 0xc7, 0xb1, + 0xa8, 0xe9, 0x10, 0x54, 0x84, 0xc3, 0x46, 0x20, 0x9c, 0xb7, 0x78, 0x7c, 0x04, 0x8c, 0x1f, 0x98, + 0x18, 0xc8, 0x4c, 0x49, 0x31, 0x07, 0x2b, 0xcd, 0xeb, 0x5e, 0x4d, 0xd1, 0xf0, 0x3b, 0xce, 0x11, + 0xe2, 0x64, 0x0f, 0x3e, 0xa8, 0xa7, 0x7b, 0x94, 0x84, 0x11, 0xde, 0x0f, 0xaf, 0x01, 0x98, 0x8a, + 0x01, 0xe3, 0x4b, 0xf3, 0x2c, 0xec, 0xe7, 0xbb, 0xe7, 0x0d, 0x5d, 0x28, 0x33, 0xc6, 0xf6, 0xf7, + 0x54, 0x97, 0x7c, 0xa9, 0xab, 0x9e, 0x26, 0x5e, 0xd6, 0xbc, 0x2e, 0xf6, 0xeb, 0xb3, 0xc4, 0xf7, + 0x4e, 0x44, 0xf9, 0x20, 0xfe, 0x8c, 0x9a, 0x9a, 0xe8, 0x30, 0x11, 0xa1, 0x89, 0x80, 0xb4, 0x2b, + 0x49, 0x50, 0x58, 0x12, 0xfc, 0x13, 0x80, 0x4f, 0xc6, 0x1d, 0xcf, 0x1c, 0xb5, 0x73, 0x9c, 0xef, + 0x5e, 0xcf, 0xcd, 0x29, 0x78, 0xc4, 0xa2, 0x36, 0x93, 0xd8, 0x53, 0xa7, 0x5f, 0x39, 0xec, 0x7d, + 0x9d, 0xd7, 0xd1, 0x18, 0x84, 0x42, 0x62, 0x2f, 0x76, 0x80, 0xc5, 0xfa, 0xc5, 0x4a, 0x84, 0xb4, + 0x07, 0xc3, 0xd2, 0x7e, 0x0a, 0xe0, 0x64, 0x27, 0x84, 0x84, 0xca, 0xb7, 0xf6, 0x70, 0xf2, 0xa2, + 0x67, 0xee, 0x4d, 0x78, 0x9a, 0xe1, 0xb9, 0x49, 0x5d, 0xb5, 0xac, 0x10, 0xad, 0xca, 0x52, 0xf7, + 0x6a, 0xda, 0xf0, 0x57, 0x00, 0x26, 0xa3, 0xfa, 0x0b, 0x7e, 0x77, 0x61, 0xbf, 0x4d, 0xb4, 0x6a, + 0xbe, 0x48, 0x88, 0x4f, 0xea, 0x74, 0xdb, 0x81, 0xf9, 0x47, 0x95, 0xa3, 0x86, 0x99, 0xbd, 0xea, + 0x35, 0x6f, 0xd4, 0xd3, 0x27, 0x6a, 0xea, 0x72, 0xf9, 0x69, 0xdc, 0xac, 0xc4, 0xdf, 0xfd, 0x9a, + 0x9e, 0x28, 0x19, 0xee, 0x62, 0xa5, 0x20, 0x69, 0x74, 0x59, 0x16, 0xef, 0x3e, 0xfe, 0x67, 0xca, + 0xd1, 0x97, 0x64, 0xb7, 0x66, 0x11, 0x87, 0x35, 0x71, 0x94, 0x3e, 0x5b, 0xa0, 0xc0, 0x6f, 0xc0, + 0x91, 0x16, 0xb6, 0x2b, 0xda, 0xd2, 0xde, 0x52, 0xff, 0x12, 0x04, 0xa5, 0x6d, 0xb6, 0x17, 0xcc, + 0x6b, 0xb0, 0x4f, 0xd5, 0x96, 0x3a, 0x24, 0x9e, 0x13, 0xc4, 0x8f, 0x73, 0xe2, 0x7e, 0x61, 0x77, + 0xbc, 0x8f, 0xa8, 0x1c, 0x02, 0xbe, 0x05, 0x47, 0x5b, 0xb8, 0x6e, 0x1a, 0xcb, 0x84, 0x56, 0xdc, + 0xbd, 0xa5, 0xfe, 0x2d, 0x80, 0x63, 0x31, 0x5b, 0x08, 0xfa, 0x6b, 0x00, 0x0e, 0xba, 0x7c, 0xbd, + 0x43, 0x0d, 0xae, 0x09, 0x0d, 0x12, 0x5c, 0x83, 0x60, 0x71, 0x77, 0x3a, 0x0c, 0xb8, 0x2d, 0x3c, + 0xde, 0xf3, 0x38, 0xc4, 0x90, 0x2e, 0xa8, 0x35, 0xe2, 0xbf, 0x0c, 0xd0, 0x53, 0x6d, 0xcf, 0xb9, + 0x27, 0x41, 0x7f, 0xf6, 0x91, 0x46, 0x3d, 0x3d, 0xc4, 0xf7, 0x6e, 0xc5, 0x70, 0xf0, 0xf1, 0xcf, + 0xc1, 0xe3, 0x36, 0x29, 0xab, 0x35, 0x62, 0xe7, 0x55, 0x5d, 0xb7, 0x89, 0xe3, 0xf0, 0xd7, 0x47, + 0x36, 0xd9, 0xa8, 0xa7, 0x4f, 0xfa, 0x33, 0xdb, 0x96, 0x80, 0x95, 0x63, 0x62, 0xe5, 0x8a, 0x58, + 0xb8, 0x01, 0x51, 0x10, 0x8f, 0x90, 0xeb, 0x19, 0x78, 0xd4, 0xf2, 0x16, 0x9a, 0x8d, 0x39, 0xa6, + 0x91, 0x46, 0x3d, 0x3d, 0xcc, 0x1b, 0xb7, 0x85, 0xb1, 0x32, 0xc8, 0xbe, 0xfb, 0x4d, 0xbf, 0xf6, + 0x5f, 0xe8, 0x39, 0x5a, 0x31, 0x5d, 0x62, 0x5b, 0xaa, 0xed, 0xd6, 0x44, 0xf0, 0x7f, 0xc0, 0xb9, + 0x2a, 0xee, 0xe0, 0x48, 0x74, 0x42, 0x01, 0x05, 0x0e, 0x6b, 0x81, 0xf0, 0x16, 0x21, 0xd2, 0x8d, + 0x7a, 0xfa, 0x51, 0x01, 0x34, 0x22, 0x0b, 0x2b, 0x09, 0x2d, 0xdc, 0x1b, 0x7f, 0xec, 0xdf, 0xb7, + 0x73, 0x84, 0x3c, 0x67, 0xaa, 0x85, 0x32, 0xd1, 0xc5, 0x0b, 0xf8, 0xbf, 0xb0, 0x22, 0xdf, 0xf8, + 0x87, 0x14, 0x85, 0x46, 0xa8, 0x70, 0x0f, 0xc0, 0xe1, 0x22, 0x21, 0x79, 0xc2, 0xe3, 0x79, 0x71, + 0x10, 0xfe, 0xe3, 0x33, 0x19, 0x7b, 0x21, 0x84, 0x7a, 0x66, 0xcf, 0x8a, 0xe7, 0x49, 0xc8, 0x16, + 0xd5, 0x15, 0x2b, 0xa8, 0x18, 0xc2, 0x82, 0xef, 0xfb, 0x0f, 0x77, 0xa8, 0xa7, 0x2f, 0xda, 0xf9, + 0xd6, 0xfd, 0xc9, 0x8f, 0x07, 0x35, 0xea, 0xe9, 0x63, 0x62, 0x4e, 0x79, 0x00, 0x37, 0xef, 0xd4, + 0xf6, 0xb9, 0xeb, 0xed, 0x6c, 0xee, 0xf0, 0x6b, 0x71, 0x27, 0xd7, 0x94, 0x6a, 0x16, 0x0e, 0x04, + 0x38, 0x31, 0x20, 0x7d, 0xd9, 0x93, 0x8d, 0x7a, 0x1a, 0x85, 0x08, 0x63, 0x05, 0xb6, 0x78, 0x66, + 0xfe, 0x19, 0x82, 0x87, 0x58, 0x6f, 0xf4, 0x23, 0x80, 0x89, 0x88, 0x7b, 0x1a, 0x5d, 0x8a, 0x95, + 0x79, 0x07, 0x67, 0x9b, 0xbc, 0xbc, 0x8b, 0x4a, 0xce, 0x07, 0x4f, 0xdd, 0xff, 0xf9, 0xf7, 0x2f, + 0x7a, 0x9f, 0x40, 0xe7, 0x64, 0xe1, 0xc5, 0x9b, 0x1e, 0x3c, 0xca, 0x21, 0xa0, 0xcf, 0x7a, 0x21, + 0x0a, 0xb7, 0x43, 0xb3, 0xdd, 0x02, 0xf0, 0x91, 0x5f, 0xea, 0xbe, 0x50, 0x00, 0x5f, 0x03, 0x0c, + 0xf9, 0xbb, 0x68, 0x35, 0x84, 0xdc, 0x1f, 0x34, 0x79, 0xa5, 0x79, 0xe1, 0x48, 0xad, 0x03, 0x5f, + 0x95, 0xbd, 0x11, 0x69, 0x0b, 0x8a, 0xe9, 0x59, 0x95, 0x1d, 0x0f, 0x96, 0xa9, 0x91, 0xb6, 0xa8, + 0xbf, 0xb8, 0x1a, 0x25, 0x09, 0xfa, 0x1b, 0xc0, 0xb1, 0x6d, 0x5d, 0x17, 0xca, 0x76, 0x7d, 0x3a, + 0x21, 0x0f, 0x9a, 0xcc, 0x3d, 0x54, 0x0f, 0x21, 0xd9, 0x0d, 0xa6, 0xd8, 0x4b, 0xe8, 0xc5, 0x6d, + 0x14, 0x8b, 0xd2, 0xc9, 0x57, 0x27, 0x72, 0x22, 0xfe, 0x02, 0xf0, 0x68, 0x9b, 0x0b, 0x43, 0x99, + 0xed, 0xb1, 0x46, 0x59, 0xc2, 0xe4, 0x4c, 0x57, 0x35, 0x82, 0xcf, 0x3d, 0x3e, 0x02, 0x2b, 0xa8, + 0xb6, 0x7f, 0x23, 0xe0, 0x7a, 0x48, 0xf2, 0x4d, 0x8f, 0x88, 0xfe, 0x04, 0x70, 0x30, 0xe8, 0xc4, + 0xd0, 0x74, 0x07, 0x4c, 0xda, 0x4d, 0x61, 0x32, 0xd3, 0x4d, 0x89, 0xe0, 0xfe, 0x1e, 0xe7, 0x7e, + 0x07, 0xbd, 0xbd, 0xdf, 0xdc, 0x7d, 0x9b, 0x88, 0x3e, 0xec, 0x85, 0x27, 0xb6, 0x3a, 0x31, 0x74, + 0xa1, 0x03, 0x2e, 0x61, 0x73, 0x98, 0xbc, 0xd8, 0x6d, 0x99, 0x90, 0xe1, 0x7d, 0x2e, 0xc3, 0x3b, + 0xe8, 0xee, 0x7e, 0xcb, 0x10, 0x74, 0x8a, 0xe8, 0x07, 0x00, 0x0f, 0x31, 0x6b, 0x85, 0x26, 0xb7, + 0x27, 0x12, 0xf4, 0x83, 0xc9, 0xf3, 0x1d, 0xe5, 0x0a, 0xa6, 0xd7, 0x19, 0xd1, 0x79, 0x74, 0xad, + 0xc3, 0x87, 0x57, 0x98, 0x21, 0x47, 0x5e, 0xd9, 0x62, 0x94, 0x56, 0x65, 0x66, 0xe2, 0xd0, 0x1f, + 0x00, 0x26, 0x22, 0xac, 0xd1, 0x4e, 0xd7, 0x50, 0xbc, 0xd7, 0xdb, 0xe9, 0x1a, 0xda, 0xc6, 0x87, + 0xe1, 0xb7, 0x18, 0xbb, 0x57, 0xd1, 0x2b, 0x0f, 0xcf, 0x2e, 0xca, 0xa9, 0xa1, 0xef, 0x01, 0x44, + 0x61, 0x03, 0xb4, 0xd3, 0xbd, 0x15, 0x6b, 0xe0, 0x76, 0xba, 0xb7, 0xe2, 0xbd, 0x16, 0x7e, 0x8c, + 0x31, 0x4d, 0xa1, 0xd1, 0x10, 0xd3, 0x80, 0x75, 0x40, 0xeb, 0x00, 0x0e, 0x85, 0x9a, 0xa0, 0x8b, + 0x5d, 0xee, 0xea, 0xa3, 0x9d, 0xed, 0xba, 0x4e, 0x80, 0x7d, 0x81, 0x81, 0xbd, 0x8a, 0xb2, 0xbb, + 0xbc, 0x31, 0x02, 0x94, 0xb2, 0xd7, 0x1f, 0x6c, 0xa4, 0xc0, 0xfa, 0x46, 0x0a, 0xfc, 0xb6, 0x91, + 0x02, 0x9f, 0x6f, 0xa6, 0x7a, 0xd6, 0x37, 0x53, 0x3d, 0xbf, 0x6c, 0xa6, 0x7a, 0x5e, 0xbf, 0x10, + 0xfe, 0x91, 0x65, 0x14, 0xb4, 0xa9, 0x12, 0x95, 0xab, 0x33, 0xf2, 0x32, 0xd5, 0x2b, 0x65, 0xe2, + 0xf0, 0xcd, 0x33, 0x97, 0xa7, 0xbc, 0xfd, 0xd9, 0xef, 0xae, 0xc2, 0x61, 0xf6, 0xaf, 0xbf, 0x99, + 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x64, 0x8c, 0x96, 0x8a, 0x27, 0x15, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1074,6 +1181,8 @@ type QueryClient interface { TotalAckFees(ctx context.Context, in *QueryTotalAckFeesRequest, opts ...grpc.CallOption) (*QueryTotalAckFeesResponse, error) // TotalTimeoutFees returns the total timeout fees for a packet given its identifier TotalTimeoutFees(ctx context.Context, in *QueryTotalTimeoutFeesRequest, opts ...grpc.CallOption) (*QueryTotalTimeoutFeesResponse, error) + // Payee returns the registered payee address for a specific channel given the relayer address + Payee(ctx context.Context, in *QueryPayeeRequest, opts ...grpc.CallOption) (*QueryPayeeResponse, error) // CounterpartyAddress returns the registered counterparty address for forward relaying CounterpartyAddress(ctx context.Context, in *QueryCounterpartyAddressRequest, opts ...grpc.CallOption) (*QueryCounterpartyAddressResponse, error) // FeeEnabledChannels returns a list of all fee enabled channels @@ -1144,6 +1253,15 @@ func (c *queryClient) TotalTimeoutFees(ctx context.Context, in *QueryTotalTimeou return out, nil } +func (c *queryClient) Payee(ctx context.Context, in *QueryPayeeRequest, opts ...grpc.CallOption) (*QueryPayeeResponse, error) { + out := new(QueryPayeeResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/Payee", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) CounterpartyAddress(ctx context.Context, in *QueryCounterpartyAddressRequest, opts ...grpc.CallOption) (*QueryCounterpartyAddressResponse, error) { out := new(QueryCounterpartyAddressResponse) err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/CounterpartyAddress", in, out, opts...) @@ -1185,6 +1303,8 @@ type QueryServer interface { TotalAckFees(context.Context, *QueryTotalAckFeesRequest) (*QueryTotalAckFeesResponse, error) // TotalTimeoutFees returns the total timeout fees for a packet given its identifier TotalTimeoutFees(context.Context, *QueryTotalTimeoutFeesRequest) (*QueryTotalTimeoutFeesResponse, error) + // Payee returns the registered payee address for a specific channel given the relayer address + Payee(context.Context, *QueryPayeeRequest) (*QueryPayeeResponse, error) // CounterpartyAddress returns the registered counterparty address for forward relaying CounterpartyAddress(context.Context, *QueryCounterpartyAddressRequest) (*QueryCounterpartyAddressResponse, error) // FeeEnabledChannels returns a list of all fee enabled channels @@ -1215,6 +1335,9 @@ func (*UnimplementedQueryServer) TotalAckFees(ctx context.Context, req *QueryTot func (*UnimplementedQueryServer) TotalTimeoutFees(ctx context.Context, req *QueryTotalTimeoutFeesRequest) (*QueryTotalTimeoutFeesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method TotalTimeoutFees not implemented") } +func (*UnimplementedQueryServer) Payee(ctx context.Context, req *QueryPayeeRequest) (*QueryPayeeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Payee not implemented") +} func (*UnimplementedQueryServer) CounterpartyAddress(ctx context.Context, req *QueryCounterpartyAddressRequest) (*QueryCounterpartyAddressResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CounterpartyAddress not implemented") } @@ -1337,6 +1460,24 @@ func _Query_TotalTimeoutFees_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Query_Payee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPayeeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Payee(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.applications.fee.v1.Query/Payee", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Payee(ctx, req.(*QueryPayeeRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Query_CounterpartyAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryCounterpartyAddressRequest) if err := dec(in); err != nil { @@ -1419,6 +1560,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "TotalTimeoutFees", Handler: _Query_TotalTimeoutFees_Handler, }, + { + MethodName: "Payee", + Handler: _Query_Payee_Handler, + }, { MethodName: "CounterpartyAddress", Handler: _Query_CounterpartyAddress_Handler, @@ -1885,6 +2030,73 @@ func (m *QueryTotalTimeoutFeesResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *QueryPayeeRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryPayeeRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPayeeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RelayerAddress) > 0 { + i -= len(m.RelayerAddress) + copy(dAtA[i:], m.RelayerAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.RelayerAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryPayeeResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryPayeeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPayeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PayeeAddress) > 0 { + i -= len(m.PayeeAddress) + copy(dAtA[i:], m.PayeeAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.PayeeAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *QueryCounterpartyAddressRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -2283,6 +2495,36 @@ func (m *QueryTotalTimeoutFeesResponse) Size() (n int) { return n } +func (m *QueryPayeeRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.RelayerAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPayeeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PayeeAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + func (m *QueryCounterpartyAddressRequest) Size() (n int) { if m == nil { return 0 @@ -3507,6 +3749,202 @@ func (m *QueryTotalTimeoutFeesResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryPayeeRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryPayeeRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPayeeRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RelayerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RelayerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryPayeeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryPayeeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPayeeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PayeeAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PayeeAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *QueryCounterpartyAddressRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/29-fee/types/query.pb.gw.go b/modules/apps/29-fee/types/query.pb.gw.go index 712c7f32727..309fab4da17 100644 --- a/modules/apps/29-fee/types/query.pb.gw.go +++ b/modules/apps/29-fee/types/query.pb.gw.go @@ -625,6 +625,82 @@ func local_request_Query_TotalTimeoutFees_0(ctx context.Context, marshaler runti } +func request_Query_Payee_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPayeeRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + val, ok = pathParams["relayer_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + } + + protoReq.RelayerAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + } + + msg, err := client.Payee(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Payee_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPayeeRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["channel_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "channel_id") + } + + protoReq.ChannelId, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) + } + + val, ok = pathParams["relayer_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + } + + protoReq.RelayerAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + } + + msg, err := server.Payee(ctx, &protoReq) + return msg, metadata, err + +} + func request_Query_CounterpartyAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryCounterpartyAddressRequest var metadata runtime.ServerMetadata @@ -939,6 +1015,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_Payee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Payee_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Payee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_CounterpartyAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1160,6 +1256,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_Payee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Payee_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Payee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_CounterpartyAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1236,6 +1352,8 @@ var ( pattern_Query_TotalTimeoutFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "apps", "fee", "v1", "channels", "packet_id.channel_id", "ports", "packet_id.port_id", "sequences", "packet_id.sequence", "total_timeout_fees"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Payee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "fee", "v1", "channels", "channel_id", "relayers", "relayer_address", "payee"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_CounterpartyAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "fee", "v1", "channels", "channel_id", "relayers", "relayer_address", "counterparty_address"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_FeeEnabledChannels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "apps", "fee", "v1", "fee_enabled"}, "", runtime.AssumeColonVerbOpt(true))) @@ -1256,6 +1374,8 @@ var ( forward_Query_TotalTimeoutFees_0 = runtime.ForwardResponseMessage + forward_Query_Payee_0 = runtime.ForwardResponseMessage + forward_Query_CounterpartyAddress_0 = runtime.ForwardResponseMessage forward_Query_FeeEnabledChannels_0 = runtime.ForwardResponseMessage diff --git a/proto/ibc/applications/fee/v1/query.proto b/proto/ibc/applications/fee/v1/query.proto index 5f648107323..e08eee99816 100644 --- a/proto/ibc/applications/fee/v1/query.proto +++ b/proto/ibc/applications/fee/v1/query.proto @@ -50,6 +50,11 @@ service Query { "sequences/{packet_id.sequence}/total_timeout_fees"; } + // Payee returns the registered payee address for a specific channel given the relayer address + rpc Payee(QueryPayeeRequest) returns (QueryPayeeResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/payee"; + } + // CounterpartyAddress returns the registered counterparty address for forward relaying rpc CounterpartyAddress(QueryCounterpartyAddressRequest) returns (QueryCounterpartyAddressResponse) { option (google.api.http).get = @@ -160,6 +165,20 @@ message QueryTotalTimeoutFeesResponse { ]; } +// QueryPayeeRequest defines the request type for the Payee rpc +message QueryPayeeRequest { + // unique channel identifier + string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + // the relayer address to which the distribution address is registered + string relayer_address = 2 [(gogoproto.moretags) = "yaml:\"relayer_address\""]; +} + +// QueryPayeeResponse defines the response type for the Payee rpc +message QueryPayeeResponse { + // the payee address to which packet fees are paid out + string payee_address = 1 [(gogoproto.moretags) = "yaml:\"payee_address\""]; +} + // QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc message QueryCounterpartyAddressRequest { // unique channel identifier From 08d91ada9c3a1cb3394c047b2364481404ec6742 Mon Sep 17 00:00:00 2001 From: Charly Date: Thu, 9 Jun 2022 16:32:48 +0200 Subject: [PATCH 150/275] feat: added check for wildcard * to allow all message types (#1512) * added check for wildcard * to allow all message types * update docs * nit --- CHANGELOG.md | 1 + docs/apps/interchain-accounts/parameters.md | 8 ++++ .../host/keeper/relay_test.go | 39 +++++++++++++++++++ .../27-interchain-accounts/host/types/keys.go | 5 +++ 4 files changed, 53 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb092156aad..58b87570e8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (apps/29-fee) [\#1225](https://github.com/cosmos/ibc-go/pull/1225) Adding Query/FeeEnabledChannel and Query/FeeEnabledChannels with CLIs to ICS29 fee middleware. * (modules/apps/29-fee) [\#1230](https://github.com/cosmos/ibc-go/pull/1230) Adding CLI command for getting incentivized packets for a specific channel-id. * (modules/apps/transfer) [\#1416](https://github.com/cosmos/ibc-go/pull/1416) Adding gRPC endpoint for getting an escrow account for a given port-id and channel-id. +* (modules/apps/27-interchain-accounts) [\#1512](https://github.com/cosmos/ibc-go/pull/1512) Allowing ICA modules to handle all message types with "*". ### Bug Fixes diff --git a/docs/apps/interchain-accounts/parameters.md b/docs/apps/interchain-accounts/parameters.md index f4ddcbc1160..8f985b9293e 100644 --- a/docs/apps/interchain-accounts/parameters.md +++ b/docs/apps/interchain-accounts/parameters.md @@ -47,4 +47,12 @@ For example, a Cosmos SDK based chain that elects to provide hosted Interchain A "host_enabled": true, "allow_messages": ["/cosmos.staking.v1beta1.MsgDelegate", "/cosmos.gov.v1beta1.MsgVote"] } +``` +There is also a special wildcard `"*"` message type which allows any type of message to be executed by the interchain account. This must be the only message in the `allow_messages` array. + +``` +"params": { + "host_enabled": true, + "allow_messages": ["*"] +} ``` \ No newline at end of file diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index fda31c34ef0..d92be7227aa 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -29,6 +29,45 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { malleate func() expPass bool }{ + { + "interchain account successfully executes an arbitrary message type using the * (allow all message types) param", + func() { + interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) + suite.Require().True(found) + + // Populate the gov keeper in advance with an active proposal + testProposal := &govtypes.TextProposal{ + Title: "IBC Gov Proposal", + Description: "tokens for all!", + } + + proposal, err := govtypes.NewProposal(testProposal, govtypes.DefaultStartingProposalID, time.Now(), time.Now().Add(time.Hour)) + suite.Require().NoError(err) + + suite.chainB.GetSimApp().GovKeeper.SetProposal(suite.chainB.GetContext(), proposal) + suite.chainB.GetSimApp().GovKeeper.ActivateVotingPeriod(suite.chainB.GetContext(), proposal) + + msg := &govtypes.MsgVote{ + ProposalId: govtypes.DefaultStartingProposalID, + Voter: interchainAccountAddr, + Option: govtypes.OptionYes, + } + + data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []sdk.Msg{msg}) + suite.Require().NoError(err) + + icaPacketData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + + packetData = icaPacketData.GetBytes() + + params := types.NewParams(true, []string{"*"}) + suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), params) + }, + true, + }, { "interchain account successfully executes banktypes.MsgSend", func() { diff --git a/modules/apps/27-interchain-accounts/host/types/keys.go b/modules/apps/27-interchain-accounts/host/types/keys.go index 74c93cdb605..7f1a04facb5 100644 --- a/modules/apps/27-interchain-accounts/host/types/keys.go +++ b/modules/apps/27-interchain-accounts/host/types/keys.go @@ -14,6 +14,11 @@ const ( // ContainsMsgType returns true if the sdk.Msg TypeURL is present in allowMsgs, otherwise false func ContainsMsgType(allowMsgs []string, msg sdk.Msg) bool { + // check that wildcard * option for allowing all message types is the only string in the array, if so, return true + if len(allowMsgs) == 1 && allowMsgs[0] == "*" { + return true + } + for _, v := range allowMsgs { if v == sdk.MsgTypeURL(msg) { return true From 5e5e2cd2b904738266b06b3fc63a744fe6c7eeab Mon Sep 17 00:00:00 2001 From: Charly Date: Thu, 9 Jun 2022 17:11:40 +0200 Subject: [PATCH 151/275] fix: deprecate AllowUpdateAfter...check (#1511) * fix: deprecate AllowUpdateAfter...check * update IsMatchingClientState * rm unnecessary fields in testing --- CHANGELOG.md | 2 + .../adr-026-ibc-client-recovery-mechanisms.md | 13 +- docs/ibc/proposals.md | 3 +- docs/ibc/proto-docs.md | 4 +- .../07-tendermint/types/proposal_handle.go | 32 ++-- .../types/proposal_handle_test.go | 126 ++------------- .../07-tendermint/types/tendermint.pb.go | 146 +++++++++--------- .../tendermint/v1/tendermint.proto | 11 +- 8 files changed, 110 insertions(+), 227 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b87570e8f..31ca5c1539f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### State Machine Breaking ### Improvements + * (cleanup) [\#1335](https://github.com/cosmos/ibc-go/pull/1335/) `gofumpt -w -l .` to standardize the code layout more strictly than `go fmt ./...` * (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. * (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. @@ -62,6 +63,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees * (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. * (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. +* (modules/light-clients/07-tendermint) [\#1118](https://github.com/cosmos/ibc-go/pull/1118) Deprecating `AllowUpdateAfterExpiry and AllowUpdateAfterMisbehaviour`. See ADR-026 for context. ### Features diff --git a/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md b/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md index c40e3b08cd5..27bcb33e545 100644 --- a/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md +++ b/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md @@ -6,6 +6,7 @@ - 2020/08/06: Revisions per review & to reference version - 2021/01/15: Revision to support substitute clients for unfreezing - 2021/05/20: Revision to simplify consensus state copying, remove initial height +- 2022/04/08: Revision to deprecate AllowUpdateAfterExpiry and AllowUpdateAfterMisbehaviour ## Status @@ -35,21 +36,20 @@ Two-thirds of the validator set (the quorum for governance, module participation We elect not to deal with chains which have actually halted, which is necessarily Byzantine behaviour and in which case token recovery is not likely possible anyways (in-flight packets cannot be timed-out, but the relative impact of that is minor). 1. Require Tendermint light clients (ICS 07) to be created with the following additional flags - 1. `allow_governance_override_after_expiry` (boolean, default false) + 1. `allow_update_after_expiry` (boolean, default true). Note that this flag has been deprecated, it remains to signal intent but checks against this value will not be enforced. 1. Require Tendermint light clients (ICS 07) to expose the following additional internal query functions 1. `Expired() boolean`, which returns whether or not the client has passed the trusting period since the last update (in which case no headers can be validated) 1. Require Tendermint light clients (ICS 07) & solo machine clients (ICS 06) to be created with the following additional flags - 1. `allow_governance_override_after_misbehaviour` (boolean, default false) + 1. `allow_update_after_misbehaviour` (boolean, default true). Note that this flag has been deprecated, it remains to signal intent but checks against this value will not be enforced. 1. Require Tendermint light clients (ICS 07) to expose the following additional state mutation functions 1. `Unfreeze()`, which unfreezes a light client after misbehaviour and clears any frozen height previously set 1. Add a new governance proposal type, `ClientUpdateProposal`, in the `x/ibc` module 1. Extend the base `Proposal` with two client identifiers (`string`). 1. The first client identifier is the proposed client to be updated. This client must be either frozen or expired. 1. The second client is a substitute client. It carries all the state for the client which may be updated. It must have identitical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain-id). It should be continually updated during the voting period. - 1. If this governance proposal passes, the client on trial will be updated to the latest state of the substitute, if and only if: - 1. `allow_governance_override_after_expiry` is true and the client has expired (`Expired()` returns true) - 1. `allow_governance_override_after_misbehaviour` is true and the client has been frozen (`Frozen()` returns true) - 1. In this case, additionally, the client is unfrozen by calling `Unfreeze()` + 1. If this governance proposal passes, the client on trial will be updated to the latest state of the substitute. + + Previously, AllowUpdateAfterExpiry and AllowUpdateAfterMisbehaviour were used to signal the recovery options for an expired or frozen client, and governance proposals were not allowed to overwrite the client if these parameters were set to false. However, this has now been deprecated because a code migration can overwrite the client and consensus states regardless of the value of these parameters. If governance would vote to overwrite a client or consensus state, it is likely that governance would also willing to perform a code migration to do the same. Note that clients frozen due to misbehaviour must wait for the evidence to expire to avoid becoming refrozen. @@ -62,7 +62,6 @@ This ADR does not address planned upgrades, which are handled separately as per - Establishes a mechanism for client recovery in the case of expiry - Establishes a mechanism for client recovery in the case of misbehaviour -- Clients can elect to disallow this recovery mechanism if they do not wish to allow for it - Constructing an ClientUpdate Proposal is as difficult as creating a new client ### Negative diff --git a/docs/ibc/proposals.md b/docs/ibc/proposals.md index c2cb34860b2..f6bf351a705 100644 --- a/docs/ibc/proposals.md +++ b/docs/ibc/proposals.md @@ -46,7 +46,6 @@ See also the relevant documentation: [ADR-026, IBC client recovery mechanisms](. ### Preconditions - The chain is updated with ibc-go >= v1.1.0. -- Recovery parameters are set to `true` for the Tendermint light client (this determines if a governance proposal can be used). If the recovery parameters are set to `false`, recovery will require custom migration code. - The client identifier of an active client for the same counterparty chain. - The governance deposit. @@ -67,7 +66,7 @@ Check if the client is attached to the expected `chain-id`. For example, for an } ``` -The client is attached to the expected Akash `chain-id` and the recovery parameters (`allow_update_after_expiry` and `allow_update_after_misbehaviour`) are set to `true`. +The client is attached to the expected Akash `chain-id`. Note that although the parameters (`allow_update_after_expiry` and `allow_update_after_misbehaviour`) exist to signal intent, these parameters have been deprecated and will not enforce any checks on the revival of client. See ADR-026 for more context on this deprecation. ### Step 2 diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 396b5d37f9d..791b5ec4972 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -5019,8 +5019,8 @@ and a possible frozen height. | `latest_height` | [ibc.core.client.v1.Height](#ibc.core.client.v1.Height) | | Latest height the client was updated to | | `proof_specs` | [ics23.ProofSpec](#ics23.ProofSpec) | repeated | Proof specifications used in verifying counterparty state | | `upgrade_path` | [string](#string) | repeated | Path at which next upgraded client will be committed. Each element corresponds to the key for a single CommitmentProof in the chained proof. NOTE: ClientState must stored under `{upgradePath}/{upgradeHeight}/clientState` ConsensusState must be stored under `{upgradepath}/{upgradeHeight}/consensusState` For SDK chains using the default upgrade module, upgrade_path should be []string{"upgrade", "upgradedIBCState"}` | -| `allow_update_after_expiry` | [bool](#bool) | | This flag, when set to true, will allow governance to recover a client which has expired | -| `allow_update_after_misbehaviour` | [bool](#bool) | | This flag, when set to true, will allow governance to unfreeze a client whose chain has experienced a misbehaviour event | +| `allow_update_after_expiry` | [bool](#bool) | | **Deprecated.** allow_update_after_expiry is deprecated | +| `allow_update_after_misbehaviour` | [bool](#bool) | | **Deprecated.** allow_update_after_misbehaviour is deprecated | diff --git a/modules/light-clients/07-tendermint/types/proposal_handle.go b/modules/light-clients/07-tendermint/types/proposal_handle.go index bfa7f242e92..88951205c22 100644 --- a/modules/light-clients/07-tendermint/types/proposal_handle.go +++ b/modules/light-clients/07-tendermint/types/proposal_handle.go @@ -12,18 +12,17 @@ import ( ) // CheckSubstituteAndUpdateState will try to update the client with the state of the -// substitute if and only if the proposal passes and one of the following conditions are -// satisfied: -// 1) AllowUpdateAfterMisbehaviour and Status() == Frozen -// 2) AllowUpdateAfterExpiry=true and Status() == Expired +// substitute. +// +// AllowUpdateAfterMisbehaviour and AllowUpdateAfterExpiry have been deprecated. +// Please see ADR 026 for more information. // // The following must always be true: // - The substitute client is the same type as the subject client // - The subject and substitute client states match in all parameters (expect frozen height, latest height, and chain-id) // // In case 1) before updating the client, the client will be unfrozen by resetting -// the FrozenHeight to the zero Height. If a client is frozen and AllowUpdateAfterMisbehaviour -// is set to true, the client will be unexpired even if AllowUpdateAfterExpiry is set to false. +// the FrozenHeight to the zero Height. func (cs ClientState) CheckSubstituteAndUpdateState( ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore, substituteClientStore sdk.KVStore, substituteClient exported.ClientState, @@ -39,23 +38,9 @@ func (cs ClientState) CheckSubstituteAndUpdateState( return nil, sdkerrors.Wrap(clienttypes.ErrInvalidSubstitute, "subject client state does not match substitute client state") } - switch cs.Status(ctx, subjectClientStore, cdc) { - - case exported.Frozen: - if !cs.AllowUpdateAfterMisbehaviour { - return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client is not allowed to be unfrozen") - } - + if cs.Status(ctx, subjectClientStore, cdc) == exported.Frozen { // unfreeze the client cs.FrozenHeight = clienttypes.ZeroHeight() - - case exported.Expired: - if !cs.AllowUpdateAfterExpiry { - return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client is not allowed to be unexpired") - } - - default: - return nil, sdkerrors.Wrap(clienttypes.ErrUpdateClientFailed, "client cannot be updated with proposal") } // copy consensus states and processed time from substitute to subject @@ -101,6 +86,11 @@ func IsMatchingClientState(subject, substitute ClientState) bool { substitute.FrozenHeight = clienttypes.ZeroHeight() subject.ChainId = "" substitute.ChainId = "" + // sets both sets of flags to true as these flags have been DEPRECATED, see ADR-026 for more information + subject.AllowUpdateAfterExpiry = true + substitute.AllowUpdateAfterExpiry = true + subject.AllowUpdateAfterMisbehaviour = true + substitute.AllowUpdateAfterMisbehaviour = true return reflect.DeepEqual(subject, substitute) } diff --git a/modules/light-clients/07-tendermint/types/proposal_handle_test.go b/modules/light-clients/07-tendermint/types/proposal_handle_test.go index fa8bc7798de..0c3e9f054ef 100644 --- a/modules/light-clients/07-tendermint/types/proposal_handle_test.go +++ b/modules/light-clients/07-tendermint/types/proposal_handle_test.go @@ -28,10 +28,12 @@ func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { { "non-matching substitute", func() { suite.coordinator.SetupClients(substitutePath) - substituteClientState = suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*types.ClientState) - tmClientState, ok := substituteClientState.(*types.ClientState) + substituteClientState, ok := suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*types.ClientState) suite.Require().True(ok) + // change trusting period so that test should fail + substituteClientState.TrustingPeriod = time.Hour * 24 * 7 + tmClientState := substituteClientState tmClientState.ChainId = tmClientState.ChainId + "different chain" }, }, @@ -47,8 +49,6 @@ func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { suite.coordinator.SetupClients(subjectPath) subjectClientState := suite.chainA.GetClientState(subjectPath.EndpointA.ClientID).(*types.ClientState) - subjectClientState.AllowUpdateAfterMisbehaviour = true - subjectClientState.AllowUpdateAfterExpiry = true // expire subject client suite.coordinator.IncrementTimeBy(subjectClientState.TrustingPeriod) @@ -71,140 +71,40 @@ func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { testCases := []struct { name string - AllowUpdateAfterExpiry bool - AllowUpdateAfterMisbehaviour bool FreezeClient bool ExpireClient bool expPass bool }{ { - name: "not allowed to be updated, not frozen or expired", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: false, - FreezeClient: false, - ExpireClient: false, - expPass: false, - }, - { - name: "not allowed to be updated, client is frozen", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: false, - FreezeClient: true, - ExpireClient: false, - expPass: false, - }, - { - name: "not allowed to be updated, client is expired", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: false, - FreezeClient: false, - ExpireClient: true, - expPass: false, - }, - { - name: "not allowed to be updated, client is frozen and expired", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: false, - FreezeClient: true, - ExpireClient: true, - expPass: false, - }, - { - name: "allowed to be updated only after misbehaviour, not frozen or expired", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: true, - FreezeClient: false, - ExpireClient: false, - expPass: false, - }, - { - name: "allowed to be updated only after misbehaviour, client is expired", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: true, - FreezeClient: false, - ExpireClient: true, - expPass: false, - }, - { - name: "allowed to be updated only after expiry, not frozen or expired", - AllowUpdateAfterExpiry: true, - AllowUpdateAfterMisbehaviour: false, - FreezeClient: false, - ExpireClient: false, - expPass: false, - }, - { - name: "allowed to be updated only after expiry, client is frozen", - AllowUpdateAfterExpiry: true, - AllowUpdateAfterMisbehaviour: false, - FreezeClient: true, - ExpireClient: false, - expPass: false, - }, - { - name: "PASS: allowed to be updated only after misbehaviour, client is frozen", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: true, - FreezeClient: true, - ExpireClient: false, - expPass: true, - }, - { - name: "PASS: allowed to be updated only after misbehaviour, client is frozen and expired", - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: true, + name: "PASS: update checks are deprecated, client is frozen and expired", FreezeClient: true, ExpireClient: true, expPass: true, }, { - name: "PASS: allowed to be updated only after expiry, client is expired", - AllowUpdateAfterExpiry: true, - AllowUpdateAfterMisbehaviour: false, + name: "PASS: update checks are deprecated, not frozen or expired", FreezeClient: false, - ExpireClient: true, + ExpireClient: false, expPass: true, }, { - name: "allowed to be updated only after expiry, client is frozen and expired", - AllowUpdateAfterExpiry: true, - AllowUpdateAfterMisbehaviour: false, - FreezeClient: true, - ExpireClient: true, - expPass: false, - }, - { - name: "allowed to be updated after expiry and misbehaviour, not frozen or expired", - AllowUpdateAfterExpiry: true, - AllowUpdateAfterMisbehaviour: true, + name: "PASS: update checks are deprecated, not frozen or expired", FreezeClient: false, ExpireClient: false, - expPass: false, + expPass: true, }, { - name: "PASS: allowed to be updated after expiry and misbehaviour, client is frozen", - AllowUpdateAfterExpiry: true, - AllowUpdateAfterMisbehaviour: true, + name: "PASS: update checks are deprecated, client is frozen", FreezeClient: true, ExpireClient: false, expPass: true, }, { - name: "PASS: allowed to be updated after expiry and misbehaviour, client is expired", - AllowUpdateAfterExpiry: true, - AllowUpdateAfterMisbehaviour: true, + name: "PASS: update checks are deprecated, client is expired", FreezeClient: false, ExpireClient: true, expPass: true, }, - { - name: "PASS: allowed to be updated after expiry and misbehaviour, client is frozen and expired", - AllowUpdateAfterExpiry: true, - AllowUpdateAfterMisbehaviour: true, - FreezeClient: true, - ExpireClient: true, - expPass: true, - }, } for _, tc := range testCases { @@ -221,8 +121,6 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(subjectPath) subjectClientState := suite.chainA.GetClientState(subjectPath.EndpointA.ClientID).(*types.ClientState) - subjectClientState.AllowUpdateAfterExpiry = tc.AllowUpdateAfterExpiry - subjectClientState.AllowUpdateAfterMisbehaviour = tc.AllowUpdateAfterMisbehaviour // apply freezing or expiry as determined by the test case if tc.FreezeClient { @@ -243,8 +141,6 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(substitutePath) substituteClientState := suite.chainA.GetClientState(substitutePath.EndpointA.ClientID).(*types.ClientState) - substituteClientState.AllowUpdateAfterExpiry = tc.AllowUpdateAfterExpiry - substituteClientState.AllowUpdateAfterMisbehaviour = tc.AllowUpdateAfterMisbehaviour suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), substitutePath.EndpointA.ClientID, substituteClientState) // update substitute a few times diff --git a/modules/light-clients/07-tendermint/types/tendermint.pb.go b/modules/light-clients/07-tendermint/types/tendermint.pb.go index 6436578b2ae..4be50fa8739 100644 --- a/modules/light-clients/07-tendermint/types/tendermint.pb.go +++ b/modules/light-clients/07-tendermint/types/tendermint.pb.go @@ -59,12 +59,10 @@ type ClientState struct { // the default upgrade module, upgrade_path should be []string{"upgrade", // "upgradedIBCState"}` UpgradePath []string `protobuf:"bytes,9,rep,name=upgrade_path,json=upgradePath,proto3" json:"upgrade_path,omitempty" yaml:"upgrade_path"` - // This flag, when set to true, will allow governance to recover a client - // which has expired - AllowUpdateAfterExpiry bool `protobuf:"varint,10,opt,name=allow_update_after_expiry,json=allowUpdateAfterExpiry,proto3" json:"allow_update_after_expiry,omitempty" yaml:"allow_update_after_expiry"` - // This flag, when set to true, will allow governance to unfreeze a client - // whose chain has experienced a misbehaviour event - AllowUpdateAfterMisbehaviour bool `protobuf:"varint,11,opt,name=allow_update_after_misbehaviour,json=allowUpdateAfterMisbehaviour,proto3" json:"allow_update_after_misbehaviour,omitempty" yaml:"allow_update_after_misbehaviour"` + // allow_update_after_expiry is deprecated + AllowUpdateAfterExpiry bool `protobuf:"varint,10,opt,name=allow_update_after_expiry,json=allowUpdateAfterExpiry,proto3" json:"allow_update_after_expiry,omitempty" yaml:"allow_update_after_expiry"` // Deprecated: Do not use. + // allow_update_after_misbehaviour is deprecated + AllowUpdateAfterMisbehaviour bool `protobuf:"varint,11,opt,name=allow_update_after_misbehaviour,json=allowUpdateAfterMisbehaviour,proto3" json:"allow_update_after_misbehaviour,omitempty" yaml:"allow_update_after_misbehaviour"` // Deprecated: Do not use. } func (m *ClientState) Reset() { *m = ClientState{} } @@ -324,75 +322,75 @@ func init() { } var fileDescriptor_c6d6cf2b288949be = []byte{ - // 1080 bytes of a gzipped FileDescriptorProto + // 1078 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcf, 0x6f, 0xe3, 0x44, - 0x14, 0x6e, 0xda, 0xb2, 0x4d, 0x26, 0xe9, 0x76, 0x31, 0xa5, 0x9b, 0x96, 0x6e, 0x1c, 0x19, 0xb4, - 0x44, 0x48, 0xb5, 0x49, 0x8a, 0x84, 0x54, 0x71, 0xc1, 0xdd, 0x45, 0x2d, 0x62, 0xa5, 0xca, 0xe5, - 0x87, 0x84, 0x84, 0xcc, 0xc4, 0x9e, 0x24, 0xa3, 0xb5, 0x3d, 0xc6, 0x33, 0x09, 0x2d, 0x7f, 0x01, - 0x1c, 0x90, 0xf6, 0x88, 0x38, 0x71, 0xe0, 0x8f, 0xd9, 0x63, 0x8f, 0x9c, 0x0c, 0x6a, 0x2f, 0x9c, - 0x73, 0xe4, 0x84, 0xe6, 0x87, 0xed, 0x69, 0xb6, 0x4b, 0xb5, 0x5c, 0xa2, 0x79, 0xef, 0x7d, 0xef, - 0xfb, 0x32, 0x6f, 0xde, 0xbc, 0x31, 0x70, 0xf0, 0x30, 0x70, 0x22, 0x3c, 0x9e, 0xb0, 0x20, 0xc2, - 0x28, 0x61, 0xd4, 0x61, 0x28, 0x09, 0x51, 0x16, 0xe3, 0x84, 0x39, 0xb3, 0xbe, 0x66, 0xd9, 0x69, - 0x46, 0x18, 0x31, 0x3a, 0x78, 0x18, 0xd8, 0x7a, 0x82, 0xad, 0x41, 0x66, 0xfd, 0x9d, 0xae, 0x96, - 0xcf, 0xce, 0x53, 0x44, 0x9d, 0x19, 0x8c, 0x70, 0x08, 0x19, 0xc9, 0x24, 0xc3, 0xce, 0xee, 0x0b, - 0x08, 0xf1, 0xab, 0xa2, 0xad, 0x34, 0x23, 0x64, 0x54, 0x58, 0x9d, 0x31, 0x21, 0xe3, 0x08, 0x39, - 0xc2, 0x1a, 0x4e, 0x47, 0x4e, 0x38, 0xcd, 0x20, 0xc3, 0x24, 0x51, 0x71, 0x73, 0x31, 0xce, 0x70, - 0x8c, 0x28, 0x83, 0x71, 0x5a, 0x00, 0xf8, 0xfe, 0x02, 0x92, 0x21, 0x47, 0xfe, 0x5d, 0xbe, 0x27, - 0xb9, 0x52, 0x80, 0x77, 0x2b, 0x00, 0x89, 0x63, 0xcc, 0xe2, 0x02, 0x54, 0x5a, 0x0a, 0xb8, 0x39, - 0x26, 0x63, 0x22, 0x96, 0x0e, 0x5f, 0x49, 0xaf, 0xf5, 0xf7, 0x1a, 0x68, 0x1e, 0x0a, 0xbe, 0x53, - 0x06, 0x19, 0x32, 0xb6, 0x41, 0x3d, 0x98, 0x40, 0x9c, 0xf8, 0x38, 0x6c, 0xd7, 0xba, 0xb5, 0x5e, - 0xc3, 0x5b, 0x13, 0xf6, 0x71, 0x68, 0x20, 0xd0, 0x64, 0xd9, 0x94, 0x32, 0x3f, 0x42, 0x33, 0x14, - 0xb5, 0x97, 0xbb, 0xb5, 0x5e, 0x73, 0xd0, 0xb3, 0xff, 0xbb, 0x9e, 0xf6, 0x27, 0x19, 0x0c, 0xf8, - 0x86, 0xdd, 0x9d, 0xe7, 0xb9, 0xb9, 0x34, 0xcf, 0x4d, 0xe3, 0x1c, 0xc6, 0xd1, 0x81, 0xa5, 0x51, - 0x59, 0x1e, 0x10, 0xd6, 0x67, 0xdc, 0x30, 0x46, 0x60, 0x43, 0x58, 0x38, 0x19, 0xfb, 0x29, 0xca, - 0x30, 0x09, 0xdb, 0x2b, 0x42, 0x6a, 0xdb, 0x96, 0xc5, 0xb2, 0x8b, 0x62, 0xd9, 0x8f, 0x54, 0x31, - 0x5d, 0x4b, 0x71, 0x6f, 0x69, 0xdc, 0x55, 0xbe, 0xf5, 0xcb, 0x9f, 0x66, 0xcd, 0xbb, 0x5b, 0x78, - 0x4f, 0x84, 0xd3, 0xc0, 0xe0, 0xde, 0x34, 0x19, 0x92, 0x24, 0xd4, 0x84, 0x56, 0x6f, 0x13, 0x7a, - 0x5b, 0x09, 0xdd, 0x97, 0x42, 0x8b, 0x04, 0x52, 0x69, 0xa3, 0x74, 0x2b, 0x29, 0x04, 0x36, 0x62, - 0x78, 0xe6, 0x07, 0x11, 0x09, 0x9e, 0xfa, 0x61, 0x86, 0x47, 0xac, 0xfd, 0xda, 0x2b, 0x6e, 0x69, - 0x21, 0x5f, 0x0a, 0xad, 0xc7, 0xf0, 0xec, 0x90, 0x3b, 0x1f, 0x71, 0x9f, 0xf1, 0x0d, 0x58, 0x1f, - 0x65, 0xe4, 0x07, 0x94, 0xf8, 0x13, 0xc4, 0x0f, 0xa4, 0x7d, 0x47, 0x88, 0xec, 0x88, 0x23, 0xe2, - 0x2d, 0x62, 0xab, 0xce, 0x99, 0xf5, 0xed, 0x23, 0x81, 0x70, 0x77, 0x95, 0xca, 0xa6, 0x54, 0xb9, - 0x96, 0x6e, 0x79, 0x2d, 0x69, 0x4b, 0x2c, 0xa7, 0x8f, 0x20, 0x43, 0x94, 0x15, 0xf4, 0x6b, 0xaf, - 0x4a, 0x7f, 0x2d, 0xdd, 0xf2, 0x5a, 0xd2, 0x56, 0xf4, 0xc7, 0xa0, 0x29, 0xae, 0x8e, 0x4f, 0x53, - 0x14, 0xd0, 0x76, 0xbd, 0xbb, 0xd2, 0x6b, 0x0e, 0xee, 0xd9, 0x38, 0xa0, 0x83, 0x7d, 0xfb, 0x84, - 0x47, 0x4e, 0x53, 0x14, 0xb8, 0x5b, 0x55, 0x0b, 0x69, 0x70, 0xcb, 0x03, 0x69, 0x01, 0xa1, 0xc6, - 0x01, 0x68, 0x4d, 0xd3, 0x71, 0x06, 0x43, 0xe4, 0xa7, 0x90, 0x4d, 0xda, 0x8d, 0xee, 0x4a, 0xaf, - 0xe1, 0xde, 0x9f, 0xe7, 0xe6, 0x1b, 0xea, 0xdc, 0xb4, 0xa8, 0xe5, 0x35, 0x95, 0x79, 0x02, 0xd9, - 0xc4, 0xf0, 0xc1, 0x36, 0x8c, 0x22, 0xf2, 0xbd, 0x3f, 0x4d, 0x43, 0xc8, 0x90, 0x0f, 0x47, 0x0c, - 0x65, 0x3e, 0x3a, 0x4b, 0x71, 0x76, 0xde, 0x06, 0xdd, 0x5a, 0xaf, 0xee, 0xbe, 0x33, 0xcf, 0xcd, - 0xae, 0x24, 0x7a, 0x29, 0xd4, 0xf2, 0xb6, 0x44, 0xec, 0x0b, 0x11, 0xfa, 0x98, 0x47, 0x1e, 0x8b, - 0x80, 0xf1, 0x1d, 0x30, 0x6f, 0xc8, 0x8a, 0x31, 0x1d, 0xa2, 0x09, 0x9c, 0x61, 0x32, 0xcd, 0xda, - 0x4d, 0x21, 0xf3, 0xde, 0x3c, 0x37, 0x1f, 0xbe, 0x54, 0x46, 0x4f, 0xb0, 0xbc, 0xdd, 0x45, 0xb1, - 0x27, 0x5a, 0xf8, 0x60, 0xf5, 0xc7, 0xdf, 0xcc, 0x25, 0xeb, 0xf7, 0x65, 0x70, 0xf7, 0x90, 0x24, - 0x14, 0x25, 0x74, 0x4a, 0xe5, 0x6d, 0x77, 0x41, 0xa3, 0x1c, 0x38, 0xe2, 0xba, 0xf3, 0xe3, 0x5c, - 0x6c, 0xc9, 0xcf, 0x0b, 0x84, 0x5b, 0xe7, 0xc7, 0xf9, 0x8c, 0x77, 0x5e, 0x95, 0x66, 0x7c, 0x04, - 0x56, 0x33, 0x42, 0x98, 0x9a, 0x07, 0x96, 0xd6, 0x0d, 0xd5, 0x04, 0x9a, 0xf5, 0xed, 0x27, 0x28, - 0x7b, 0x1a, 0x21, 0x8f, 0x10, 0xe6, 0xae, 0x72, 0x1a, 0x4f, 0x64, 0x19, 0x3f, 0xd5, 0xc0, 0x66, - 0x82, 0xce, 0x98, 0x5f, 0x4e, 0x59, 0xea, 0x4f, 0x20, 0x9d, 0x88, 0x3b, 0xdf, 0x72, 0xbf, 0x9a, - 0xe7, 0xe6, 0x5b, 0xb2, 0x06, 0x37, 0xa1, 0xac, 0x7f, 0x72, 0xf3, 0x83, 0x31, 0x66, 0x93, 0xe9, - 0x90, 0xcb, 0xe9, 0xb3, 0x5f, 0x5b, 0x46, 0x78, 0x48, 0x9d, 0xe1, 0x39, 0x43, 0xd4, 0x3e, 0x42, - 0x67, 0x2e, 0x5f, 0x78, 0x06, 0xa7, 0xfb, 0xb2, 0x64, 0x3b, 0x82, 0x74, 0xa2, 0xca, 0xf4, 0xf3, - 0x32, 0x68, 0xe9, 0xd5, 0x33, 0xfa, 0xa0, 0x21, 0x1b, 0xbb, 0x9c, 0x89, 0xee, 0xe6, 0x3c, 0x37, - 0xef, 0xc9, 0xbf, 0x55, 0x86, 0x2c, 0xaf, 0x2e, 0xd7, 0xc7, 0xa1, 0x01, 0x41, 0x7d, 0x82, 0x60, - 0x88, 0x32, 0xbf, 0xaf, 0xea, 0xf2, 0xf0, 0xb6, 0x39, 0x79, 0x24, 0xf0, 0x6e, 0xe7, 0x32, 0x37, - 0xd7, 0xe4, 0xba, 0x3f, 0xcf, 0xcd, 0x0d, 0x29, 0x52, 0x90, 0x59, 0xde, 0x9a, 0x5c, 0xf6, 0x35, - 0x89, 0x81, 0x9a, 0x8f, 0xff, 0x43, 0x62, 0xf0, 0x82, 0xc4, 0xa0, 0x94, 0x18, 0xa8, 0x7a, 0xfc, - 0xba, 0x02, 0xee, 0x48, 0xb4, 0x01, 0xc1, 0x3a, 0xc5, 0xe3, 0x04, 0x85, 0xbe, 0x84, 0xa8, 0x96, - 0xe9, 0xe8, 0x3a, 0xf2, 0x2d, 0x3c, 0x15, 0x30, 0x25, 0xb8, 0x7b, 0x91, 0x9b, 0xb5, 0x6a, 0x0a, - 0x5c, 0xa3, 0xb0, 0xbc, 0x16, 0xd5, 0xb0, 0x7c, 0xc8, 0x94, 0x67, 0xec, 0x53, 0x54, 0xb4, 0xd5, - 0x0d, 0x12, 0xe5, 0xe1, 0x9d, 0x22, 0xe6, 0xb6, 0x2b, 0xfa, 0x6b, 0xe9, 0x96, 0xd7, 0x9a, 0x69, - 0x38, 0xe3, 0x5b, 0x20, 0x9f, 0x01, 0xa1, 0x2f, 0x86, 0xd8, 0xca, 0xad, 0x43, 0xec, 0x81, 0x1a, - 0x62, 0x6f, 0x6a, 0x8f, 0x4b, 0x99, 0x6f, 0x79, 0xeb, 0xca, 0xa1, 0xc6, 0x58, 0x04, 0x8c, 0x02, - 0x51, 0x35, 0xab, 0x7a, 0x58, 0x6e, 0xdb, 0xc5, 0x83, 0x79, 0x6e, 0x6e, 0x5f, 0x57, 0xa9, 0x38, - 0x2c, 0xef, 0x75, 0xe5, 0xac, 0xda, 0xd6, 0xfa, 0x14, 0xd4, 0x8b, 0x07, 0xd6, 0xd8, 0x05, 0x8d, - 0x64, 0x1a, 0xa3, 0x8c, 0x47, 0xc4, 0xc9, 0xac, 0x7a, 0x95, 0xc3, 0xe8, 0x82, 0x66, 0x88, 0x12, - 0x12, 0xe3, 0x44, 0xc4, 0x97, 0x45, 0x5c, 0x77, 0xb9, 0xfe, 0xf3, 0xcb, 0x4e, 0xed, 0xe2, 0xb2, - 0x53, 0xfb, 0xeb, 0xb2, 0x53, 0x7b, 0x76, 0xd5, 0x59, 0xba, 0xb8, 0xea, 0x2c, 0xfd, 0x71, 0xd5, - 0x59, 0xfa, 0xfa, 0xb1, 0x76, 0xc5, 0x02, 0x42, 0x63, 0x42, 0xf9, 0x67, 0xd7, 0xde, 0x98, 0x38, - 0xb3, 0x7d, 0x27, 0x26, 0xe1, 0x34, 0x42, 0x54, 0x7e, 0x84, 0xed, 0x15, 0x5f, 0x61, 0xef, 0x7f, - 0xb8, 0xb7, 0xf8, 0x99, 0x34, 0xbc, 0x23, 0x46, 0xca, 0xfe, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, - 0xc4, 0x2b, 0x98, 0x08, 0xb4, 0x09, 0x00, 0x00, + 0x14, 0x6e, 0xda, 0xb2, 0x4d, 0x26, 0xe9, 0x76, 0x31, 0xa5, 0x9b, 0x96, 0x6e, 0x1c, 0x19, 0xa9, + 0xe4, 0x40, 0x6d, 0x92, 0x22, 0x21, 0x55, 0x5c, 0x70, 0x77, 0x51, 0x8b, 0x58, 0xa9, 0x72, 0xf9, + 0x21, 0x21, 0x21, 0x33, 0xb1, 0x27, 0xc9, 0x68, 0x6d, 0x8f, 0xe5, 0x99, 0x84, 0x96, 0xbf, 0x00, + 0x4e, 0xec, 0x11, 0x71, 0xe2, 0xc0, 0x1f, 0xb3, 0xc7, 0x1e, 0x39, 0x19, 0xd4, 0x5e, 0x39, 0xe5, + 0xc8, 0x09, 0xcd, 0x0f, 0xdb, 0xd3, 0x6c, 0x97, 0x6a, 0xb9, 0x44, 0xf3, 0xde, 0xfb, 0xde, 0xf7, + 0x65, 0xe6, 0xbd, 0x79, 0x63, 0xe0, 0xe0, 0x61, 0xe0, 0x44, 0x78, 0x3c, 0x61, 0x41, 0x84, 0x51, + 0xc2, 0xa8, 0xc3, 0x50, 0x12, 0xa2, 0x2c, 0xc6, 0x09, 0x73, 0x66, 0x7d, 0xcd, 0xb2, 0xd3, 0x8c, + 0x30, 0x62, 0x74, 0xf0, 0x30, 0xb0, 0xf5, 0x04, 0x5b, 0x83, 0xcc, 0xfa, 0x3b, 0x5d, 0x2d, 0x9f, + 0x5d, 0xa4, 0x88, 0x3a, 0x33, 0x18, 0xe1, 0x10, 0x32, 0x92, 0x49, 0x86, 0x9d, 0xdd, 0x97, 0x10, + 0xe2, 0x57, 0x45, 0x5b, 0x69, 0x46, 0xc8, 0xa8, 0xb0, 0x3a, 0x63, 0x42, 0xc6, 0x11, 0x72, 0x84, + 0x35, 0x9c, 0x8e, 0x9c, 0x70, 0x9a, 0x41, 0x86, 0x49, 0xa2, 0xe2, 0xe6, 0x62, 0x9c, 0xe1, 0x18, + 0x51, 0x06, 0xe3, 0xb4, 0x00, 0xf0, 0xfd, 0x05, 0x24, 0x43, 0x8e, 0xfc, 0xbb, 0x7c, 0x4f, 0x72, + 0xa5, 0x00, 0xef, 0x55, 0x00, 0x12, 0xc7, 0x98, 0xc5, 0x05, 0xa8, 0xb4, 0x14, 0x70, 0x73, 0x4c, + 0xc6, 0x44, 0x2c, 0x1d, 0xbe, 0x92, 0x5e, 0xeb, 0xef, 0x35, 0xd0, 0x3c, 0x12, 0x7c, 0x67, 0x0c, + 0x32, 0x64, 0x6c, 0x83, 0x7a, 0x30, 0x81, 0x38, 0xf1, 0x71, 0xd8, 0xae, 0x75, 0x6b, 0xbd, 0x86, + 0xb7, 0x26, 0xec, 0x93, 0xd0, 0x40, 0xa0, 0xc9, 0xb2, 0x29, 0x65, 0x7e, 0x84, 0x66, 0x28, 0x6a, + 0x2f, 0x77, 0x6b, 0xbd, 0xe6, 0xa0, 0x67, 0xff, 0xf7, 0x79, 0xda, 0x9f, 0x66, 0x30, 0xe0, 0x1b, + 0x76, 0x77, 0x5e, 0xe4, 0xe6, 0xd2, 0x3c, 0x37, 0x8d, 0x0b, 0x18, 0x47, 0x87, 0x96, 0x46, 0x65, + 0x79, 0x40, 0x58, 0x9f, 0x73, 0xc3, 0x18, 0x81, 0x0d, 0x61, 0xe1, 0x64, 0xec, 0xa7, 0x28, 0xc3, + 0x24, 0x6c, 0xaf, 0x08, 0xa9, 0x6d, 0x5b, 0x1e, 0x96, 0x5d, 0x1c, 0x96, 0xfd, 0x58, 0x1d, 0xa6, + 0x6b, 0x29, 0xee, 0x2d, 0x8d, 0xbb, 0xca, 0xb7, 0x7e, 0xf9, 0xd3, 0xac, 0x79, 0xf7, 0x0b, 0xef, + 0xa9, 0x70, 0x1a, 0x18, 0x3c, 0x98, 0x26, 0x43, 0x92, 0x84, 0x9a, 0xd0, 0xea, 0x5d, 0x42, 0xef, + 0x2a, 0xa1, 0x87, 0x52, 0x68, 0x91, 0x40, 0x2a, 0x6d, 0x94, 0x6e, 0x25, 0x85, 0xc0, 0x46, 0x0c, + 0xcf, 0xfd, 0x20, 0x22, 0xc1, 0x33, 0x3f, 0xcc, 0xf0, 0x88, 0xb5, 0xdf, 0x78, 0xcd, 0x2d, 0x2d, + 0xe4, 0x4b, 0xa1, 0xf5, 0x18, 0x9e, 0x1f, 0x71, 0xe7, 0x63, 0xee, 0x33, 0xbe, 0x05, 0xeb, 0xa3, + 0x8c, 0xfc, 0x80, 0x12, 0x7f, 0x82, 0x78, 0x41, 0xda, 0xf7, 0x84, 0xc8, 0x8e, 0x28, 0x11, 0x6f, + 0x11, 0x5b, 0x75, 0xce, 0xac, 0x6f, 0x1f, 0x0b, 0x84, 0xbb, 0xab, 0x54, 0x36, 0xa5, 0xca, 0x8d, + 0x74, 0xcb, 0x6b, 0x49, 0x5b, 0x62, 0x39, 0x7d, 0x04, 0x19, 0xa2, 0xac, 0xa0, 0x5f, 0x7b, 0x5d, + 0xfa, 0x1b, 0xe9, 0x96, 0xd7, 0x92, 0xb6, 0xa2, 0x3f, 0x01, 0x4d, 0x71, 0x75, 0x7c, 0x9a, 0xa2, + 0x80, 0xb6, 0xeb, 0xdd, 0x95, 0x5e, 0x73, 0xf0, 0xc0, 0xc6, 0x01, 0x1d, 0x1c, 0xd8, 0xa7, 0x3c, + 0x72, 0x96, 0xa2, 0xc0, 0xdd, 0xaa, 0x5a, 0x48, 0x83, 0x5b, 0x1e, 0x48, 0x0b, 0x08, 0x35, 0x0e, + 0x41, 0x6b, 0x9a, 0x8e, 0x33, 0x18, 0x22, 0x3f, 0x85, 0x6c, 0xd2, 0x6e, 0x74, 0x57, 0x7a, 0x0d, + 0xf7, 0xe1, 0x3c, 0x37, 0xdf, 0x52, 0x75, 0xd3, 0xa2, 0x96, 0xd7, 0x54, 0xe6, 0x29, 0x64, 0x13, + 0x03, 0x82, 0x6d, 0x18, 0x45, 0xe4, 0x7b, 0x7f, 0x9a, 0x86, 0x90, 0x21, 0x1f, 0x8e, 0x18, 0xca, + 0x7c, 0x74, 0x9e, 0xe2, 0xec, 0xa2, 0x0d, 0xba, 0xb5, 0x5e, 0xdd, 0xdd, 0x9b, 0xe7, 0x66, 0x57, + 0x12, 0xbd, 0x12, 0x6a, 0xb5, 0x6b, 0xde, 0x96, 0x88, 0x7e, 0x29, 0x82, 0x9f, 0xf0, 0xd8, 0x13, + 0x11, 0x32, 0x28, 0x30, 0x6f, 0xc9, 0x8b, 0x31, 0x1d, 0xa2, 0x09, 0x9c, 0x61, 0x32, 0xcd, 0xda, + 0x4d, 0x21, 0xf4, 0xfe, 0x3c, 0x37, 0xf7, 0x5e, 0x29, 0xa4, 0x27, 0x70, 0xb9, 0xdd, 0x45, 0xb9, + 0xa7, 0x1a, 0xe0, 0x70, 0xf5, 0xc7, 0xdf, 0xcc, 0x25, 0xeb, 0xf7, 0x65, 0x70, 0xff, 0x88, 0x24, + 0x14, 0x25, 0x74, 0x4a, 0xe5, 0x8d, 0x77, 0x41, 0xa3, 0x1c, 0x3a, 0xe2, 0xca, 0xf3, 0x92, 0x2e, + 0xb6, 0xe5, 0x17, 0x05, 0xc2, 0xad, 0xf3, 0x92, 0x3e, 0xe7, 0xdd, 0x57, 0xa5, 0x19, 0x1f, 0x83, + 0xd5, 0x8c, 0x10, 0xa6, 0x66, 0x82, 0xa5, 0x75, 0x44, 0x35, 0x85, 0x66, 0x7d, 0xfb, 0x29, 0xca, + 0x9e, 0x45, 0xc8, 0x23, 0x84, 0xb9, 0xab, 0x9c, 0xc6, 0x13, 0x59, 0xc6, 0x4f, 0x35, 0xb0, 0x99, + 0xa0, 0x73, 0xe6, 0x97, 0x93, 0x96, 0xfa, 0x13, 0x48, 0x27, 0xe2, 0xde, 0xb7, 0xdc, 0xaf, 0xe7, + 0xb9, 0xf9, 0x8e, 0x3c, 0x85, 0xdb, 0x50, 0xd6, 0x3f, 0xb9, 0xf9, 0xe1, 0x18, 0xb3, 0xc9, 0x74, + 0xc8, 0xe5, 0xf4, 0xf9, 0xaf, 0x2d, 0x23, 0x3c, 0xa4, 0xce, 0xf0, 0x82, 0x21, 0x6a, 0x1f, 0xa3, + 0x73, 0x97, 0x2f, 0x3c, 0x83, 0xd3, 0x7d, 0x55, 0xb2, 0x1d, 0x43, 0x3a, 0x51, 0xc7, 0xf4, 0xf3, + 0x32, 0x68, 0xe9, 0xa7, 0x67, 0x1c, 0x80, 0x86, 0x6c, 0xee, 0x72, 0x2e, 0x8a, 0x46, 0x7c, 0x20, + 0xff, 0x56, 0x19, 0xe2, 0x65, 0xa8, 0x4b, 0xeb, 0x24, 0x34, 0x20, 0xa8, 0x4f, 0x10, 0x0c, 0x51, + 0xe6, 0xf7, 0xd5, 0xc9, 0xec, 0xdd, 0x35, 0x2d, 0x8f, 0x05, 0xde, 0xed, 0x5c, 0xe5, 0xe6, 0x9a, + 0x5c, 0xf7, 0xe7, 0xb9, 0xb9, 0x21, 0x65, 0x0a, 0x32, 0xcb, 0x5b, 0x93, 0xcb, 0xbe, 0x26, 0x31, + 0x50, 0x53, 0xf2, 0x7f, 0x48, 0x0c, 0x5e, 0x92, 0x18, 0x94, 0x12, 0x03, 0x75, 0x22, 0xbf, 0xae, + 0x80, 0x7b, 0x12, 0x6d, 0x40, 0xb0, 0x4e, 0xf1, 0x38, 0x41, 0xa1, 0x2f, 0x21, 0xaa, 0x69, 0x3a, + 0xba, 0x8e, 0x7c, 0x11, 0xcf, 0x04, 0x4c, 0x09, 0xee, 0x5e, 0xe6, 0x66, 0xad, 0x9a, 0x05, 0x37, + 0x28, 0x2c, 0xaf, 0x45, 0x35, 0x2c, 0x1f, 0x35, 0x65, 0x95, 0x7d, 0x8a, 0x8a, 0xc6, 0xba, 0x45, + 0xa2, 0x2c, 0xdf, 0x19, 0x62, 0x6e, 0xbb, 0xa2, 0xbf, 0x91, 0x6e, 0x79, 0xad, 0x99, 0x86, 0x33, + 0xbe, 0x03, 0xf2, 0x31, 0x10, 0xfa, 0x62, 0x94, 0xad, 0xdc, 0x39, 0xca, 0x1e, 0xa9, 0x51, 0xf6, + 0xb6, 0xf6, 0xc4, 0x94, 0xf9, 0x96, 0xb7, 0xae, 0x1c, 0x6a, 0x98, 0x45, 0xc0, 0x28, 0x10, 0x55, + 0xbb, 0xaa, 0xe7, 0xe5, 0xae, 0x5d, 0x3c, 0x9a, 0xe7, 0xe6, 0xf6, 0x4d, 0x95, 0x8a, 0xc3, 0xf2, + 0xde, 0x54, 0xce, 0xaa, 0x71, 0xad, 0xcf, 0x40, 0xbd, 0x78, 0x66, 0x8d, 0x5d, 0xd0, 0x48, 0xa6, + 0x31, 0xca, 0x78, 0x44, 0x54, 0x66, 0xd5, 0xab, 0x1c, 0x46, 0x17, 0x34, 0x43, 0x94, 0x90, 0x18, + 0x27, 0x22, 0xbe, 0x2c, 0xe2, 0xba, 0xcb, 0xf5, 0x5f, 0x5c, 0x75, 0x6a, 0x97, 0x57, 0x9d, 0xda, + 0x5f, 0x57, 0x9d, 0xda, 0xf3, 0xeb, 0xce, 0xd2, 0xe5, 0x75, 0x67, 0xe9, 0x8f, 0xeb, 0xce, 0xd2, + 0x37, 0x4f, 0xb4, 0x4b, 0x16, 0x10, 0x1a, 0x13, 0xca, 0x3f, 0xbe, 0xf6, 0xc7, 0xc4, 0x99, 0x1d, + 0x38, 0x31, 0x09, 0xa7, 0x11, 0xa2, 0xf2, 0x53, 0x6c, 0xbf, 0xf8, 0x16, 0xfb, 0xe0, 0xa3, 0xfd, + 0xc5, 0x8f, 0xa5, 0xe1, 0x3d, 0x31, 0x54, 0x0e, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xdd, 0xc8, + 0x3e, 0xfe, 0xba, 0x09, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { diff --git a/proto/ibc/lightclients/tendermint/v1/tendermint.proto b/proto/ibc/lightclients/tendermint/v1/tendermint.proto index 322574fa5bf..2815fe6ad2a 100644 --- a/proto/ibc/lightclients/tendermint/v1/tendermint.proto +++ b/proto/ibc/lightclients/tendermint/v1/tendermint.proto @@ -52,12 +52,11 @@ message ClientState { // "upgradedIBCState"}` repeated string upgrade_path = 9 [(gogoproto.moretags) = "yaml:\"upgrade_path\""]; - // This flag, when set to true, will allow governance to recover a client - // which has expired - bool allow_update_after_expiry = 10 [(gogoproto.moretags) = "yaml:\"allow_update_after_expiry\""]; - // This flag, when set to true, will allow governance to unfreeze a client - // whose chain has experienced a misbehaviour event - bool allow_update_after_misbehaviour = 11 [(gogoproto.moretags) = "yaml:\"allow_update_after_misbehaviour\""]; + // allow_update_after_expiry is deprecated + bool allow_update_after_expiry = 10 [deprecated = true, (gogoproto.moretags) = "yaml:\"allow_update_after_expiry\""]; + // allow_update_after_misbehaviour is deprecated + bool allow_update_after_misbehaviour = 11 + [deprecated = true, (gogoproto.moretags) = "yaml:\"allow_update_after_misbehaviour\""]; } // ConsensusState defines the consensus state from Tendermint. From da232b85669d0324e81759072b46fee8e974a7a2 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sat, 11 Jun 2022 22:24:58 +0200 Subject: [PATCH 152/275] changed gRPC web route to consensus_state/{client_id}/heights (#1517) --- docs/client/swagger-ui/swagger.yaml | 518 ++++++++++---------- docs/ibc/proto-docs.md | 2 +- modules/core/02-client/types/query.pb.go | 135 +++-- modules/core/02-client/types/query.pb.gw.go | 2 +- proto/ibc/core/client/v1/query.proto | 2 +- 5 files changed, 320 insertions(+), 339 deletions(-) diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml index 5299015bfff..409bddcafc2 100644 --- a/docs/client/swagger-ui/swagger.yaml +++ b/docs/client/swagger-ui/swagger.yaml @@ -4503,56 +4503,236 @@ paths: type: string tags: - Query - '/ibc/core/client/v1/consensus_states/heights/{client_id}': + '/ibc/core/client/v1/consensus_states/{client_id}': get: - summary: >- - ConsensusStateHeights queries the height of every consensus states - associated with a given client. - operationId: ConsensusStateHeights + summary: |- + ConsensusStates queries all the consensus state associated with a given + client. + operationId: ConsensusStates responses: '200': description: A successful response. schema: type: object properties: - consensus_state_heights: + consensus_states: type: array items: type: object properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each height - while keeping + height: + title: consensus state height + type: object + properties: + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each + height while keeping - RevisionNumber the same. However some consensus algorithms - may choose to + RevisionNumber the same. However some consensus + algorithms may choose to - reset the height in certain conditions e.g. hard forks, - state-machine + reset the height in certain conditions e.g. hard forks, + state-machine - breaking changes In these cases, the RevisionNumber is - incremented so that + breaking changes In these cases, the RevisionNumber is + incremented so that - height continues to be monitonically increasing even as the - RevisionHeight + height continues to be monitonically increasing even as + the RevisionHeight - gets reset - title: >- - Height is a monotonically increasing data type + gets reset + consensus_state: + type: object + properties: + type_url: + type: string + description: >- + A URL/resource name that uniquely identifies the + type of the serialized - that can be compared against another Height for the purposes - of updating and + protocol buffer message. This string must contain at + least - freezing clients - title: consensus state heights + one "/" character. The last segment of the URL's + path must represent + + the fully qualified name of the type (as in + + `path/google.protobuf.Duration`). The name should be + in a canonical form + + (e.g., leading "." is not accepted). + + + In practice, teams usually precompile into the + binary all types that they + + expect it to use in the context of Any. However, for + URLs which use the + + scheme `http`, `https`, or no scheme, one can + optionally set up a type + + server that maps type URLs to message definitions as + follows: + + + * If no scheme is provided, `https` is assumed. + + * An HTTP GET on the URL must yield a + [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results + based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available + in the official + + protobuf release, and it is not used for type URLs + beginning with + + type.googleapis.com. + + + Schemes other than `http`, `https` (or the empty + scheme) might be + + used with implementation specific semantics. + value: + type: string + format: byte + description: >- + Must be a valid serialized protocol buffer of the + above specified type. + description: >- + `Any` contains an arbitrary serialized protocol buffer + message along with a + + URL that describes the type of the serialized message. + + + Protobuf library provides support to pack/unpack Any + values in the form + + of utility functions or additional generated methods of + the Any type. + + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by + default use + + 'type.googleapis.com/full.type.name' as the type URL and + the unpack + + methods only use the fully qualified type name after the + last '/' + + in the type URL, for example "foo.bar.com/x/y.z" will + yield type + + name "y.z". + + + + JSON + + ==== + + The JSON representation of an `Any` value uses the + regular + + representation of the deserialized, embedded message, + with an + + additional field `@type` which contains the type URL. + Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a + custom JSON + + representation, that representation will be embedded + adding a field + + `value` which holds the custom JSON in addition to the + `@type` + + field. Example (for message + [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + title: consensus state + description: >- + ConsensusStateWithHeight defines a consensus state with an + additional height + + field. + title: consensus states associated with the identifier pagination: title: pagination response type: object @@ -4582,8 +4762,8 @@ paths: PageResponse page = 2; } title: |- - QueryConsensusStateHeightsResponse is the response type for the - Query/ConsensusStateHeights RPC method + QueryConsensusStatesResponse is the response type for the + Query/ConsensusStates RPC method default: description: An unexpected error response schema: @@ -4828,242 +5008,56 @@ paths: format: boolean tags: - Query - '/ibc/core/client/v1/consensus_states/{client_id}': + '/ibc/core/client/v1/consensus_states/{client_id}/heights': get: - summary: |- - ConsensusStates queries all the consensus state associated with a given - client. - operationId: ConsensusStates + summary: >- + ConsensusStateHeights queries the height of every consensus states + associated with a given client. + operationId: ConsensusStateHeights responses: '200': description: A successful response. schema: type: object properties: - consensus_states: + consensus_state_heights: type: array items: type: object properties: - height: - type: object - properties: - revision_number: - type: string - format: uint64 - title: the revision that the client is currently on - revision_height: - type: string - format: uint64 - title: the height within the given revision - description: >- - Normally the RevisionHeight is incremented at each - height while keeping - - RevisionNumber the same. However some consensus - algorithms may choose to - - reset the height in certain conditions e.g. hard forks, - state-machine - - breaking changes In these cases, the RevisionNumber is - incremented so that - - height continues to be monitonically increasing even as - the RevisionHeight - - gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the - purposes of updating and - - freezing clients - consensus_state: - type: object - properties: - type_url: - type: string - description: >- - A URL/resource name that uniquely identifies the - type of the serialized - - protocol buffer message. This string must contain at - least - - one "/" character. The last segment of the URL's - path must represent - - the fully qualified name of the type (as in - - `path/google.protobuf.Duration`). The name should be - in a canonical form - - (e.g., leading "." is not accepted). - - - In practice, teams usually precompile into the - binary all types that they - - expect it to use in the context of Any. However, for - URLs which use the - - scheme `http`, `https`, or no scheme, one can - optionally set up a type - - server that maps type URLs to message definitions as - follows: - - - * If no scheme is provided, `https` is assumed. - - * An HTTP GET on the URL must yield a - [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results - based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available - in the official - - protobuf release, and it is not used for type URLs - beginning with - - type.googleapis.com. - - - Schemes other than `http`, `https` (or the empty - scheme) might be - - used with implementation specific semantics. - value: - type: string - format: byte - description: >- - Must be a valid serialized protocol buffer of the - above specified type. - description: >- - `Any` contains an arbitrary serialized protocol buffer - message along with a - - URL that describes the type of the serialized message. - - - Protobuf library provides support to pack/unpack Any - values in the form - - of utility functions or additional generated methods of - the Any type. - - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by - default use - - 'type.googleapis.com/full.type.name' as the type URL and - the unpack - - methods only use the fully qualified type name after the - last '/' - - in the type URL, for example "foo.bar.com/x/y.z" will - yield type - - name "y.z". - - - - JSON - - ==== - - The JSON representation of an `Any` value uses the - regular - - representation of the deserialized, embedded message, - with an - - additional field `@type` which contains the type URL. - Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + revision_number: + type: string + format: uint64 + title: the revision that the client is currently on + revision_height: + type: string + format: uint64 + title: the height within the given revision + description: >- + Normally the RevisionHeight is incremented at each height + while keeping - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } + RevisionNumber the same. However some consensus algorithms + may choose to - If the embedded message type is well-known and has a - custom JSON + reset the height in certain conditions e.g. hard forks, + state-machine - representation, that representation will be embedded - adding a field + breaking changes In these cases, the RevisionNumber is + incremented so that - `value` which holds the custom JSON in addition to the - `@type` + height continues to be monitonically increasing even as the + RevisionHeight - field. Example (for message - [google.protobuf.Duration][]): + gets reset + title: >- + Height is a monotonically increasing data type - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - title: consensus state - description: >- - ConsensusStateWithHeight defines a consensus state with an - additional height + that can be compared against another Height for the purposes + of updating and - field. - title: consensus states associated with the identifier + freezing clients + title: consensus state heights pagination: title: pagination response type: object @@ -5093,8 +5087,8 @@ paths: PageResponse page = 2; } title: |- - QueryConsensusStatesResponse is the response type for the - Query/ConsensusStates RPC method + QueryConsensusStateHeightsResponse is the response type for the + Query/ConsensusStateHeights RPC method default: description: An unexpected error response schema: @@ -13991,6 +13985,7 @@ definitions: type: object properties: height: + title: consensus state height type: object properties: revision_number: @@ -14017,13 +14012,6 @@ definitions: RevisionHeight gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes of - updating and - - freezing clients consensus_state: type: object properties: @@ -15126,6 +15114,7 @@ definitions: type: object properties: height: + title: consensus state height type: object properties: revision_number: @@ -15153,13 +15142,6 @@ definitions: RevisionHeight gets reset - title: >- - Height is a monotonically increasing data type - - that can be compared against another Height for the purposes of - updating and - - freezing clients consensus_state: type: object properties: diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 791b5ec4972..6080f32d60e 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -3499,7 +3499,7 @@ Query provides defines the gRPC querier service | `ClientStates` | [QueryClientStatesRequest](#ibc.core.client.v1.QueryClientStatesRequest) | [QueryClientStatesResponse](#ibc.core.client.v1.QueryClientStatesResponse) | ClientStates queries all the IBC light clients of a chain. | GET|/ibc/core/client/v1/client_states| | `ConsensusState` | [QueryConsensusStateRequest](#ibc.core.client.v1.QueryConsensusStateRequest) | [QueryConsensusStateResponse](#ibc.core.client.v1.QueryConsensusStateResponse) | ConsensusState queries a consensus state associated with a client state at a given height. | GET|/ibc/core/client/v1/consensus_states/{client_id}/revision/{revision_number}/height/{revision_height}| | `ConsensusStates` | [QueryConsensusStatesRequest](#ibc.core.client.v1.QueryConsensusStatesRequest) | [QueryConsensusStatesResponse](#ibc.core.client.v1.QueryConsensusStatesResponse) | ConsensusStates queries all the consensus state associated with a given client. | GET|/ibc/core/client/v1/consensus_states/{client_id}| -| `ConsensusStateHeights` | [QueryConsensusStateHeightsRequest](#ibc.core.client.v1.QueryConsensusStateHeightsRequest) | [QueryConsensusStateHeightsResponse](#ibc.core.client.v1.QueryConsensusStateHeightsResponse) | ConsensusStateHeights queries the height of every consensus states associated with a given client. | GET|/ibc/core/client/v1/consensus_states/heights/{client_id}| +| `ConsensusStateHeights` | [QueryConsensusStateHeightsRequest](#ibc.core.client.v1.QueryConsensusStateHeightsRequest) | [QueryConsensusStateHeightsResponse](#ibc.core.client.v1.QueryConsensusStateHeightsResponse) | ConsensusStateHeights queries the height of every consensus states associated with a given client. | GET|/ibc/core/client/v1/consensus_states/{client_id}/heights| | `ClientStatus` | [QueryClientStatusRequest](#ibc.core.client.v1.QueryClientStatusRequest) | [QueryClientStatusResponse](#ibc.core.client.v1.QueryClientStatusResponse) | Status queries the status of an IBC client. | GET|/ibc/core/client/v1/client_status/{client_id}| | `ClientParams` | [QueryClientParamsRequest](#ibc.core.client.v1.QueryClientParamsRequest) | [QueryClientParamsResponse](#ibc.core.client.v1.QueryClientParamsResponse) | ClientParams queries all parameters of the ibc client. | GET|/ibc/client/v1/params| | `UpgradedClientState` | [QueryUpgradedClientStateRequest](#ibc.core.client.v1.QueryUpgradedClientStateRequest) | [QueryUpgradedClientStateResponse](#ibc.core.client.v1.QueryUpgradedClientStateResponse) | UpgradedClientState queries an Upgraded IBC light client. | GET|/ibc/core/client/v1/upgraded_client_states| diff --git a/modules/core/02-client/types/query.pb.go b/modules/core/02-client/types/query.pb.go index f4c033bfea3..bcb5ccd498e 100644 --- a/modules/core/02-client/types/query.pb.go +++ b/modules/core/02-client/types/query.pb.go @@ -984,74 +984,73 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/query.proto", fileDescriptor_dc42cdfd1d52d76e) } var fileDescriptor_dc42cdfd1d52d76e = []byte{ - // 1057 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcf, 0x6f, 0x1b, 0x45, - 0x14, 0xce, 0xa4, 0x69, 0xd4, 0x3e, 0xbb, 0x09, 0x9a, 0xe6, 0x87, 0xbb, 0x2d, 0x8e, 0xb3, 0x41, - 0x34, 0x2d, 0xc9, 0x4e, 0xe2, 0xd0, 0x24, 0x42, 0x42, 0x82, 0x54, 0x2a, 0xed, 0xa5, 0x94, 0x45, - 0x08, 0x84, 0x84, 0xa2, 0xdd, 0xf5, 0x66, 0xb3, 0x92, 0xbd, 0xe3, 0x7a, 0x76, 0x2d, 0x45, 0x55, - 0x2e, 0x3d, 0x21, 0x4e, 0x48, 0x48, 0x5c, 0x91, 0x38, 0x72, 0xa8, 0x38, 0x20, 0x71, 0xe5, 0x04, - 0x39, 0x70, 0xa8, 0x04, 0x07, 0x4e, 0x14, 0x25, 0xfc, 0x21, 0xc8, 0x33, 0xb3, 0xf6, 0x8e, 0x3d, - 0xae, 0xd7, 0x28, 0x70, 0xdb, 0x9d, 0x79, 0x3f, 0xbe, 0xef, 0x7b, 0xcf, 0xef, 0xad, 0xa1, 0x1c, - 0xba, 0x1e, 0xf1, 0x68, 0xcb, 0x27, 0x5e, 0x3d, 0xf4, 0xa3, 0x98, 0xb4, 0x37, 0xc9, 0xe3, 0xc4, - 0x6f, 0x1d, 0x59, 0xcd, 0x16, 0x8d, 0x29, 0xc6, 0xa1, 0xeb, 0x59, 0x9d, 0x7b, 0x4b, 0xdc, 0x5b, - 0xed, 0x4d, 0xe3, 0xb6, 0x47, 0x59, 0x83, 0x32, 0xe2, 0x3a, 0xcc, 0x17, 0xc6, 0xa4, 0xbd, 0xe9, - 0xfa, 0xb1, 0xb3, 0x49, 0x9a, 0x4e, 0x10, 0x46, 0x4e, 0x1c, 0xd2, 0x48, 0xf8, 0x1b, 0x4b, 0x9a, - 0xf8, 0x32, 0x92, 0x30, 0xb8, 0x16, 0x50, 0x1a, 0xd4, 0x7d, 0xc2, 0xdf, 0xdc, 0xe4, 0x80, 0x38, - 0x91, 0xcc, 0x6d, 0xdc, 0x90, 0x57, 0x4e, 0x33, 0x24, 0x4e, 0x14, 0xd1, 0x98, 0x07, 0x66, 0xf2, - 0x76, 0x2e, 0xa0, 0x01, 0xe5, 0x8f, 0xa4, 0xf3, 0x24, 0x4e, 0xcd, 0x6d, 0x58, 0xfc, 0xa0, 0x83, - 0xe8, 0x2e, 0xcf, 0xf1, 0x61, 0xec, 0xc4, 0xbe, 0xed, 0x3f, 0x4e, 0x7c, 0x16, 0xe3, 0xeb, 0x70, - 0x59, 0x64, 0xde, 0x0f, 0x6b, 0x25, 0x54, 0x41, 0xab, 0x97, 0xed, 0x4b, 0xe2, 0xe0, 0x41, 0xcd, - 0x7c, 0x86, 0xa0, 0x34, 0xe8, 0xc8, 0x9a, 0x34, 0x62, 0x3e, 0xde, 0x81, 0xa2, 0xf4, 0x64, 0x9d, - 0x73, 0xee, 0x5c, 0xa8, 0xce, 0x59, 0x02, 0x9f, 0x95, 0x42, 0xb7, 0xde, 0x8d, 0x8e, 0xec, 0x82, - 0xd7, 0x0b, 0x80, 0xe7, 0xe0, 0x62, 0xb3, 0x45, 0xe9, 0x41, 0x69, 0xb2, 0x82, 0x56, 0x8b, 0xb6, - 0x78, 0xc1, 0x77, 0xa1, 0xc8, 0x1f, 0xf6, 0x0f, 0xfd, 0x30, 0x38, 0x8c, 0x4b, 0x17, 0x78, 0x38, - 0xc3, 0x1a, 0x94, 0xda, 0xba, 0xcf, 0x2d, 0xf6, 0xa6, 0x4e, 0xfe, 0x5c, 0x9a, 0xb0, 0x0b, 0xdc, - 0x4b, 0x1c, 0x99, 0xee, 0x20, 0x5e, 0x96, 0x32, 0xbd, 0x07, 0xd0, 0x2b, 0x84, 0x44, 0xfb, 0xba, - 0x25, 0xaa, 0x66, 0x75, 0xaa, 0x66, 0x89, 0x12, 0xcb, 0xaa, 0x59, 0x8f, 0x9c, 0x20, 0x55, 0xc9, - 0xce, 0x78, 0x9a, 0xbf, 0x23, 0xb8, 0xa6, 0x49, 0x22, 0x55, 0x89, 0xe0, 0x4a, 0x56, 0x15, 0x56, - 0x42, 0x95, 0x0b, 0xab, 0x85, 0xea, 0x2d, 0x1d, 0x8f, 0x07, 0x35, 0x3f, 0x8a, 0xc3, 0x83, 0xd0, - 0xaf, 0x65, 0x42, 0xed, 0x95, 0x3b, 0xb4, 0xbe, 0x7b, 0xb1, 0xb4, 0xa0, 0xbd, 0x66, 0x76, 0x31, - 0xa3, 0x25, 0xc3, 0xef, 0x29, 0xac, 0x26, 0x39, 0xab, 0x9b, 0x23, 0x59, 0x09, 0xb0, 0x0a, 0xad, - 0xef, 0x11, 0x18, 0x82, 0x56, 0xe7, 0x2a, 0x62, 0x09, 0xcb, 0xdd, 0x27, 0xf8, 0x26, 0xcc, 0xb6, - 0xfc, 0x76, 0xc8, 0x42, 0x1a, 0xed, 0x47, 0x49, 0xc3, 0xf5, 0x5b, 0x1c, 0xc9, 0x94, 0x3d, 0x93, - 0x1e, 0x3f, 0xe4, 0xa7, 0x8a, 0x61, 0xa6, 0xce, 0x19, 0x43, 0x51, 0x48, 0xbc, 0x02, 0x57, 0xea, - 0x1d, 0x7e, 0x71, 0x6a, 0x36, 0x55, 0x41, 0xab, 0x97, 0xec, 0xa2, 0x38, 0x94, 0xd5, 0xfe, 0x11, - 0xc1, 0x75, 0x2d, 0x64, 0x59, 0x8b, 0xb7, 0x61, 0xd6, 0x4b, 0x6f, 0x72, 0x34, 0xe9, 0x8c, 0xa7, - 0x84, 0xf9, 0x2f, 0xfb, 0xf4, 0xa9, 0x1e, 0x39, 0xcb, 0xa5, 0xf6, 0x3d, 0x4d, 0xc9, 0xff, 0x4d, - 0x23, 0xff, 0x8c, 0xe0, 0x86, 0x1e, 0x84, 0xd4, 0xef, 0x33, 0x78, 0xa5, 0x4f, 0xbf, 0xb4, 0x9d, - 0xd7, 0x74, 0x74, 0xd5, 0x30, 0x1f, 0x87, 0xf1, 0xa1, 0x22, 0xc0, 0xac, 0x2a, 0xef, 0x39, 0xb6, - 0xee, 0xe7, 0x08, 0x96, 0x35, 0x44, 0x44, 0xf6, 0xff, 0x57, 0xd3, 0x5f, 0x10, 0x98, 0x2f, 0x83, - 0x22, 0x95, 0xfd, 0x04, 0x16, 0xfb, 0x94, 0x95, 0xed, 0x94, 0x0a, 0x3c, 0xba, 0x9f, 0xe6, 0x3d, - 0x5d, 0x86, 0xf3, 0x13, 0x75, 0x67, 0x60, 0x94, 0x26, 0xb9, 0xa4, 0x34, 0xb7, 0x06, 0xc6, 0x63, - 0xd2, 0x23, 0xbe, 0x00, 0xd3, 0x8c, 0x9f, 0x48, 0x37, 0xf9, 0x66, 0x1a, 0x4a, 0xb6, 0x47, 0x4e, - 0xcb, 0x69, 0xa4, 0xd9, 0xcc, 0xf7, 0x95, 0x80, 0xe9, 0x9d, 0x0c, 0x58, 0x85, 0xe9, 0x26, 0x3f, - 0x91, 0x3f, 0x6d, 0xad, 0x70, 0xd2, 0x47, 0x5a, 0x9a, 0xcb, 0xb0, 0xc4, 0x03, 0x7e, 0xd4, 0x0c, - 0x5a, 0x4e, 0x4d, 0x19, 0xaf, 0x69, 0xce, 0x3a, 0x54, 0x86, 0x9b, 0xc8, 0xd4, 0xf7, 0x61, 0x3e, - 0x91, 0xd7, 0xfb, 0xb9, 0x37, 0xe1, 0xd5, 0x64, 0x30, 0xa2, 0xf9, 0x9a, 0x6c, 0x9a, 0x6e, 0x36, - 0xdd, 0x08, 0x36, 0x13, 0x58, 0x79, 0xa9, 0x95, 0x84, 0xf5, 0x10, 0x4a, 0x3d, 0x58, 0x63, 0x8c, - 0xbf, 0x85, 0x44, 0x1b, 0xb7, 0xfa, 0x6b, 0x11, 0x2e, 0xf2, 0xbc, 0xf8, 0x1b, 0x04, 0x85, 0x0c, - 0x6c, 0xfc, 0x86, 0x4e, 0xeb, 0x21, 0x1f, 0x1a, 0xc6, 0x5a, 0x3e, 0x63, 0x41, 0xc2, 0xbc, 0xf3, - 0xf4, 0xb7, 0xbf, 0xbf, 0x9a, 0x24, 0x78, 0x9d, 0x0c, 0xfd, 0x54, 0x92, 0x13, 0x89, 0x3c, 0xe9, - 0xb6, 0xe2, 0x31, 0xfe, 0x1a, 0x41, 0x31, 0xbb, 0x2c, 0x71, 0xae, 0xac, 0x69, 0xa7, 0x19, 0xeb, - 0x39, 0xad, 0x25, 0xc8, 0x5b, 0x1c, 0xe4, 0x0a, 0x5e, 0x1e, 0x09, 0x12, 0xbf, 0x40, 0x30, 0xa3, - 0xea, 0x8a, 0xad, 0xe1, 0xc9, 0x74, 0xe5, 0x37, 0x48, 0x6e, 0x7b, 0x09, 0xaf, 0xce, 0xe1, 0x1d, - 0xe0, 0x9a, 0x16, 0x5e, 0xdf, 0x60, 0xcf, 0xca, 0x48, 0xd2, 0x65, 0x4c, 0x9e, 0xf4, 0xad, 0xf5, - 0x63, 0x22, 0xc6, 0x54, 0xe6, 0x42, 0x1c, 0x1c, 0xe3, 0x67, 0x08, 0x66, 0xfb, 0x16, 0x09, 0xce, - 0x0b, 0xb9, 0x5b, 0x80, 0x8d, 0xfc, 0x0e, 0x92, 0xe4, 0x2e, 0x27, 0x59, 0xc5, 0x1b, 0xe3, 0x92, - 0xc4, 0x27, 0x08, 0xe6, 0xb5, 0x53, 0x1a, 0xdf, 0xc9, 0x89, 0x42, 0x5d, 0x30, 0xc6, 0xf6, 0xb8, - 0x6e, 0x92, 0xc2, 0x3b, 0x9c, 0xc2, 0x5b, 0x78, 0x37, 0x17, 0x05, 0xb9, 0x27, 0x14, 0x2a, 0xdf, - 0x2a, 0x6d, 0x9f, 0xe4, 0x6b, 0xfb, 0x64, 0xac, 0xb6, 0xef, 0xcd, 0xf0, 0xdc, 0xbf, 0xcd, 0x44, - 0x05, 0xf9, 0x45, 0x17, 0xa4, 0x18, 0xc7, 0x23, 0x41, 0x2a, 0x5b, 0x60, 0x24, 0x48, 0x75, 0x2f, - 0x98, 0xaf, 0x72, 0x90, 0x8b, 0x78, 0x5e, 0x80, 0xec, 0xe2, 0x13, 0x2b, 0x00, 0xff, 0x80, 0xe0, - 0xaa, 0x66, 0xb6, 0xe3, 0xad, 0xa1, 0x59, 0x86, 0x2f, 0x0b, 0xe3, 0xcd, 0xf1, 0x9c, 0x24, 0xc2, - 0x2a, 0x47, 0xb8, 0x86, 0x6f, 0xeb, 0x64, 0xd4, 0x2e, 0x16, 0x86, 0x7f, 0x42, 0xb0, 0xa0, 0x1f, - 0xff, 0x78, 0x7b, 0x34, 0x08, 0xed, 0x58, 0xd9, 0x19, 0xdb, 0x2f, 0x4f, 0x1b, 0x0c, 0xdb, 0x40, - 0x6c, 0xcf, 0x3e, 0x39, 0x2d, 0xa3, 0xe7, 0xa7, 0x65, 0xf4, 0xd7, 0x69, 0x19, 0x7d, 0x79, 0x56, - 0x9e, 0x78, 0x7e, 0x56, 0x9e, 0xf8, 0xe3, 0xac, 0x3c, 0xf1, 0xe9, 0x6e, 0x10, 0xc6, 0x87, 0x89, - 0x6b, 0x79, 0xb4, 0x41, 0xe4, 0x9f, 0xe9, 0xd0, 0xf5, 0xd6, 0x03, 0x4a, 0xda, 0x5b, 0xa4, 0x41, - 0x6b, 0x49, 0xdd, 0x67, 0x22, 0xcf, 0x46, 0x75, 0x5d, 0xa6, 0x8a, 0x8f, 0x9a, 0x3e, 0x73, 0xa7, - 0xf9, 0x22, 0xdb, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x80, 0xba, 0x64, 0xbc, 0xb8, 0x0f, 0x00, - 0x00, + // 1055 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0xa4, 0x69, 0xd4, 0x3e, 0xbb, 0x09, 0x9a, 0xe6, 0xc3, 0xdd, 0x16, 0xc7, 0xd9, 0x20, + 0x9a, 0x96, 0x64, 0x27, 0x71, 0x68, 0x12, 0x21, 0x21, 0x41, 0x2a, 0x95, 0xf6, 0x52, 0xca, 0x22, + 0x04, 0x42, 0x42, 0xd1, 0xee, 0x7a, 0xb2, 0x59, 0xc9, 0xde, 0x71, 0x3d, 0xbb, 0x96, 0xa2, 0x2a, + 0x97, 0x9e, 0x10, 0x27, 0x24, 0x24, 0xae, 0x48, 0x1c, 0x39, 0x54, 0x1c, 0x90, 0xb8, 0x72, 0x82, + 0x1c, 0x38, 0x54, 0x82, 0x03, 0x27, 0x8a, 0x12, 0xfe, 0x10, 0xe4, 0x99, 0x59, 0x7b, 0xd7, 0x1e, + 0xd7, 0x6b, 0x14, 0xb8, 0xed, 0xbe, 0xcf, 0xdf, 0xfb, 0xbd, 0xe7, 0xf7, 0xd6, 0x50, 0x0e, 0x5c, + 0x8f, 0x78, 0xac, 0x45, 0x89, 0x57, 0x0f, 0x68, 0x18, 0x91, 0xf6, 0x26, 0x79, 0x1c, 0xd3, 0xd6, + 0x91, 0xd5, 0x6c, 0xb1, 0x88, 0x61, 0x1c, 0xb8, 0x9e, 0xd5, 0xd1, 0x5b, 0x52, 0x6f, 0xb5, 0x37, + 0x8d, 0xdb, 0x1e, 0xe3, 0x0d, 0xc6, 0x89, 0xeb, 0x70, 0x2a, 0x8d, 0x49, 0x7b, 0xd3, 0xa5, 0x91, + 0xb3, 0x49, 0x9a, 0x8e, 0x1f, 0x84, 0x4e, 0x14, 0xb0, 0x50, 0xfa, 0x1b, 0x4b, 0x9a, 0xf8, 0x2a, + 0x92, 0x34, 0xb8, 0xe6, 0x33, 0xe6, 0xd7, 0x29, 0x11, 0x6f, 0x6e, 0x7c, 0x40, 0x9c, 0x50, 0xe5, + 0x36, 0x6e, 0x28, 0x95, 0xd3, 0x0c, 0x88, 0x13, 0x86, 0x2c, 0x12, 0x81, 0xb9, 0xd2, 0xce, 0xf9, + 0xcc, 0x67, 0xe2, 0x91, 0x74, 0x9e, 0xa4, 0xd4, 0xdc, 0x86, 0xc5, 0x0f, 0x3a, 0x88, 0xee, 0x8a, + 0x1c, 0x1f, 0x46, 0x4e, 0x44, 0x6d, 0xfa, 0x38, 0xa6, 0x3c, 0xc2, 0xd7, 0xe1, 0xb2, 0xcc, 0xbc, + 0x1f, 0xd4, 0x4a, 0xa8, 0x82, 0x56, 0x2f, 0xdb, 0x97, 0xa4, 0xe0, 0x41, 0xcd, 0x7c, 0x86, 0xa0, + 0x34, 0xe8, 0xc8, 0x9b, 0x2c, 0xe4, 0x14, 0xef, 0x40, 0x51, 0x79, 0xf2, 0x8e, 0x5c, 0x38, 0x17, + 0xaa, 0x73, 0x96, 0xc4, 0x67, 0x25, 0xd0, 0xad, 0x77, 0xc3, 0x23, 0xbb, 0xe0, 0xf5, 0x02, 0xe0, + 0x39, 0xb8, 0xd8, 0x6c, 0x31, 0x76, 0x50, 0x9a, 0xac, 0xa0, 0xd5, 0xa2, 0x2d, 0x5f, 0xf0, 0x5d, + 0x28, 0x8a, 0x87, 0xfd, 0x43, 0x1a, 0xf8, 0x87, 0x51, 0xe9, 0x82, 0x08, 0x67, 0x58, 0x83, 0x54, + 0x5b, 0xf7, 0x85, 0xc5, 0xde, 0xd4, 0xc9, 0x9f, 0x4b, 0x13, 0x76, 0x41, 0x78, 0x49, 0x91, 0xe9, + 0x0e, 0xe2, 0xe5, 0x49, 0xa5, 0xf7, 0x00, 0x7a, 0x8d, 0x50, 0x68, 0x5f, 0xb7, 0x64, 0xd7, 0xac, + 0x4e, 0xd7, 0x2c, 0xd9, 0x62, 0xd5, 0x35, 0xeb, 0x91, 0xe3, 0x27, 0x2c, 0xd9, 0x29, 0x4f, 0xf3, + 0x77, 0x04, 0xd7, 0x34, 0x49, 0x14, 0x2b, 0x21, 0x5c, 0x49, 0xb3, 0xc2, 0x4b, 0xa8, 0x72, 0x61, + 0xb5, 0x50, 0xbd, 0xa5, 0xab, 0xe3, 0x41, 0x8d, 0x86, 0x51, 0x70, 0x10, 0xd0, 0x5a, 0x2a, 0xd4, + 0x5e, 0xb9, 0x53, 0xd6, 0x77, 0x2f, 0x96, 0x16, 0xb4, 0x6a, 0x6e, 0x17, 0x53, 0x5c, 0x72, 0xfc, + 0x5e, 0xa6, 0xaa, 0x49, 0x51, 0xd5, 0xcd, 0x91, 0x55, 0x49, 0xb0, 0x99, 0xb2, 0xbe, 0x47, 0x60, + 0xc8, 0xb2, 0x3a, 0xaa, 0x90, 0xc7, 0x3c, 0xf7, 0x9c, 0xe0, 0x9b, 0x30, 0xdb, 0xa2, 0xed, 0x80, + 0x07, 0x2c, 0xdc, 0x0f, 0xe3, 0x86, 0x4b, 0x5b, 0x02, 0xc9, 0x94, 0x3d, 0x93, 0x88, 0x1f, 0x0a, + 0x69, 0xc6, 0x30, 0xd5, 0xe7, 0x94, 0xa1, 0x6c, 0x24, 0x5e, 0x81, 0x2b, 0xf5, 0x4e, 0x7d, 0x51, + 0x62, 0x36, 0x55, 0x41, 0xab, 0x97, 0xec, 0xa2, 0x14, 0xaa, 0x6e, 0xff, 0x88, 0xe0, 0xba, 0x16, + 0xb2, 0xea, 0xc5, 0xdb, 0x30, 0xeb, 0x25, 0x9a, 0x1c, 0x43, 0x3a, 0xe3, 0x65, 0xc2, 0xfc, 0x97, + 0x73, 0xfa, 0x54, 0x8f, 0x9c, 0xe7, 0x62, 0xfb, 0x9e, 0xa6, 0xe5, 0xff, 0x66, 0x90, 0x7f, 0x46, + 0x70, 0x43, 0x0f, 0x42, 0xf1, 0xf7, 0x19, 0xbc, 0xd2, 0xc7, 0x5f, 0x32, 0xce, 0x6b, 0xba, 0x72, + 0xb3, 0x61, 0x3e, 0x0e, 0xa2, 0xc3, 0x0c, 0x01, 0xb3, 0x59, 0x7a, 0xcf, 0x71, 0x74, 0x3f, 0x47, + 0xb0, 0xac, 0x29, 0x44, 0x66, 0xff, 0x7f, 0x39, 0xfd, 0x05, 0x81, 0xf9, 0x32, 0x28, 0x8a, 0xd9, + 0x4f, 0x60, 0xb1, 0x8f, 0x59, 0x35, 0x4e, 0x09, 0xc1, 0xa3, 0xe7, 0x69, 0xde, 0xd3, 0x65, 0x38, + 0x3f, 0x52, 0x77, 0x06, 0x56, 0x69, 0x9c, 0x8b, 0x4a, 0x73, 0x6b, 0x60, 0x3d, 0xc6, 0xbd, 0xc2, + 0x17, 0x60, 0x9a, 0x0b, 0x89, 0x72, 0x53, 0x6f, 0xa6, 0x91, 0xc9, 0xf6, 0xc8, 0x69, 0x39, 0x8d, + 0x24, 0x9b, 0xf9, 0x7e, 0x26, 0x60, 0xa2, 0x53, 0x01, 0xab, 0x30, 0xdd, 0x14, 0x12, 0xf5, 0xd3, + 0xd6, 0x12, 0xa7, 0x7c, 0x94, 0xa5, 0xb9, 0x0c, 0x4b, 0x22, 0xe0, 0x47, 0x4d, 0xbf, 0xe5, 0xd4, + 0x32, 0xeb, 0x35, 0xc9, 0x59, 0x87, 0xca, 0x70, 0x13, 0x95, 0xfa, 0x3e, 0xcc, 0xc7, 0x4a, 0xbd, + 0x9f, 0xfb, 0x12, 0x5e, 0x8d, 0x07, 0x23, 0x9a, 0xaf, 0xa9, 0xa1, 0xe9, 0x66, 0xd3, 0xad, 0x60, + 0x33, 0x86, 0x95, 0x97, 0x5a, 0x29, 0x58, 0x0f, 0xa1, 0xd4, 0x83, 0x35, 0xc6, 0xfa, 0x5b, 0x88, + 0xb5, 0x71, 0xab, 0xbf, 0x16, 0xe1, 0xa2, 0xc8, 0x8b, 0xbf, 0x41, 0x50, 0x48, 0xc1, 0xc6, 0x6f, + 0xe8, 0xb8, 0x1e, 0xf2, 0xa1, 0x61, 0xac, 0xe5, 0x33, 0x96, 0x45, 0x98, 0x77, 0x9e, 0xfe, 0xf6, + 0xf7, 0x57, 0x93, 0x04, 0xaf, 0x93, 0xa1, 0x9f, 0x4a, 0x6a, 0x23, 0x91, 0x27, 0xdd, 0x51, 0x3c, + 0xc6, 0x5f, 0x23, 0x28, 0xa6, 0x8f, 0x25, 0xce, 0x95, 0x35, 0x99, 0x34, 0x63, 0x3d, 0xa7, 0xb5, + 0x02, 0x79, 0x4b, 0x80, 0x5c, 0xc1, 0xcb, 0x23, 0x41, 0xe2, 0x17, 0x08, 0x66, 0xb2, 0xbc, 0x62, + 0x6b, 0x78, 0x32, 0x5d, 0xfb, 0x0d, 0x92, 0xdb, 0x5e, 0xc1, 0xab, 0x0b, 0x78, 0x07, 0xb8, 0xa6, + 0x85, 0xd7, 0xb7, 0xd8, 0xd3, 0x34, 0x92, 0xe4, 0x18, 0x93, 0x27, 0x7d, 0x67, 0xfd, 0x98, 0xc8, + 0x35, 0x95, 0x52, 0x48, 0xc1, 0x31, 0x7e, 0x86, 0x60, 0xb6, 0xef, 0x90, 0xe0, 0xbc, 0x90, 0xbb, + 0x0d, 0xd8, 0xc8, 0xef, 0xa0, 0x8a, 0xdc, 0x15, 0x45, 0x56, 0xf1, 0xc6, 0xb8, 0x45, 0xe2, 0x13, + 0x04, 0xf3, 0xda, 0x2d, 0x8d, 0xef, 0xe4, 0x44, 0x91, 0x3d, 0x30, 0xc6, 0xf6, 0xb8, 0x6e, 0xaa, + 0x84, 0x77, 0x44, 0x09, 0x6f, 0xe1, 0xdd, 0xb1, 0xfb, 0xa4, 0x6e, 0x06, 0xfe, 0x36, 0x33, 0xf6, + 0x71, 0xbe, 0xb1, 0x8f, 0xc7, 0x1a, 0xfb, 0xde, 0x0e, 0xcf, 0xfd, 0xdb, 0x8c, 0xb3, 0x7c, 0x7f, + 0xd1, 0x05, 0x29, 0xd7, 0xf1, 0x48, 0x90, 0x99, 0x2b, 0x30, 0x12, 0x64, 0xf6, 0x2e, 0x98, 0xaf, + 0x0a, 0x90, 0x8b, 0x78, 0x5e, 0x82, 0xec, 0xe2, 0x93, 0x27, 0x00, 0xff, 0x80, 0xe0, 0xaa, 0x66, + 0xb7, 0xe3, 0xad, 0xa1, 0x59, 0x86, 0x1f, 0x0b, 0xe3, 0xcd, 0xf1, 0x9c, 0x14, 0xc2, 0xaa, 0x40, + 0xb8, 0x86, 0x6f, 0xeb, 0x68, 0xd4, 0x1e, 0x16, 0x8e, 0x7f, 0x42, 0xb0, 0xa0, 0x5f, 0xff, 0x78, + 0x7b, 0x34, 0x08, 0xed, 0x5a, 0xd9, 0x19, 0xdb, 0x2f, 0xcf, 0x18, 0x0c, 0xbb, 0x40, 0x7c, 0xcf, + 0x3e, 0x39, 0x2d, 0xa3, 0xe7, 0xa7, 0x65, 0xf4, 0xd7, 0x69, 0x19, 0x7d, 0x79, 0x56, 0x9e, 0x78, + 0x7e, 0x56, 0x9e, 0xf8, 0xe3, 0xac, 0x3c, 0xf1, 0xe9, 0xae, 0x1f, 0x44, 0x87, 0xb1, 0x6b, 0x79, + 0xac, 0x41, 0xd4, 0x9f, 0xe9, 0xc0, 0xf5, 0xd6, 0x7d, 0x46, 0xda, 0x5b, 0xa4, 0xc1, 0x6a, 0x71, + 0x9d, 0x72, 0x99, 0x67, 0xa3, 0xba, 0xae, 0x52, 0x45, 0x47, 0x4d, 0xca, 0xdd, 0x69, 0x71, 0xc8, + 0xb6, 0xfe, 0x09, 0x00, 0x00, 0xff, 0xff, 0x42, 0x17, 0xfc, 0x54, 0xb8, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/02-client/types/query.pb.gw.go b/modules/core/02-client/types/query.pb.gw.go index 7bc1177962b..4286cc772ae 100644 --- a/modules/core/02-client/types/query.pb.gw.go +++ b/modules/core/02-client/types/query.pb.gw.go @@ -908,7 +908,7 @@ var ( pattern_Query_ConsensusStates_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "client", "v1", "consensus_states", "client_id"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_ConsensusStateHeights_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"ibc", "core", "client", "v1", "consensus_states", "heights", "client_id"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_ConsensusStateHeights_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"ibc", "core", "client", "v1", "consensus_states", "client_id", "heights"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_ClientStatus_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"ibc", "core", "client", "v1", "client_status", "client_id"}, "", runtime.AssumeColonVerbOpt(true))) diff --git a/proto/ibc/core/client/v1/query.proto b/proto/ibc/core/client/v1/query.proto index 72c4fa0e3d7..33a4191cd06 100644 --- a/proto/ibc/core/client/v1/query.proto +++ b/proto/ibc/core/client/v1/query.proto @@ -38,7 +38,7 @@ service Query { // ConsensusStateHeights queries the height of every consensus states associated with a given client. rpc ConsensusStateHeights(QueryConsensusStateHeightsRequest) returns (QueryConsensusStateHeightsResponse) { - option (google.api.http).get = "/ibc/core/client/v1/consensus_states/heights/{client_id}"; + option (google.api.http).get = "/ibc/core/client/v1/consensus_states/{client_id}/heights"; } // Status queries the status of an IBC client. From 1370784fefb9f24cddb748c6cc3746a0a78688de Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sat, 11 Jun 2022 22:25:36 +0200 Subject: [PATCH 153/275] Update adr-026-ibc-client-recovery-mechanisms.md --- docs/architecture/adr-026-ibc-client-recovery-mechanisms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md b/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md index 27bcb33e545..516002ed1b9 100644 --- a/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md +++ b/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md @@ -49,7 +49,7 @@ We elect not to deal with chains which have actually halted, which is necessaril 1. The second client is a substitute client. It carries all the state for the client which may be updated. It must have identitical client and chain parameters to the client which may be updated (except for latest height, frozen height, and chain-id). It should be continually updated during the voting period. 1. If this governance proposal passes, the client on trial will be updated to the latest state of the substitute. - Previously, AllowUpdateAfterExpiry and AllowUpdateAfterMisbehaviour were used to signal the recovery options for an expired or frozen client, and governance proposals were not allowed to overwrite the client if these parameters were set to false. However, this has now been deprecated because a code migration can overwrite the client and consensus states regardless of the value of these parameters. If governance would vote to overwrite a client or consensus state, it is likely that governance would also willing to perform a code migration to do the same. + Previously, `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehaviour` were used to signal the recovery options for an expired or frozen client, and governance proposals were not allowed to overwrite the client if these parameters were set to false. However, this has now been deprecated because a code migration can overwrite the client and consensus states regardless of the value of these parameters. If governance would vote to overwrite a client or consensus state, it is likely that governance would also be willing to perform a code migration to do the same. Note that clients frozen due to misbehaviour must wait for the evidence to expire to avoid becoming refrozen. From 11297aaa61e651c16e6d4147a15be24ce55ba7cc Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Mon, 13 Jun 2022 11:59:39 +0100 Subject: [PATCH 154/275] Skip distribution if refund fails to send on channel closure (#1523) --- CHANGELOG.md | 3 ++- modules/apps/29-fee/ibc_middleware_test.go | 8 +++---- modules/apps/29-fee/keeper/escrow.go | 19 +++++++-------- modules/apps/29-fee/keeper/escrow_test.go | 28 +++++++++++++--------- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31ca5c1539f..ff0d73923e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,7 +79,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output -* (apps/29-fee) [\#1278](https://github.com/cosmos/ibc-go/pull/1278) The URI path for the query to get all incentivized packets for a specifc channel did not follow the same format as the rest of queries. +* (apps/29-fee) [\#1278](https://github.com/cosmos/ibc-go/pull/1278) The URI path for the query to get all incentivized packets for a specific channel did not follow the same format as the rest of queries. +* (apps/29-fee)[\#1343](https://github.com/cosmos/ibc-go/pull/1523) Fixed an issue where a bad refund address would prevent channel closure. ## [v3.0.0](https://github.com/cosmos/ibc-go/releases/tag/v3.0.0) - 2022-03-15 diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 17a961d0074..37cfaf2f948 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -345,7 +345,7 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { }, false, }, { - "RefundFeesOnChannelClosure fails - invalid refund address", func() { + "RefundFeesOnChannelClosure continues - invalid refund address", func() { // store the fee in state & update escrow account balance packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) @@ -354,7 +354,7 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) suite.Require().NoError(err) }, - false, + true, }, { "fee module locked", func() { @@ -434,7 +434,7 @@ func (suite *FeeTestSuite) TestOnChanCloseConfirm() { }, false, }, { - "RefundChannelFeesOnClosure fails - refund address is invalid", func() { + "RefundChannelFeesOnClosure continues - refund address is invalid", func() { // store the fee in state & update escrow account balance packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) @@ -443,7 +443,7 @@ func (suite *FeeTestSuite) TestOnChanCloseConfirm() { err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, fee.Total()) suite.Require().NoError(err) }, - false, + true, }, { "fee module locked", func() { diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 130ac18e1b3..9755fb45e8d 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -194,6 +194,7 @@ func (k Keeper) RefundFeesOnChannelClosure(ctx sdk.Context, portID, channelID st cacheCtx, writeFn := ctx.CacheContext() for _, identifiedPacketFee := range identifiedPacketFees { + var failedToSendCoins bool for _, packetFee := range identifiedPacketFee.PacketFees { if !k.EscrowAccountHasBalance(cacheCtx, packetFee.Fee.Total()) { @@ -211,24 +212,20 @@ func (k Keeper) RefundFeesOnChannelClosure(ctx sdk.Context, portID, channelID st refundAddr, err := sdk.AccAddressFromBech32(packetFee.RefundAddress) if err != nil { - return err - } - - // if the refund address is blocked, skip and continue distribution - if k.bankKeeper.BlockedAddr(refundAddr) { + failedToSendCoins = true continue } // refund all fees to refund address - // Use SendCoins rather than the module account send functions since refund address may be a user account or module address. - moduleAcc := k.GetFeeModuleAddress() - if err = k.bankKeeper.SendCoins(cacheCtx, moduleAcc, refundAddr, packetFee.Fee.Total()); err != nil { - return err + if err = k.bankKeeper.SendCoinsFromModuleToAccount(cacheCtx, types.ModuleName, refundAddr, packetFee.Fee.Total()); err != nil { + failedToSendCoins = true + continue } - } - k.DeleteFeesInEscrow(cacheCtx, identifiedPacketFee.PacketId) + if !failedToSendCoins { + k.DeleteFeesInEscrow(cacheCtx, identifiedPacketFee.PacketId) + } } // NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context. diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 9b67934c647..7ccf87aa91b 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -2,11 +2,10 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/tendermint/tendermint/crypto/secp256k1" ) func (suite *KeeperTestSuite) TestDistributeFee() { @@ -277,12 +276,13 @@ func (suite *KeeperTestSuite) TestDistributePacketFeesOnTimeout() { func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { var ( - expIdentifiedPacketFees []types.IdentifiedPacketFees - expEscrowBal sdk.Coins - expRefundBal sdk.Coins - refundAcc sdk.AccAddress - fee types.Fee - locked bool + expIdentifiedPacketFees []types.IdentifiedPacketFees + expEscrowBal sdk.Coins + expRefundBal sdk.Coins + refundAcc sdk.AccAddress + fee types.Fee + locked bool + expectEscrowFeesToBeDeleted bool ) testCases := []struct { @@ -375,6 +375,7 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { { "invalid refund acc address", func() { // store the fee in state & update escrow account balance + expectEscrowFeesToBeDeleted = false packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, uint64(1)) packetFees := types.NewPacketFees([]types.PacketFee{types.NewPacketFee(fee, "invalid refund address", nil)}) identifiedPacketFees := types.NewIdentifiedPacketFees(packetID, packetFees.PacketFees) @@ -385,10 +386,14 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.Require().NoError(err) expIdentifiedPacketFees = []types.IdentifiedPacketFees{identifiedPacketFees} - }, false, + + expEscrowBal = fee.Total() + expRefundBal = expRefundBal.Sub(fee.Total()) + }, true, }, { "distributing to blocked address is skipped", func() { + expectEscrowFeesToBeDeleted = false blockedAddr := suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() // store the fee in state & update escrow account balance @@ -418,6 +423,7 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { expIdentifiedPacketFees = []types.IdentifiedPacketFees{} expEscrowBal = sdk.Coins{} locked = false + expectEscrowFeesToBeDeleted = true // setup refundAcc = suite.chainA.SenderAccount.GetAddress() @@ -464,8 +470,8 @@ func (suite *KeeperTestSuite) TestRefundFeesOnChannelClosure() { suite.Require().Equal(expEscrowBal, escrowBal) // escrow balance should be empty suite.Require().Equal(expRefundBal, refundBal) // all packets should have been refunded - // all fees in escrow should be deleted for this channel - suite.Require().Empty(suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + // all fees in escrow should be deleted if expected for this channel + suite.Require().Equal(expectEscrowFeesToBeDeleted, len(suite.chainA.GetSimApp().IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) == 0) } }) } From ead32f60c616ccd2b457d508a87f41279632ae83 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 14 Jun 2022 11:22:25 +0100 Subject: [PATCH 155/275] Build simd images as part of the release process (#1533) --- .github/workflows/release.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 479d90a432e..4b42de16645 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,10 @@ on: - 'v[0-9]+.[0-9]+.[0-9]+' # Push events to matching v*, i.e. v1.0.0, v20.15.10 - 'v[0-9]+.[0-9]+.[0-9]+-?[a-z0-9]+' # Push events to matching v*-[alpha/beta/rc], i.e. v3.0.0-alpha1, v3.0.0-beta1, v3.0.0-rc0 +env: + REGISTRY: ghcr.io + IMAGE_NAME: ibc-go-simd + jobs: goreleaser: runs-on: ubuntu-latest @@ -27,3 +31,24 @@ jobs: args: release --rm-dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to the Container registry + uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: ${{ env.REGISTRY }}/cosmos/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From dab07f9399adb66b45dd30286bc51470b1c8593d Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 14 Jun 2022 12:50:46 +0200 Subject: [PATCH 156/275] refactor: rename RegisterCounterpartyAddress rpc to RegisterCounterpartyPayee (#1513) * renaming counterparty address rpc to counterparty payee * updating counterparty payee cli * reorder cli cmd list * Apply suggestions from code review Co-authored-by: Charly * removing address suffix from msg fields, updating protodoc and godoc * updating cli args naming convention to align * updating keys to reflect naming changes * updating docs * updating protodocs and godocs Co-authored-by: Charly Co-authored-by: Carlos Rodriguez --- docs/ibc/proto-docs.md | 28 +- modules/apps/29-fee/client/cli/cli.go | 2 +- modules/apps/29-fee/client/cli/tx.go | 52 +-- modules/apps/29-fee/ibc_middleware.go | 2 +- modules/apps/29-fee/ibc_middleware_test.go | 6 +- modules/apps/29-fee/ica_test.go | 2 +- modules/apps/29-fee/keeper/genesis.go | 2 +- modules/apps/29-fee/keeper/genesis_test.go | 4 +- modules/apps/29-fee/keeper/grpc_query.go | 2 +- modules/apps/29-fee/keeper/grpc_query_test.go | 2 +- modules/apps/29-fee/keeper/keeper.go | 24 +- modules/apps/29-fee/keeper/keeper_test.go | 2 +- modules/apps/29-fee/keeper/msg_server.go | 28 +- modules/apps/29-fee/keeper/msg_server_test.go | 48 ++- modules/apps/29-fee/keeper/relay.go | 2 +- modules/apps/29-fee/keeper/relay_test.go | 2 +- modules/apps/29-fee/transfer_test.go | 2 +- modules/apps/29-fee/types/codec.go | 6 +- modules/apps/29-fee/types/errors.go | 2 +- modules/apps/29-fee/types/genesis.go | 2 +- modules/apps/29-fee/types/keys.go | 24 +- modules/apps/29-fee/types/keys_test.go | 22 +- modules/apps/29-fee/types/msgs.go | 55 ++- modules/apps/29-fee/types/msgs_test.go | 32 +- modules/apps/29-fee/types/tx.pb.go | 330 +++++++++--------- .../07-tendermint/types/tendermint.pb.go | 130 +++---- proto/ibc/applications/fee/v1/tx.proto | 42 +-- 27 files changed, 433 insertions(+), 422 deletions(-) diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 6080f32d60e..9d0cf13eb4e 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -73,8 +73,8 @@ - [MsgPayPacketFeeAsync](#ibc.applications.fee.v1.MsgPayPacketFeeAsync) - [MsgPayPacketFeeAsyncResponse](#ibc.applications.fee.v1.MsgPayPacketFeeAsyncResponse) - [MsgPayPacketFeeResponse](#ibc.applications.fee.v1.MsgPayPacketFeeResponse) - - [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress) - - [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse) + - [MsgRegisterCounterpartyPayee](#ibc.applications.fee.v1.MsgRegisterCounterpartyPayee) + - [MsgRegisterCounterpartyPayeeResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyPayeeResponse) - [MsgRegisterPayee](#ibc.applications.fee.v1.MsgRegisterPayee) - [MsgRegisterPayeeResponse](#ibc.applications.fee.v1.MsgRegisterPayeeResponse) @@ -1342,28 +1342,28 @@ MsgPayPacketFeeResponse defines the response type for the PayPacketFee rpc - + -### MsgRegisterCounterpartyAddress -MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc +### MsgRegisterCounterpartyPayee +MsgRegisterCounterpartyPayee defines the request type for the RegisterCounterpartyPayee rpc | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `address` | [string](#string) | | the relayer address | -| `counterparty_address` | [string](#string) | | the counterparty relayer address | | `port_id` | [string](#string) | | unique port identifier | | `channel_id` | [string](#string) | | unique channel identifier | +| `relayer` | [string](#string) | | the relayer address | +| `counterparty_payee` | [string](#string) | | the counterparty payee address | - + -### MsgRegisterCounterpartyAddressResponse -MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc +### MsgRegisterCounterpartyPayeeResponse +MsgRegisterCounterpartyPayeeResponse defines the response type for the RegisterCounterpartyPayee rpc @@ -1380,8 +1380,8 @@ MsgRegisterPayee defines the request type for the RegisterPayee rpc | ----- | ---- | ----- | ----------- | | `port_id` | [string](#string) | | unique port identifier | | `channel_id` | [string](#string) | | unique channel identifier | -| `relayer_address` | [string](#string) | | the relayer address | -| `payee` | [string](#string) | | the fee payee address | +| `relayer` | [string](#string) | | the relayer address | +| `payee` | [string](#string) | | the payee address | @@ -1411,8 +1411,8 @@ Msg defines the ICS29 Msg service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `RegisterPayee` | [MsgRegisterPayee](#ibc.applications.fee.v1.MsgRegisterPayee) | [MsgRegisterPayeeResponse](#ibc.applications.fee.v1.MsgRegisterPayeeResponse) | RegisterPayee defines a rpc handler method for MsgRegisterPayee RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which packets originate as this is where fee distribution takes place. This function may be called more than once by a relayer, in which case, the latest payee is always used. | | -| `RegisterCounterpartyAddress` | [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress) | [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse) | RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying. This ensures they will be properly compensated for forward relaying since destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function may be called more than once by a relayer, in which case, the latest counterparty address is always used. | | +| `RegisterPayee` | [MsgRegisterPayee](#ibc.applications.fee.v1.MsgRegisterPayee) | [MsgRegisterPayeeResponse](#ibc.applications.fee.v1.MsgRegisterPayeeResponse) | RegisterPayee defines a rpc handler method for MsgRegisterPayee RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on the source chain from which packets originate as this is where fee distribution takes place. This function may be called more than once by a relayer, in which case, the latest payee is always used. | | +| `RegisterCounterpartyPayee` | [MsgRegisterCounterpartyPayee](#ibc.applications.fee.v1.MsgRegisterCounterpartyPayee) | [MsgRegisterCounterpartyPayeeResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyPayeeResponse) | RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty payee address before relaying. This ensures they will be properly compensated for forward relaying since the destination chain must include the registered counterparty payee address in the acknowledgement. This function may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. | | | `PayPacketFee` | [MsgPayPacketFee](#ibc.applications.fee.v1.MsgPayPacketFee) | [MsgPayPacketFeeResponse](#ibc.applications.fee.v1.MsgPayPacketFeeResponse) | PayPacketFee defines a rpc handler method for MsgPayPacketFee PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to incentivize the relaying of the packet at the next sequence NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows initiates the lifecycle of the incentivized packet | | | `PayPacketFeeAsync` | [MsgPayPacketFeeAsync](#ibc.applications.fee.v1.MsgPayPacketFeeAsync) | [MsgPayPacketFeeAsyncResponse](#ibc.applications.fee.v1.MsgPayPacketFeeAsyncResponse) | PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to incentivize the relaying of a known packet (i.e. at a particular sequence) | | diff --git a/modules/apps/29-fee/client/cli/cli.go b/modules/apps/29-fee/client/cli/cli.go index fdf5d3ffbb9..d609104ba67 100644 --- a/modules/apps/29-fee/client/cli/cli.go +++ b/modules/apps/29-fee/client/cli/cli.go @@ -42,8 +42,8 @@ func NewTxCmd() *cobra.Command { txCmd.AddCommand( NewRegisterPayeeCmd(), + NewRegisterCounterpartyPayeeCmd(), NewPayPacketFeeAsyncTxCmd(), - NewRegisterCounterpartyAddressCmd(), ) return txCmd diff --git a/modules/apps/29-fee/client/cli/tx.go b/modules/apps/29-fee/client/cli/tx.go index 24f84731d88..ef038ac7fd5 100644 --- a/modules/apps/29-fee/client/cli/tx.go +++ b/modules/apps/29-fee/client/cli/tx.go @@ -25,7 +25,7 @@ const ( // NewRegisterPayeeCmd returns the command to create a MsgRegisterPayee func NewRegisterPayeeCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "register-payee [port-id] [channel-id] [relayer-address] [payee-address] ", + Use: "register-payee [port-id] [channel-id] [relayer] [payee] ", Short: "Register a payee on a given channel.", Long: strings.TrimSpace(`Register a payee address on a given channel.`), Example: fmt.Sprintf("%s tx ibc-fee register-payee transfer channel-0 cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5", version.AppName), @@ -47,6 +47,31 @@ func NewRegisterPayeeCmd() *cobra.Command { return cmd } +// NewRegisterCounterpartyPayeeCmd returns the command to create a MsgRegisterCounterpartyPayee +func NewRegisterCounterpartyPayeeCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "register-counterparty-payee [port-id] [channel-id] [relayer] [counterparty-payee] ", + Short: "Register a counterparty payee address on a given channel.", + Long: strings.TrimSpace(`Register a counterparty payee address on a given channel.`), + Example: fmt.Sprintf("%s tx ibc-fee register-counterparty-payee transfer channel-0 cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2", version.AppName), + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgRegisterCounterpartyPayee(args[0], args[1], args[2], args[3]) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + // NewPayPacketFeeAsyncTxCmd returns the command to create a MsgPayPacketFeeAsync func NewPayPacketFeeAsyncTxCmd() *cobra.Command { cmd := &cobra.Command{ @@ -122,28 +147,3 @@ func NewPayPacketFeeAsyncTxCmd() *cobra.Command { return cmd } - -// NewRegisterCounterpartyAddressCmd returns the command to create a MsgRegisterCounterpartyAddress -func NewRegisterCounterpartyAddressCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "register-counterparty [port-id] [channel-id] [address] [counterparty-address] ", - Short: "Register a counterparty relayer address on a given channel.", - Long: strings.TrimSpace(`Register a counterparty relayer address on a given channel.`), - Example: fmt.Sprintf("%s tx ibc-fee register-counterparty transfer channel-0 cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2", version.AppName), - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - msg := types.NewMsgRegisterCounterpartyAddress(args[0], args[1], args[2], args[3]) - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - flags.AddTxFlagsToCmd(cmd) - - return cmd -} diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index d5cc6f4cfca..d9161d7caba 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -231,7 +231,7 @@ func (im IBCMiddleware) OnRecvPacket( } // if forwardRelayer is not found we refund recv_fee - forwardRelayer, _ := im.keeper.GetCounterpartyAddress(ctx, relayer.String(), packet.GetDestChannel()) + forwardRelayer, _ := im.keeper.GetCounterpartyPayeeAddress(ctx, relayer.String(), packet.GetDestChannel()) return types.NewIncentivizedAcknowledgement(forwardRelayer, ack.Acknowledgement(), ack.Success()) } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 37cfaf2f948..1aa8810453e 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -539,7 +539,7 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { { "forward address is not found", func() { - suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), "", suite.path.EndpointB.ChannelID) + suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), "", suite.path.EndpointB.ChannelID) }, false, true, @@ -566,7 +566,7 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { cbs, ok := suite.chainB.App.GetIBCKeeper().Router.GetRoute(module) suite.Require().True(ok) - suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) + suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) // malleate test case tc.malleate() @@ -575,7 +575,7 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { switch { case tc.name == "success": - forwardAddr, _ := suite.chainB.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) + forwardAddr, _ := suite.chainB.GetSimApp().IBCFeeKeeper.GetCounterpartyPayeeAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) expectedAck := types.IncentivizedAcknowledgement{ AppAcknowledgement: ibcmock.MockAcknowledgement.Acknowledgement(), diff --git a/modules/apps/29-fee/ica_test.go b/modules/apps/29-fee/ica_test.go index 88b3d088412..d8cd4e4ce05 100644 --- a/modules/apps/29-fee/ica_test.go +++ b/modules/apps/29-fee/ica_test.go @@ -102,7 +102,7 @@ func (suite *FeeTestSuite) TestFeeInterchainAccounts() { suite.Require().True(suite.chainB.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) // register counterparty address on destination chainB as chainA.SenderAccounts[1] for recv fee distribution - suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), path.EndpointB.ChannelID) + suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), path.EndpointB.ChannelID) // escrow a packet fee for the next send sequence expectedFee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) diff --git a/modules/apps/29-fee/keeper/genesis.go b/modules/apps/29-fee/keeper/genesis.go index c4be3a9d027..eb7b1fd7095 100644 --- a/modules/apps/29-fee/keeper/genesis.go +++ b/modules/apps/29-fee/keeper/genesis.go @@ -13,7 +13,7 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { } for _, relayer := range state.RegisteredRelayers { - k.SetCounterpartyAddress(ctx, relayer.Address, relayer.CounterpartyAddress, relayer.ChannelId) + k.SetCounterpartyPayeeAddress(ctx, relayer.Address, relayer.CounterpartyAddress, relayer.ChannelId) } for _, forwardAddr := range state.ForwardRelayers { diff --git a/modules/apps/29-fee/keeper/genesis_test.go b/modules/apps/29-fee/keeper/genesis_test.go index 7cd2e5bd1a6..05b8c907bb4 100644 --- a/modules/apps/29-fee/keeper/genesis_test.go +++ b/modules/apps/29-fee/keeper/genesis_test.go @@ -56,7 +56,7 @@ func (suite *KeeperTestSuite) TestInitGenesis() { suite.Require().True(isEnabled) // check relayers - addr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) + addr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) suite.Require().True(found) suite.Require().Equal(genesisState.RegisteredRelayers[0].CounterpartyAddress, addr) @@ -82,7 +82,7 @@ func (suite *KeeperTestSuite) TestExportGenesis() { sender := suite.chainA.SenderAccount.GetAddress().String() counterparty := suite.chainB.SenderAccount.GetAddress().String() // set counterparty address - suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID) + suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID) // set forward relayer address suite.chainA.GetSimApp().IBCFeeKeeper.SetRelayerAddressForAsyncAck(suite.chainA.GetContext(), packetID, sender) diff --git a/modules/apps/29-fee/keeper/grpc_query.go b/modules/apps/29-fee/keeper/grpc_query.go index 2df2b1823c9..ec8bf2ea656 100644 --- a/modules/apps/29-fee/keeper/grpc_query.go +++ b/modules/apps/29-fee/keeper/grpc_query.go @@ -197,7 +197,7 @@ func (k Keeper) CounterpartyAddress(goCtx context.Context, req *types.QueryCount ctx := sdk.UnwrapSDKContext(goCtx) - counterpartyAddr, found := k.GetCounterpartyAddress(ctx, req.RelayerAddress, req.ChannelId) + counterpartyAddr, found := k.GetCounterpartyPayeeAddress(ctx, req.RelayerAddress, req.ChannelId) if !found { return nil, status.Errorf(codes.NotFound, "counterparty address not found for address: %s on channel: %s", req.RelayerAddress, req.ChannelId) } diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index dc345fa06eb..2f7b4f3f4bc 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -508,7 +508,7 @@ func (suite *KeeperTestSuite) TestQueryCounterpartyAddress() { pk := secp256k1.GenPrivKey().PubKey() expectedCounterpartyAddr := sdk.AccAddress(pk.Address()) - suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress( + suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress( suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), expectedCounterpartyAddr.String(), diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index 311bee5eb69..c8ccc9a0e6c 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -150,7 +150,7 @@ func (k Keeper) GetAllFeeEnabledChannels(ctx sdk.Context) []types.FeeEnabledChan // GetPayeeAddress retrieves the fee payee address stored in state given the provided channel identifier and relayer address func (k Keeper) GetPayeeAddress(ctx sdk.Context, relayerAddr, channelID string) (string, bool) { store := ctx.KVStore(k.storeKey) - key := types.KeyPayeeAddress(relayerAddr, channelID) + key := types.KeyPayee(relayerAddr, channelID) if !store.Has(key) { return "", false @@ -162,13 +162,13 @@ func (k Keeper) GetPayeeAddress(ctx sdk.Context, relayerAddr, channelID string) // SetPayeeAddress stores the fee payee address in state keyed by the provided channel identifier and relayer address func (k Keeper) SetPayeeAddress(ctx sdk.Context, relayerAddr, payeeAddr, channelID string) { store := ctx.KVStore(k.storeKey) - store.Set(types.KeyPayeeAddress(relayerAddr, channelID), []byte(payeeAddr)) + store.Set(types.KeyPayee(relayerAddr, channelID), []byte(payeeAddr)) } // GetAllPayeeAddresses returns all registered payees func (k Keeper) GetAllPayeeAddresses(ctx sdk.Context) []types.RegisteredPayee { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte(types.PayeeAddressKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.PayeeKeyPrefix)) defer iterator.Close() var registeredPayees []types.RegisteredPayee @@ -190,17 +190,17 @@ func (k Keeper) GetAllPayeeAddresses(ctx sdk.Context) []types.RegisteredPayee { return registeredPayees } -// SetCounterpartyAddress maps the destination chain relayer address to the source relayer address -// The receiving chain must store the mapping from: address -> counterpartyAddress for the given channel -func (k Keeper) SetCounterpartyAddress(ctx sdk.Context, address, counterpartyAddress, channelID string) { +// SetCounterpartyPayeeAddress maps the destination chain counterparty payee address to the source relayer address +// The receiving chain must store the mapping from: address -> counterpartyPayeeAddress for the given channel +func (k Keeper) SetCounterpartyPayeeAddress(ctx sdk.Context, address, counterpartyAddress, channelID string) { store := ctx.KVStore(k.storeKey) - store.Set(types.KeyCounterpartyRelayer(address, channelID), []byte(counterpartyAddress)) + store.Set(types.KeyCounterpartyPayee(address, channelID), []byte(counterpartyAddress)) } -// GetCounterpartyAddress gets the relayer counterparty address given a destination relayer address -func (k Keeper) GetCounterpartyAddress(ctx sdk.Context, address, channelID string) (string, bool) { +// GetCounterpartyPayeeAddress gets the counterparty payee address given a destination relayer address +func (k Keeper) GetCounterpartyPayeeAddress(ctx sdk.Context, address, channelID string) (string, bool) { store := ctx.KVStore(k.storeKey) - key := types.KeyCounterpartyRelayer(address, channelID) + key := types.KeyCounterpartyPayee(address, channelID) if !store.Has(key) { return "", false @@ -213,12 +213,12 @@ func (k Keeper) GetCounterpartyAddress(ctx sdk.Context, address, channelID strin // GetAllRelayerAddresses returns all registered relayer addresses func (k Keeper) GetAllRelayerAddresses(ctx sdk.Context) []types.RegisteredRelayerAddress { store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, []byte(types.CounterpartyRelayerAddressKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte(types.CounterpartyPayeeKeyPrefix)) defer iterator.Close() var registeredAddrArr []types.RegisteredRelayerAddress for ; iterator.Valid(); iterator.Next() { - address, channelID, err := types.ParseKeyCounterpartyRelayer(string(iterator.Key())) + address, channelID, err := types.ParseKeyCounterpartyPayee(string(iterator.Key())) if err != nil { panic(err) } diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index 1b26fe6ac5e..b322cb07c60 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -262,7 +262,7 @@ func (suite *KeeperTestSuite) TestGetAllRelayerAddresses() { sender := suite.chainA.SenderAccount.GetAddress().String() counterparty := suite.chainB.SenderAccount.GetAddress().String() - suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID) + suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID) expectedAddr := []types.RegisteredRelayerAddress{ { diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index 0dfc8cb9a10..fe7af407d2f 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -14,9 +14,9 @@ var _ types.MsgServer = Keeper{} // RegisterPayee defines a rpc handler method for MsgRegisterPayee // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional -// payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which -// packets originate as this is where fee distribution takes place. This function may be called more than once by a relayer, -// in which case, the latest payee is always used. +// payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on +// the source chain from which packets originate as this is where fee distribution takes place. This function may be +// called more than once by a relayer, in which case, the latest payee is always used. func (k Keeper) RegisterPayee(goCtx context.Context, msg *types.MsgRegisterPayee) (*types.MsgRegisterPayeeResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -29,20 +29,22 @@ func (k Keeper) RegisterPayee(goCtx context.Context, msg *types.MsgRegisterPayee return nil, types.ErrFeeNotEnabled } - k.SetPayeeAddress(ctx, msg.RelayerAddress, msg.Payee, msg.ChannelId) + k.SetPayeeAddress(ctx, msg.Relayer, msg.Payee, msg.ChannelId) - k.Logger(ctx).Info("registering payee address for relayer", "relayer address", msg.RelayerAddress, "payee address", msg.Payee, "channel", msg.ChannelId) + k.Logger(ctx).Info("registering payee address for relayer", "relayer", msg.Relayer, "payee", msg.Payee, "channel", msg.ChannelId) return &types.MsgRegisterPayeeResponse{}, nil } -// RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying -// This ensures they will be properly compensated for forward relaying on the source chain since the destination chain must send back relayer's source address (counterparty address) in acknowledgement -// This function may be called more than once by relayers, in which case, the previous counterparty address will be overwritten by the new counterparty address -func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.MsgRegisterCounterpartyAddress) (*types.MsgRegisterCounterpartyAddressResponse, error) { +// RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee +// RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty +// payee address before relaying. This ensures they will be properly compensated for forward relaying since +// the destination chain must include the registered counterparty payee address in the acknowledgement. This function +// may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. +func (k Keeper) RegisterCounterpartyPayee(goCtx context.Context, msg *types.MsgRegisterCounterpartyPayee) (*types.MsgRegisterCounterpartyPayeeResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // only register counterparty address if the channel exists and is fee enabled + // only register counterparty payee if the channel exists and is fee enabled if _, found := k.channelKeeper.GetChannel(ctx, msg.PortId, msg.ChannelId); !found { return nil, channeltypes.ErrChannelNotFound } @@ -51,11 +53,11 @@ func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.Ms return nil, types.ErrFeeNotEnabled } - k.SetCounterpartyAddress(ctx, msg.Address, msg.CounterpartyAddress, msg.ChannelId) + k.SetCounterpartyPayeeAddress(ctx, msg.Relayer, msg.CounterpartyPayee, msg.ChannelId) - k.Logger(ctx).Info("registering counterparty address for relayer", "address", msg.Address, "counterparty address", msg.CounterpartyAddress, "channel", msg.ChannelId) + k.Logger(ctx).Info("registering counterparty payee for relayer", "relayer", msg.Relayer, "counterparty payee", msg.CounterpartyPayee, "channel", msg.ChannelId) - return &types.MsgRegisterCounterpartyAddressResponse{}, nil + return &types.MsgRegisterCounterpartyPayeeResponse{}, nil } // PayPacketFee defines a rpc handler method for MsgPayPacketFee diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 76179514943..9a05f294c9d 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -73,12 +73,10 @@ func (suite *KeeperTestSuite) TestRegisterPayee() { } } -func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() { +func (suite *KeeperTestSuite) TestRegisterCounterpartyPayee() { var ( - sender string - counterparty string - channelID string - ctx sdk.Context + msg *types.MsgRegisterCounterpartyPayee + expCounterpartyPayee string ) testCases := []struct { @@ -92,43 +90,57 @@ func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() { func() {}, }, { - "counterparty is an arbitrary string", + "counterparty payee is an arbitrary string", true, - func() { counterparty = "arbitrary-string" }, + func() { + msg.CounterpartyPayee = "arbitrary-string" + expCounterpartyPayee = "arbitrary-string" + }, }, { "channel does not exist", false, - func() { channelID = "channel-22" }, + func() { + msg.ChannelId = "channel-100" + }, }, { "channel is not fee enabled", false, func() { - suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(ctx, suite.path.EndpointA.ChannelConfig.PortID, channelID) + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) }, }, } for _, tc := range testCases { suite.SetupTest() - ctx = suite.chainA.GetContext() suite.coordinator.Setup(suite.path) // setup channel - sender = suite.chainA.SenderAccount.GetAddress().String() - counterparty = suite.chainB.SenderAccount.GetAddress().String() - channelID = suite.path.EndpointA.ChannelID + expCounterpartyPayee = suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String() + msg = types.NewMsgRegisterCounterpartyPayee( + suite.path.EndpointA.ChannelConfig.PortID, + suite.path.EndpointA.ChannelID, + suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), + expCounterpartyPayee, + ) tc.malleate() - msg := types.NewMsgRegisterCounterpartyAddress(suite.path.EndpointA.ChannelConfig.PortID, channelID, sender, counterparty) - _, err := suite.chainA.GetSimApp().IBCFeeKeeper.RegisterCounterpartyAddress(sdk.WrapSDKContext(ctx), msg) + res, err := suite.chainA.GetSimApp().IBCFeeKeeper.RegisterCounterpartyPayee(sdk.WrapSDKContext(suite.chainA.GetContext()), msg) if tc.expPass { - suite.Require().NoError(err) // message committed + suite.Require().NoError(err) + suite.Require().NotNil(res) + + counterpartyPayee, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + ibctesting.FirstChannelID, + ) - counterpartyAddress, _ := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyAddress(ctx, suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) - suite.Require().Equal(counterparty, counterpartyAddress) + suite.Require().True(found) + suite.Require().Equal(expCounterpartyPayee, counterpartyPayee) } else { suite.Require().Error(err) } diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index 476497bfbbb..0c14726c9ed 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -35,7 +35,7 @@ func (k Keeper) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.C // it is possible that a relayer has not registered a counterparty address. // if there is no registered counterparty address then write acknowledgement with empty relayer address and refund recv_fee. - forwardRelayer, _ := k.GetCounterpartyAddress(ctx, relayer, packet.GetDestChannel()) + forwardRelayer, _ := k.GetCounterpartyPayeeAddress(ctx, relayer, packet.GetDestChannel()) ack := types.NewIncentivizedAcknowledgement(forwardRelayer, acknowledgement.Acknowledgement(), acknowledgement.Success()) diff --git a/modules/apps/29-fee/keeper/relay_test.go b/modules/apps/29-fee/keeper/relay_test.go index d0a9e620f9d..5dd0aa15815 100644 --- a/modules/apps/29-fee/keeper/relay_test.go +++ b/modules/apps/29-fee/keeper/relay_test.go @@ -18,7 +18,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgementAsync() { "success", func() { suite.chainB.GetSimApp().IBCFeeKeeper.SetRelayerAddressForAsyncAck(suite.chainB.GetContext(), channeltypes.NewPacketId(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID, 1), suite.chainA.SenderAccount.GetAddress().String()) - suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) + suite.chainB.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainB.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.path.EndpointB.ChannelID) }, true, }, diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 3f4545e9fdd..be91db917ed 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -46,7 +46,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() { // to differentiate from the chainA.SenderAccount for checking successful relay payouts relayerAddress := suite.chainB.SenderAccount.GetAddress() - msgRegister := types.NewMsgRegisterCounterpartyAddress(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String()) + msgRegister := types.NewMsgRegisterCounterpartyPayee(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String()) _, err = suite.chainB.SendMsgs(msgRegister) suite.Require().NoError(err) // message committed diff --git a/modules/apps/29-fee/types/codec.go b/modules/apps/29-fee/types/codec.go index 871f148b043..272056d6f9f 100644 --- a/modules/apps/29-fee/types/codec.go +++ b/modules/apps/29-fee/types/codec.go @@ -10,9 +10,10 @@ import ( // RegisterLegacyAminoCodec registers the necessary x/ibc 29-fee interfaces and concrete types // on the provided LegacyAmino codec. These types are used for Amino JSON serialization. func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - cdc.RegisterConcrete(&MsgRegisterCounterpartyAddress{}, "cosmos-sdk/MsgRegisterCounterpartyAddress", nil) cdc.RegisterConcrete(&MsgPayPacketFee{}, "cosmos-sdk/MsgPayPacketFee", nil) cdc.RegisterConcrete(&MsgPayPacketFeeAsync{}, "cosmos-sdk/MsgPayPacketFeeAsync", nil) + cdc.RegisterConcrete(&MsgRegisterPayee{}, "cosmos-sdk/MsgRegisterPayee", nil) + cdc.RegisterConcrete(&MsgRegisterCounterpartyPayee{}, "cosmos-sdk/MsgRegisterCounterpartyPayee", nil) } // RegisterInterfaces register the 29-fee module interfaces to protobuf @@ -20,9 +21,10 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations( (*sdk.Msg)(nil), - &MsgRegisterCounterpartyAddress{}, &MsgPayPacketFee{}, &MsgPayPacketFeeAsync{}, + &MsgRegisterPayee{}, + &MsgRegisterCounterpartyPayee{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) diff --git a/modules/apps/29-fee/types/errors.go b/modules/apps/29-fee/types/errors.go index 812db0a43a4..0ac40e5f824 100644 --- a/modules/apps/29-fee/types/errors.go +++ b/modules/apps/29-fee/types/errors.go @@ -11,7 +11,7 @@ var ( ErrBalanceNotFound = sdkerrors.Register(ModuleName, 4, "balance not found for given account address") ErrFeeNotFound = sdkerrors.Register(ModuleName, 5, "there is no fee escrowed for the given packetID") ErrRelayersNotNil = sdkerrors.Register(ModuleName, 6, "relayers must be nil. This feature is not supported") - ErrCounterpartyAddressEmpty = sdkerrors.Register(ModuleName, 7, "counterparty address must not be empty") + ErrCounterpartyPayeeEmpty = sdkerrors.Register(ModuleName, 7, "counterparty payee must not be empty") ErrForwardRelayerAddressNotFound = sdkerrors.Register(ModuleName, 8, "forward relayer address not found") ErrFeeNotEnabled = sdkerrors.Register(ModuleName, 9, "fee module is not enabled for this channel. If this error occurs after channel setup, fee module may not be enabled") ErrRelayerNotFoundForAsyncAck = sdkerrors.Register(ModuleName, 10, "relayer address must be stored for async WriteAcknowledgement") diff --git a/modules/apps/29-fee/types/genesis.go b/modules/apps/29-fee/types/genesis.go index db406c3fefb..74660034041 100644 --- a/modules/apps/29-fee/types/genesis.go +++ b/modules/apps/29-fee/types/genesis.go @@ -89,7 +89,7 @@ func (gs GenesisState) Validate() error { } if strings.TrimSpace(rel.CounterpartyAddress) == "" { - return ErrCounterpartyAddressEmpty + return ErrCounterpartyPayeeEmpty } } diff --git a/modules/apps/29-fee/types/keys.go b/modules/apps/29-fee/types/keys.go index 6cb6f53551c..7cbaffcd556 100644 --- a/modules/apps/29-fee/types/keys.go +++ b/modules/apps/29-fee/types/keys.go @@ -28,11 +28,11 @@ const ( // FeeEnabledPrefix is the key prefix for storing fee enabled flag FeeEnabledKeyPrefix = "feeEnabled" - // PayeeAddressKeyPrefix is the key prefix for the fee payee address stored in state - PayeeAddressKeyPrefix = "payeeAddress" + // PayeeKeyPrefix is the key prefix for the fee payee address stored in state + PayeeKeyPrefix = "payee" - // CounterpartyRelayerAddressKeyPrefix is the key prefix for relayer address mapping - CounterpartyRelayerAddressKeyPrefix = "relayerAddress" + // CounterpartyPayeeKeyPrefix is the key prefix for the counterparty payee address mapping + CounterpartyPayeeKeyPrefix = "counterpartyPayee" // FeesInEscrowPrefix is the key prefix for fee in escrow mapping FeesInEscrowPrefix = "feesInEscrow" @@ -73,9 +73,9 @@ func ParseKeyFeeEnabled(key string) (portID, channelID string, err error) { return portID, channelID, nil } -// KeyPayeeAddress returns the key for relayer address -> payee address mapping -func KeyPayeeAddress(relayerAddr, channelID string) []byte { - return []byte(fmt.Sprintf("%s/%s/%s", PayeeAddressKeyPrefix, relayerAddr, channelID)) +// KeyPayee returns the key for relayer address -> payee address mapping +func KeyPayee(relayerAddr, channelID string) []byte { + return []byte(fmt.Sprintf("%s/%s/%s", PayeeKeyPrefix, relayerAddr, channelID)) } // ParseKeyPayeeAddress returns the registered relayer addresss and channelID used to the store the fee payee address @@ -90,13 +90,13 @@ func ParseKeyPayeeAddress(key string) (relayerAddr, channelID string, err error) return keySplit[1], keySplit[2], nil } -// KeyCounterpartyRelayer returns the key for relayer address -> counterparty address mapping -func KeyCounterpartyRelayer(address, channelID string) []byte { - return []byte(fmt.Sprintf("%s/%s/%s", CounterpartyRelayerAddressKeyPrefix, address, channelID)) +// KeyCounterpartyPayee returns the key for relayer address -> counterparty payee address mapping +func KeyCounterpartyPayee(address, channelID string) []byte { + return []byte(fmt.Sprintf("%s/%s/%s", CounterpartyPayeeKeyPrefix, address, channelID)) } -// ParseKeyCounterpartyRelayer returns the registered relayer address and channelID used to store the counterpartyrelayer address -func ParseKeyCounterpartyRelayer(key string) (address string, channelID string, error error) { +// ParseKeyCounterpartyPayee returns the registered relayer address and channelID used to store the counterparty payee address +func ParseKeyCounterpartyPayee(key string) (address string, channelID string, error error) { keySplit := strings.Split(key, "/") if len(keySplit) != 3 { return "", "", sdkerrors.Wrapf( diff --git a/modules/apps/29-fee/types/keys_test.go b/modules/apps/29-fee/types/keys_test.go index 442c4a47634..94f2c4602b2 100644 --- a/modules/apps/29-fee/types/keys_test.go +++ b/modules/apps/29-fee/types/keys_test.go @@ -13,12 +13,12 @@ import ( var validPacketID = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) -func TestKeyPayeeAddress(t *testing.T) { - key := types.KeyPayeeAddress("relayer-address", ibctesting.FirstChannelID) - require.Equal(t, string(key), fmt.Sprintf("%s/%s/%s", types.PayeeAddressKeyPrefix, "relayer-address", ibctesting.FirstChannelID)) +func TestKeyPayee(t *testing.T) { + key := types.KeyPayee("relayer-address", ibctesting.FirstChannelID) + require.Equal(t, string(key), fmt.Sprintf("%s/%s/%s", types.PayeeKeyPrefix, "relayer-address", ibctesting.FirstChannelID)) } -func TestParseKeyPayeeAddress(t *testing.T) { +func TestParseKeyPayee(t *testing.T) { testCases := []struct { name string key string @@ -26,7 +26,7 @@ func TestParseKeyPayeeAddress(t *testing.T) { }{ { "success", - string(types.KeyPayeeAddress("relayer-address", ibctesting.FirstChannelID)), + string(types.KeyPayee("relayer-address", ibctesting.FirstChannelID)), true, }, { @@ -49,14 +49,14 @@ func TestParseKeyPayeeAddress(t *testing.T) { } } -func TestKeyCounterpartyRelayer(t *testing.T) { +func TestKeyCounterpartyPayee(t *testing.T) { var ( relayerAddress = "relayer_address" channelID = "channel-0" ) - key := types.KeyCounterpartyRelayer(relayerAddress, channelID) - require.Equal(t, string(key), fmt.Sprintf("%s/%s/%s", types.CounterpartyRelayerAddressKeyPrefix, relayerAddress, channelID)) + key := types.KeyCounterpartyPayee(relayerAddress, channelID) + require.Equal(t, string(key), fmt.Sprintf("%s/%s/%s", types.CounterpartyPayeeKeyPrefix, relayerAddress, channelID)) } func TestKeyFeesInEscrow(t *testing.T) { @@ -172,7 +172,7 @@ func TestParseKeyForwardRelayerAddress(t *testing.T) { } } -func TestParseKeyCounterpartyRelayer(t *testing.T) { +func TestParseKeyCounterpartyPayee(t *testing.T) { relayerAddress := "relayer_address" testCases := []struct { @@ -182,7 +182,7 @@ func TestParseKeyCounterpartyRelayer(t *testing.T) { }{ { "success", - string(types.KeyCounterpartyRelayer(relayerAddress, ibctesting.FirstChannelID)), + string(types.KeyCounterpartyPayee(relayerAddress, ibctesting.FirstChannelID)), true, }, { @@ -193,7 +193,7 @@ func TestParseKeyCounterpartyRelayer(t *testing.T) { } for _, tc := range testCases { - address, channelID, err := types.ParseKeyCounterpartyRelayer(tc.key) + address, channelID, err := types.ParseKeyCounterpartyPayee(tc.key) if tc.expPass { require.NoError(t, err) diff --git a/modules/apps/29-fee/types/msgs.go b/modules/apps/29-fee/types/msgs.go index 3d5520f3ff2..81d22d50422 100644 --- a/modules/apps/29-fee/types/msgs.go +++ b/modules/apps/29-fee/types/msgs.go @@ -19,10 +19,10 @@ const ( // NewMsgRegisterPayee creates a new instance of MsgRegisterPayee func NewMsgRegisterPayee(portID, channelID, relayerAddr, payeeAddr string) *MsgRegisterPayee { return &MsgRegisterPayee{ - PortId: portID, - ChannelId: channelID, - RelayerAddress: relayerAddr, - Payee: payeeAddr, + PortId: portID, + ChannelId: channelID, + Relayer: relayerAddr, + Payee: payeeAddr, } } @@ -36,11 +36,11 @@ func (msg MsgRegisterPayee) ValidateBasic() error { return err } - if msg.RelayerAddress == msg.Payee { + if msg.Relayer == msg.Payee { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "relayer address and payee must not be equal") } - _, err := sdk.AccAddressFromBech32(msg.RelayerAddress) + _, err := sdk.AccAddressFromBech32(msg.Relayer) if err != nil { return sdkerrors.Wrap(err, "failed to create sdk.AccAddress from relayer address") } @@ -55,7 +55,7 @@ func (msg MsgRegisterPayee) ValidateBasic() error { // GetSigners implements sdk.Msg func (msg MsgRegisterPayee) GetSigners() []sdk.AccAddress { - signer, err := sdk.AccAddressFromBech32(msg.RelayerAddress) + signer, err := sdk.AccAddressFromBech32(msg.Relayer) if err != nil { panic(err) } @@ -63,46 +63,45 @@ func (msg MsgRegisterPayee) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{signer} } -// NewMsgRegisterCounterpartyAddress creates a new instance of MsgRegisterCounterpartyAddress -func NewMsgRegisterCounterpartyAddress(portID, channelID, address, counterpartyAddress string) *MsgRegisterCounterpartyAddress { - return &MsgRegisterCounterpartyAddress{ - Address: address, - CounterpartyAddress: counterpartyAddress, - PortId: portID, - ChannelId: channelID, +// NewMsgRegisterCounterpartyPayee creates a new instance of MsgRegisterCounterpartyPayee +func NewMsgRegisterCounterpartyPayee(portID, channelID, relayerAddr, counterpartyPayeeAddr string) *MsgRegisterCounterpartyPayee { + return &MsgRegisterCounterpartyPayee{ + PortId: portID, + ChannelId: channelID, + Relayer: relayerAddr, + CounterpartyPayee: counterpartyPayeeAddr, } } // ValidateBasic performs a basic check of the MsgRegisterCounterpartyAddress fields -func (msg MsgRegisterCounterpartyAddress) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Address) - if err != nil { - return sdkerrors.Wrap(err, "failed to convert msg.Address into sdk.AccAddress") - } - - if strings.TrimSpace(msg.CounterpartyAddress) == "" { - return ErrCounterpartyAddressEmpty - } - - // validate portId +func (msg MsgRegisterCounterpartyPayee) ValidateBasic() error { if err := host.PortIdentifierValidator(msg.PortId); err != nil { return err } - // validate channelId if err := host.ChannelIdentifierValidator(msg.ChannelId); err != nil { return err } + _, err := sdk.AccAddressFromBech32(msg.Relayer) + if err != nil { + return sdkerrors.Wrap(err, "failed to create sdk.AccAddress from relayer address") + } + + if strings.TrimSpace(msg.CounterpartyPayee) == "" { + return ErrCounterpartyPayeeEmpty + } + return nil } // GetSigners implements sdk.Msg -func (msg MsgRegisterCounterpartyAddress) GetSigners() []sdk.AccAddress { - signer, err := sdk.AccAddressFromBech32(msg.Address) +func (msg MsgRegisterCounterpartyPayee) GetSigners() []sdk.AccAddress { + signer, err := sdk.AccAddressFromBech32(msg.Relayer) if err != nil { panic(err) } + return []sdk.AccAddress{signer} } diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go index 4ca23fea458..5b6cbc8c033 100644 --- a/modules/apps/29-fee/types/msgs_test.go +++ b/modules/apps/29-fee/types/msgs_test.go @@ -42,7 +42,7 @@ func TestMsgRegisterPayeeValidation(t *testing.T) { { "invalid request relayer and payee are equal", func() { - msg.RelayerAddress = defaultAccAddress + msg.Relayer = defaultAccAddress msg.Payee = defaultAccAddress }, false, @@ -50,7 +50,7 @@ func TestMsgRegisterPayeeValidation(t *testing.T) { { "invalid relayer address", func() { - msg.RelayerAddress = "invalid-address" + msg.Relayer = "invalid-address" }, false, }, @@ -87,8 +87,8 @@ func TestRegisterPayeeGetSigners(t *testing.T) { require.Equal(t, []sdk.AccAddress{sdk.AccAddress(accAddress)}, msg.GetSigners()) } -func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { - var msg *types.MsgRegisterCounterpartyAddress +func TestMsgRegisterCountepartyPayeeValidation(t *testing.T) { + var msg *types.MsgRegisterCounterpartyPayee testCases := []struct { name string @@ -101,44 +101,44 @@ func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { true, }, { - "validate with incorrect destination relayer address", + "invalid portID", func() { - msg.Address = "invalid-address" + msg.PortId = "" }, false, }, { - "invalid counterparty address", + "invalid channelID", func() { - msg.CounterpartyAddress = "" + msg.ChannelId = "" }, false, }, { - "invalid counterparty address: whitespaced empty string", + "validate with incorrect destination relayer address", func() { - msg.CounterpartyAddress = " " + msg.Relayer = "invalid-address" }, false, }, { - "invalid channelID", + "invalid counterparty payee address", func() { - msg.ChannelId = "" + msg.CounterpartyPayee = "" }, false, }, { - "invalid portID", + "invalid counterparty payee address: whitespaced empty string", func() { - msg.PortId = "" + msg.CounterpartyPayee = " " }, false, }, } for i, tc := range testCases { - msg = types.NewMsgRegisterCounterpartyAddress(ibctesting.MockPort, ibctesting.FirstChannelID, defaultAccAddress, defaultAccAddress) + msg = types.NewMsgRegisterCounterpartyPayee(ibctesting.MockPort, ibctesting.FirstChannelID, defaultAccAddress, defaultAccAddress) tc.malleate() @@ -154,7 +154,7 @@ func TestMsgRegisterCountepartyAddressValidation(t *testing.T) { func TestRegisterCountepartyAddressGetSigners(t *testing.T) { accAddress := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - msg := types.NewMsgRegisterCounterpartyAddress(ibctesting.MockPort, ibctesting.FirstChannelID, accAddress.String(), defaultAccAddress) + msg := types.NewMsgRegisterCounterpartyPayee(ibctesting.MockPort, ibctesting.FirstChannelID, accAddress.String(), defaultAccAddress) require.Equal(t, []sdk.AccAddress{sdk.AccAddress(accAddress)}, msg.GetSigners()) } diff --git a/modules/apps/29-fee/types/tx.pb.go b/modules/apps/29-fee/types/tx.pb.go index 7c941f44c9c..e62ca434e8d 100644 --- a/modules/apps/29-fee/types/tx.pb.go +++ b/modules/apps/29-fee/types/tx.pb.go @@ -36,8 +36,8 @@ type MsgRegisterPayee struct { // unique channel identifier ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` // the relayer address - RelayerAddress string `protobuf:"bytes,3,opt,name=relayer_address,json=relayerAddress,proto3" json:"relayer_address,omitempty" yaml:"relayer_address"` - // the fee payee address + Relayer string `protobuf:"bytes,3,opt,name=relayer,proto3" json:"relayer,omitempty"` + // the payee address Payee string `protobuf:"bytes,4,opt,name=payee,proto3" json:"payee,omitempty"` } @@ -111,30 +111,30 @@ func (m *MsgRegisterPayeeResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgRegisterPayeeResponse proto.InternalMessageInfo -// MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc -type MsgRegisterCounterpartyAddress struct { - // the relayer address - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - // the counterparty relayer address - CounterpartyAddress string `protobuf:"bytes,2,opt,name=counterparty_address,json=counterpartyAddress,proto3" json:"counterparty_address,omitempty" yaml:"counterparty_address"` +// MsgRegisterCounterpartyPayee defines the request type for the RegisterCounterpartyPayee rpc +type MsgRegisterCounterpartyPayee struct { // unique port identifier - PortId string `protobuf:"bytes,3,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` // unique channel identifier - ChannelId string `protobuf:"bytes,4,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + // the relayer address + Relayer string `protobuf:"bytes,3,opt,name=relayer,proto3" json:"relayer,omitempty"` + // the counterparty payee address + CounterpartyPayee string `protobuf:"bytes,4,opt,name=counterparty_payee,json=counterpartyPayee,proto3" json:"counterparty_payee,omitempty" yaml:"counterparty_payee"` } -func (m *MsgRegisterCounterpartyAddress) Reset() { *m = MsgRegisterCounterpartyAddress{} } -func (m *MsgRegisterCounterpartyAddress) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterCounterpartyAddress) ProtoMessage() {} -func (*MsgRegisterCounterpartyAddress) Descriptor() ([]byte, []int) { +func (m *MsgRegisterCounterpartyPayee) Reset() { *m = MsgRegisterCounterpartyPayee{} } +func (m *MsgRegisterCounterpartyPayee) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterCounterpartyPayee) ProtoMessage() {} +func (*MsgRegisterCounterpartyPayee) Descriptor() ([]byte, []int) { return fileDescriptor_05c93128649f1b96, []int{2} } -func (m *MsgRegisterCounterpartyAddress) XXX_Unmarshal(b []byte) error { +func (m *MsgRegisterCounterpartyPayee) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgRegisterCounterpartyAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgRegisterCounterpartyPayee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgRegisterCounterpartyAddress.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgRegisterCounterpartyPayee.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -144,36 +144,34 @@ func (m *MsgRegisterCounterpartyAddress) XXX_Marshal(b []byte, deterministic boo return b[:n], nil } } -func (m *MsgRegisterCounterpartyAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterCounterpartyAddress.Merge(m, src) +func (m *MsgRegisterCounterpartyPayee) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterCounterpartyPayee.Merge(m, src) } -func (m *MsgRegisterCounterpartyAddress) XXX_Size() int { +func (m *MsgRegisterCounterpartyPayee) XXX_Size() int { return m.Size() } -func (m *MsgRegisterCounterpartyAddress) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterCounterpartyAddress.DiscardUnknown(m) +func (m *MsgRegisterCounterpartyPayee) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterCounterpartyPayee.DiscardUnknown(m) } -var xxx_messageInfo_MsgRegisterCounterpartyAddress proto.InternalMessageInfo +var xxx_messageInfo_MsgRegisterCounterpartyPayee proto.InternalMessageInfo -// MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc -type MsgRegisterCounterpartyAddressResponse struct { +// MsgRegisterCounterpartyPayeeResponse defines the response type for the RegisterCounterpartyPayee rpc +type MsgRegisterCounterpartyPayeeResponse struct { } -func (m *MsgRegisterCounterpartyAddressResponse) Reset() { - *m = MsgRegisterCounterpartyAddressResponse{} -} -func (m *MsgRegisterCounterpartyAddressResponse) String() string { return proto.CompactTextString(m) } -func (*MsgRegisterCounterpartyAddressResponse) ProtoMessage() {} -func (*MsgRegisterCounterpartyAddressResponse) Descriptor() ([]byte, []int) { +func (m *MsgRegisterCounterpartyPayeeResponse) Reset() { *m = MsgRegisterCounterpartyPayeeResponse{} } +func (m *MsgRegisterCounterpartyPayeeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterCounterpartyPayeeResponse) ProtoMessage() {} +func (*MsgRegisterCounterpartyPayeeResponse) Descriptor() ([]byte, []int) { return fileDescriptor_05c93128649f1b96, []int{3} } -func (m *MsgRegisterCounterpartyAddressResponse) XXX_Unmarshal(b []byte) error { +func (m *MsgRegisterCounterpartyPayeeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgRegisterCounterpartyAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgRegisterCounterpartyPayeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgRegisterCounterpartyAddressResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgRegisterCounterpartyPayeeResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -183,17 +181,17 @@ func (m *MsgRegisterCounterpartyAddressResponse) XXX_Marshal(b []byte, determini return b[:n], nil } } -func (m *MsgRegisterCounterpartyAddressResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRegisterCounterpartyAddressResponse.Merge(m, src) +func (m *MsgRegisterCounterpartyPayeeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterCounterpartyPayeeResponse.Merge(m, src) } -func (m *MsgRegisterCounterpartyAddressResponse) XXX_Size() int { +func (m *MsgRegisterCounterpartyPayeeResponse) XXX_Size() int { return m.Size() } -func (m *MsgRegisterCounterpartyAddressResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRegisterCounterpartyAddressResponse.DiscardUnknown(m) +func (m *MsgRegisterCounterpartyPayeeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterCounterpartyPayeeResponse.DiscardUnknown(m) } -var xxx_messageInfo_MsgRegisterCounterpartyAddressResponse proto.InternalMessageInfo +var xxx_messageInfo_MsgRegisterCounterpartyPayeeResponse proto.InternalMessageInfo // MsgPayPacketFee defines the request type for the PayPacketFee rpc // This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be @@ -363,8 +361,8 @@ var xxx_messageInfo_MsgPayPacketFeeAsyncResponse proto.InternalMessageInfo func init() { proto.RegisterType((*MsgRegisterPayee)(nil), "ibc.applications.fee.v1.MsgRegisterPayee") proto.RegisterType((*MsgRegisterPayeeResponse)(nil), "ibc.applications.fee.v1.MsgRegisterPayeeResponse") - proto.RegisterType((*MsgRegisterCounterpartyAddress)(nil), "ibc.applications.fee.v1.MsgRegisterCounterpartyAddress") - proto.RegisterType((*MsgRegisterCounterpartyAddressResponse)(nil), "ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse") + proto.RegisterType((*MsgRegisterCounterpartyPayee)(nil), "ibc.applications.fee.v1.MsgRegisterCounterpartyPayee") + proto.RegisterType((*MsgRegisterCounterpartyPayeeResponse)(nil), "ibc.applications.fee.v1.MsgRegisterCounterpartyPayeeResponse") proto.RegisterType((*MsgPayPacketFee)(nil), "ibc.applications.fee.v1.MsgPayPacketFee") proto.RegisterType((*MsgPayPacketFeeResponse)(nil), "ibc.applications.fee.v1.MsgPayPacketFeeResponse") proto.RegisterType((*MsgPayPacketFeeAsync)(nil), "ibc.applications.fee.v1.MsgPayPacketFeeAsync") @@ -374,53 +372,51 @@ func init() { func init() { proto.RegisterFile("ibc/applications/fee/v1/tx.proto", fileDescriptor_05c93128649f1b96) } var fileDescriptor_05c93128649f1b96 = []byte{ - // 732 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcf, 0x4f, 0xdb, 0x58, - 0x10, 0x8e, 0x09, 0xbf, 0x32, 0xb0, 0x40, 0xbc, 0x01, 0x8c, 0x61, 0x6d, 0xd6, 0x87, 0x55, 0x56, - 0x2b, 0xec, 0x4d, 0x00, 0xad, 0x96, 0x0b, 0x22, 0x48, 0xa8, 0x1c, 0x50, 0x23, 0xab, 0xa7, 0xaa, - 0x12, 0x72, 0x9c, 0x89, 0x71, 0x9b, 0xe4, 0x59, 0x7e, 0x4e, 0x54, 0xff, 0x07, 0x3d, 0x72, 0xeb, - 0x95, 0x3f, 0x87, 0x23, 0x87, 0x1e, 0xaa, 0x1e, 0xac, 0x0a, 0x2e, 0x3d, 0x47, 0xea, 0xa9, 0x97, - 0xca, 0xf6, 0xb3, 0xeb, 0xa4, 0x09, 0x0a, 0xbd, 0xbd, 0x99, 0xf9, 0x66, 0xde, 0x7c, 0x9f, 0x67, - 0xfc, 0x60, 0xd7, 0x6e, 0x98, 0x9a, 0xe1, 0x38, 0x6d, 0xdb, 0x34, 0x3c, 0x9b, 0x74, 0xa9, 0xd6, - 0x42, 0xd4, 0xfa, 0x15, 0xcd, 0x7b, 0xab, 0x3a, 0x2e, 0xf1, 0x08, 0xbf, 0x69, 0x37, 0x4c, 0x35, - 0x8b, 0x50, 0x5b, 0x88, 0x6a, 0xbf, 0x22, 0x96, 0x2c, 0x62, 0x91, 0x08, 0xa3, 0x85, 0xa7, 0x18, - 0x2e, 0xfe, 0x39, 0xa9, 0x60, 0x98, 0x95, 0x81, 0x98, 0xc4, 0x45, 0xcd, 0xbc, 0x32, 0xba, 0x5d, - 0x6c, 0x87, 0x61, 0x76, 0x8c, 0x21, 0xca, 0x27, 0x0e, 0xd6, 0x2e, 0xa8, 0xa5, 0xa3, 0x65, 0x53, - 0x0f, 0xdd, 0xba, 0xe1, 0x23, 0xf2, 0xff, 0xc0, 0x82, 0x43, 0x5c, 0xef, 0xd2, 0x6e, 0x0a, 0xdc, - 0x2e, 0x57, 0x2e, 0xd4, 0xf8, 0x41, 0x20, 0xaf, 0xf8, 0x46, 0xa7, 0x7d, 0xa4, 0xb0, 0x80, 0xa2, - 0xcf, 0x87, 0xa7, 0xf3, 0x26, 0x7f, 0x00, 0xc0, 0x4a, 0x86, 0xf8, 0x99, 0x08, 0xbf, 0x3e, 0x08, - 0xe4, 0x62, 0x8c, 0xff, 0x11, 0x53, 0xf4, 0x02, 0x33, 0xce, 0x9b, 0xfc, 0x29, 0xac, 0xba, 0xd8, - 0x36, 0x7c, 0x74, 0x2f, 0x8d, 0x66, 0xd3, 0x45, 0x4a, 0x85, 0x7c, 0x94, 0x2a, 0x0e, 0x02, 0x79, - 0x23, 0x4e, 0x1d, 0x01, 0x28, 0xfa, 0x0a, 0xf3, 0x9c, 0xc4, 0x0e, 0xbe, 0x04, 0x73, 0x4e, 0xd8, - 0xb0, 0x30, 0x1b, 0xa6, 0xea, 0xb1, 0x71, 0xb4, 0xf8, 0xee, 0x46, 0xce, 0x7d, 0xb9, 0x91, 0x73, - 0x8a, 0x08, 0xc2, 0x28, 0x37, 0x1d, 0xa9, 0x43, 0xba, 0x14, 0x95, 0x6f, 0x1c, 0x48, 0x99, 0xe0, - 0x29, 0xe9, 0x75, 0x3d, 0x74, 0x1d, 0xc3, 0xf5, 0xfc, 0xa4, 0xbc, 0x00, 0x0b, 0x49, 0x6f, 0x91, - 0x0c, 0x7a, 0x62, 0xf2, 0x3a, 0x94, 0xcc, 0x4c, 0x42, 0x4a, 0x21, 0x66, 0x2f, 0x0f, 0x02, 0x79, - 0x9b, 0xb1, 0x1f, 0x83, 0x52, 0xf4, 0xdf, 0xcd, 0x31, 0xb7, 0x65, 0x44, 0xcf, 0x3f, 0x51, 0xf4, - 0xd9, 0xe9, 0x44, 0xcf, 0x28, 0x53, 0x86, 0xbf, 0x1e, 0x27, 0x9f, 0xea, 0x74, 0x3d, 0x03, 0xab, - 0x17, 0xd4, 0xaa, 0x1b, 0x7e, 0xdd, 0x30, 0xdf, 0xa0, 0x77, 0x86, 0xc8, 0x1f, 0x40, 0xbe, 0x85, - 0x18, 0x89, 0xb2, 0x54, 0xdd, 0x51, 0x27, 0xcc, 0xad, 0x7a, 0x86, 0x58, 0x9b, 0xbd, 0x0d, 0xe4, - 0x9c, 0x1e, 0xc2, 0xf9, 0x63, 0x58, 0xa1, 0xa4, 0xe7, 0x9a, 0x78, 0x99, 0xf0, 0x8c, 0xe5, 0xda, - 0x1a, 0x04, 0xf2, 0x7a, 0xdc, 0xf7, 0x70, 0x5c, 0xd1, 0x97, 0x63, 0x47, 0x3d, 0x26, 0xfd, 0x0c, - 0x8a, 0x0c, 0x90, 0xe1, 0x1e, 0x6b, 0xb5, 0x33, 0x08, 0x64, 0x61, 0xa8, 0x46, 0x56, 0x82, 0xd5, - 0xd8, 0x77, 0x9a, 0x4e, 0xdf, 0x06, 0xcc, 0x53, 0xdb, 0xea, 0xa2, 0xcb, 0x26, 0x87, 0x59, 0xbc, - 0x08, 0x8b, 0x6c, 0xc4, 0xa8, 0x30, 0xb7, 0x9b, 0x2f, 0x17, 0xf4, 0xd4, 0xce, 0x88, 0xb7, 0x05, - 0x9b, 0x23, 0x8a, 0xa4, 0x6a, 0x7d, 0xe0, 0xa0, 0x34, 0x12, 0x3b, 0xa1, 0x7e, 0xd7, 0xe4, 0x5f, - 0x40, 0xc1, 0x89, 0x3c, 0xc9, 0x52, 0x2d, 0x55, 0xff, 0x88, 0x84, 0x0b, 0xd7, 0x53, 0x4d, 0x76, - 0xb2, 0x5f, 0x51, 0xe3, 0xbc, 0xf3, 0x66, 0x4d, 0x08, 0x95, 0x1b, 0x04, 0xf2, 0x1a, 0x1b, 0x81, - 0x24, 0x5b, 0xd1, 0x17, 0x1d, 0x86, 0xe1, 0x5f, 0x01, 0x30, 0x7f, 0xf8, 0x3d, 0x66, 0xa2, 0xb2, - 0xca, 0xc4, 0xef, 0x91, 0xb6, 0x54, 0xdb, 0x62, 0xb5, 0x8b, 0x43, 0xb5, 0x5b, 0x88, 0x8a, 0xce, - 0xda, 0x3c, 0x1b, 0x5a, 0x24, 0x09, 0x76, 0xc6, 0xb1, 0x4a, 0x68, 0x57, 0xbf, 0xe6, 0x21, 0x7f, - 0x41, 0x2d, 0xbe, 0x03, 0xbf, 0x0d, 0xff, 0x49, 0xfe, 0x9e, 0xd8, 0xcc, 0xe8, 0x62, 0x8a, 0x95, - 0xa9, 0xa1, 0xc9, 0xb5, 0xfc, 0x7b, 0x0e, 0xb6, 0x1f, 0x5b, 0xe0, 0xff, 0xa6, 0x29, 0x39, 0x26, - 0x51, 0x3c, 0xfe, 0xc5, 0xc4, 0xb4, 0xb3, 0xd7, 0xb0, 0x3c, 0xb4, 0x31, 0xe5, 0xc7, 0x0a, 0x66, - 0x91, 0xe2, 0xbf, 0xd3, 0x22, 0xd3, 0xbb, 0x7c, 0x28, 0xfe, 0x3c, 0x6f, 0x7b, 0xd3, 0x96, 0x89, - 0xe0, 0xe2, 0xe1, 0x93, 0xe0, 0xc9, 0xd5, 0xb5, 0xe7, 0xb7, 0xf7, 0x12, 0x77, 0x77, 0x2f, 0x71, - 0x9f, 0xef, 0x25, 0xee, 0xfa, 0x41, 0xca, 0xdd, 0x3d, 0x48, 0xb9, 0x8f, 0x0f, 0x52, 0xee, 0xe5, - 0xa1, 0x65, 0x7b, 0x57, 0xbd, 0x86, 0x6a, 0x92, 0x8e, 0x66, 0x12, 0xda, 0x21, 0x54, 0xb3, 0x1b, - 0xe6, 0x9e, 0x45, 0xb4, 0xfe, 0xbe, 0xd6, 0x21, 0xcd, 0x5e, 0x1b, 0x69, 0xf8, 0x7a, 0x51, 0xad, - 0xfa, 0xff, 0x5e, 0xf8, 0x70, 0x79, 0xbe, 0x83, 0xb4, 0x31, 0x1f, 0xbd, 0x4a, 0xfb, 0xdf, 0x03, - 0x00, 0x00, 0xff, 0xff, 0x8c, 0x56, 0x8c, 0xfd, 0x2e, 0x07, 0x00, 0x00, + // 699 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0x4f, 0x4f, 0xdb, 0x4a, + 0x10, 0x8f, 0x09, 0xff, 0x32, 0xf0, 0x80, 0xac, 0xe0, 0xe1, 0x58, 0x10, 0xf3, 0xac, 0xa7, 0x27, + 0x9e, 0x2a, 0xec, 0x26, 0xc0, 0xa1, 0x48, 0x55, 0x55, 0x23, 0xa1, 0x22, 0x15, 0x35, 0xb2, 0x7a, + 0xaa, 0x2a, 0x21, 0xc7, 0xd9, 0x18, 0xb7, 0x89, 0xd7, 0xf2, 0x3a, 0x51, 0xfd, 0x0d, 0x7a, 0xa4, + 0xdf, 0x80, 0x6f, 0xd0, 0xaf, 0xc1, 0x91, 0x43, 0x0f, 0x3d, 0x59, 0x15, 0x5c, 0x7a, 0xab, 0x94, + 0x7e, 0x81, 0x6a, 0xed, 0xb5, 0xeb, 0x24, 0x0a, 0x4a, 0x7b, 0xea, 0x6d, 0x67, 0xe6, 0x37, 0xbf, + 0x9d, 0xf9, 0x79, 0xc6, 0x0b, 0x3b, 0x4e, 0xd3, 0xd2, 0x4c, 0xcf, 0xeb, 0x38, 0x96, 0x19, 0x38, + 0xc4, 0xa5, 0x5a, 0x1b, 0x63, 0xad, 0x5f, 0xd3, 0x82, 0x77, 0xaa, 0xe7, 0x93, 0x80, 0xa0, 0x4d, + 0xa7, 0x69, 0xa9, 0x79, 0x84, 0xda, 0xc6, 0x58, 0xed, 0xd7, 0xa4, 0x75, 0x9b, 0xd8, 0x24, 0xc6, + 0x68, 0xec, 0x94, 0xc0, 0xa5, 0x7f, 0x26, 0x11, 0xb2, 0xac, 0x1c, 0xc4, 0x22, 0x3e, 0xd6, 0xac, + 0x0b, 0xd3, 0x75, 0x71, 0x87, 0x85, 0xf9, 0x31, 0x81, 0x28, 0x1f, 0x05, 0x58, 0x3b, 0xa3, 0xb6, + 0x81, 0x6d, 0x87, 0x06, 0xd8, 0x6f, 0x98, 0x21, 0xc6, 0xe8, 0x01, 0x2c, 0x78, 0xc4, 0x0f, 0xce, + 0x9d, 0x96, 0x28, 0xec, 0x08, 0xbb, 0x25, 0x1d, 0x0d, 0x22, 0x79, 0x25, 0x34, 0xbb, 0x9d, 0x23, + 0x85, 0x07, 0x14, 0x63, 0x9e, 0x9d, 0x4e, 0x5b, 0xe8, 0x00, 0x80, 0x53, 0x32, 0xfc, 0x4c, 0x8c, + 0xdf, 0x18, 0x44, 0x72, 0x39, 0xc1, 0xff, 0x8c, 0x29, 0x46, 0x89, 0x1b, 0xa7, 0x2d, 0x24, 0xc2, + 0x82, 0x8f, 0x3b, 0x66, 0x88, 0x7d, 0xb1, 0xc8, 0x52, 0x8c, 0xd4, 0x44, 0xeb, 0x30, 0xe7, 0xb1, + 0x2a, 0xc4, 0xd9, 0xd8, 0x9f, 0x18, 0x47, 0x8b, 0xef, 0xaf, 0xe4, 0xc2, 0xd7, 0x2b, 0xb9, 0xa0, + 0x48, 0x20, 0x8e, 0x16, 0x6c, 0x60, 0xea, 0x11, 0x97, 0x62, 0xe5, 0xbb, 0x00, 0x5b, 0xb9, 0xe0, + 0x31, 0xe9, 0xb9, 0x01, 0xf6, 0x3d, 0xd3, 0x0f, 0xc2, 0x3f, 0xa0, 0xb3, 0xe7, 0x80, 0xac, 0x5c, + 0x45, 0xe7, 0xb9, 0x36, 0xf5, 0xed, 0x41, 0x24, 0x57, 0x38, 0xef, 0x18, 0x46, 0x31, 0xca, 0xd6, + 0x68, 0x2b, 0x39, 0x45, 0xfe, 0x83, 0x7f, 0xef, 0x6b, 0x3a, 0x53, 0xe7, 0x72, 0x06, 0x56, 0xcf, + 0xa8, 0xdd, 0x30, 0xc3, 0x86, 0x69, 0xbd, 0xc5, 0xc1, 0x09, 0xc6, 0xe8, 0x00, 0x8a, 0x6d, 0x8c, + 0x63, 0x31, 0x96, 0xea, 0x5b, 0xea, 0x84, 0x11, 0x54, 0x4f, 0x30, 0xd6, 0x67, 0xaf, 0x23, 0xb9, + 0x60, 0x30, 0x38, 0x7a, 0x02, 0x2b, 0x94, 0xf4, 0x7c, 0x0b, 0x9f, 0xa7, 0x6a, 0x26, 0xea, 0x54, + 0x06, 0x91, 0xbc, 0x91, 0x74, 0x31, 0x1c, 0x57, 0x8c, 0xe5, 0xc4, 0xd1, 0x48, 0xa4, 0x7d, 0x06, + 0x65, 0x0e, 0xc8, 0x29, 0x1c, 0xcb, 0xa5, 0x6f, 0x0d, 0x22, 0x59, 0x1c, 0xe2, 0xc8, 0x0b, 0xbd, + 0x9a, 0xf8, 0x8e, 0x33, 0xb9, 0xff, 0x86, 0x79, 0xea, 0xd8, 0x2e, 0xf6, 0xf9, 0xbc, 0x70, 0x0b, + 0x49, 0xb0, 0xc8, 0x75, 0xa7, 0xe2, 0xdc, 0x4e, 0x71, 0xb7, 0x64, 0x64, 0x76, 0x4e, 0xba, 0x0a, + 0x6c, 0x8e, 0x28, 0x92, 0xa9, 0xf5, 0x49, 0x80, 0xf5, 0x91, 0xd8, 0x53, 0x1a, 0xba, 0x16, 0x7a, + 0x09, 0x25, 0x2f, 0xf6, 0xa4, 0x53, 0xb4, 0x54, 0xdf, 0x8e, 0x85, 0x63, 0x9b, 0xa6, 0xa6, 0xeb, + 0xd5, 0xaf, 0xa9, 0x49, 0xde, 0x69, 0x4b, 0x17, 0x99, 0x72, 0x83, 0x48, 0x5e, 0xe3, 0x83, 0x96, + 0x66, 0x2b, 0xc6, 0xa2, 0xc7, 0x31, 0xe8, 0x35, 0x00, 0xf7, 0xb3, 0xef, 0x31, 0x13, 0xd3, 0x2a, + 0x13, 0xbf, 0x47, 0x56, 0x92, 0x5e, 0xe1, 0xdc, 0xe5, 0x21, 0xee, 0x36, 0x1b, 0x1a, 0x5e, 0xe6, + 0xc9, 0xd0, 0xb0, 0x54, 0xe3, 0x0d, 0x19, 0xeb, 0x2a, 0x6d, 0xbb, 0xfe, 0xad, 0x08, 0xc5, 0x33, + 0x6a, 0xa3, 0x2e, 0xfc, 0x35, 0xfc, 0x53, 0xf8, 0x7f, 0x62, 0x31, 0xa3, 0xeb, 0x28, 0xd5, 0xa6, + 0x86, 0xa6, 0xd7, 0xa2, 0x0f, 0x02, 0x54, 0x26, 0xaf, 0xed, 0xe1, 0x34, 0x84, 0x63, 0x69, 0xd2, + 0xe3, 0xdf, 0x4a, 0xcb, 0x6a, 0x7a, 0x03, 0xcb, 0x43, 0xbb, 0xb2, 0x7b, 0x1f, 0x5d, 0x1e, 0x29, + 0x3d, 0x9c, 0x16, 0x99, 0xdd, 0x15, 0x42, 0x79, 0x7c, 0xd2, 0xf6, 0xa6, 0xa5, 0x89, 0xe1, 0xd2, + 0xe1, 0x2f, 0xc1, 0xd3, 0xab, 0xf5, 0x17, 0xd7, 0xb7, 0x55, 0xe1, 0xe6, 0xb6, 0x2a, 0x7c, 0xb9, + 0xad, 0x0a, 0x97, 0x77, 0xd5, 0xc2, 0xcd, 0x5d, 0xb5, 0xf0, 0xf9, 0xae, 0x5a, 0x78, 0x75, 0x68, + 0x3b, 0xc1, 0x45, 0xaf, 0xa9, 0x5a, 0xa4, 0xab, 0x59, 0x84, 0x76, 0x09, 0xd5, 0x9c, 0xa6, 0xb5, + 0x67, 0x13, 0xad, 0xbf, 0xaf, 0x75, 0x49, 0xab, 0xd7, 0xc1, 0x94, 0x3d, 0x41, 0x54, 0xab, 0x3f, + 0xda, 0x63, 0xaf, 0x4f, 0x10, 0x7a, 0x98, 0x36, 0xe7, 0xe3, 0xa7, 0x65, 0xff, 0x47, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x59, 0xf9, 0x73, 0xbc, 0xf3, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -437,16 +433,16 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { // RegisterPayee defines a rpc handler method for MsgRegisterPayee // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional - // payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which - // packets originate as this is where fee distribution takes place. This function may be called more than once by a - // relayer, in which case, the latest payee is always used. + // payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on + // the source chain from which packets originate as this is where fee distribution takes place. This function may be + // called more than once by a relayer, in which case, the latest payee is always used. RegisterPayee(ctx context.Context, in *MsgRegisterPayee, opts ...grpc.CallOption) (*MsgRegisterPayeeResponse, error) - // RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress - // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their - // counterparty address before relaying. This ensures they will be properly compensated for forward relaying since - // destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function - // may be called more than once by a relayer, in which case, the latest counterparty address is always used. - RegisterCounterpartyAddress(ctx context.Context, in *MsgRegisterCounterpartyAddress, opts ...grpc.CallOption) (*MsgRegisterCounterpartyAddressResponse, error) + // RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee + // RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty + // payee address before relaying. This ensures they will be properly compensated for forward relaying since + // the destination chain must include the registered counterparty payee address in the acknowledgement. This function + // may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. + RegisterCounterpartyPayee(ctx context.Context, in *MsgRegisterCounterpartyPayee, opts ...grpc.CallOption) (*MsgRegisterCounterpartyPayeeResponse, error) // PayPacketFee defines a rpc handler method for MsgPayPacketFee // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to // incentivize the relaying of the packet at the next sequence @@ -476,9 +472,9 @@ func (c *msgClient) RegisterPayee(ctx context.Context, in *MsgRegisterPayee, opt return out, nil } -func (c *msgClient) RegisterCounterpartyAddress(ctx context.Context, in *MsgRegisterCounterpartyAddress, opts ...grpc.CallOption) (*MsgRegisterCounterpartyAddressResponse, error) { - out := new(MsgRegisterCounterpartyAddressResponse) - err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Msg/RegisterCounterpartyAddress", in, out, opts...) +func (c *msgClient) RegisterCounterpartyPayee(ctx context.Context, in *MsgRegisterCounterpartyPayee, opts ...grpc.CallOption) (*MsgRegisterCounterpartyPayeeResponse, error) { + out := new(MsgRegisterCounterpartyPayeeResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Msg/RegisterCounterpartyPayee", in, out, opts...) if err != nil { return nil, err } @@ -507,16 +503,16 @@ func (c *msgClient) PayPacketFeeAsync(ctx context.Context, in *MsgPayPacketFeeAs type MsgServer interface { // RegisterPayee defines a rpc handler method for MsgRegisterPayee // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional - // payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which - // packets originate as this is where fee distribution takes place. This function may be called more than once by a - // relayer, in which case, the latest payee is always used. + // payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on + // the source chain from which packets originate as this is where fee distribution takes place. This function may be + // called more than once by a relayer, in which case, the latest payee is always used. RegisterPayee(context.Context, *MsgRegisterPayee) (*MsgRegisterPayeeResponse, error) - // RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress - // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their - // counterparty address before relaying. This ensures they will be properly compensated for forward relaying since - // destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function - // may be called more than once by a relayer, in which case, the latest counterparty address is always used. - RegisterCounterpartyAddress(context.Context, *MsgRegisterCounterpartyAddress) (*MsgRegisterCounterpartyAddressResponse, error) + // RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee + // RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty + // payee address before relaying. This ensures they will be properly compensated for forward relaying since + // the destination chain must include the registered counterparty payee address in the acknowledgement. This function + // may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. + RegisterCounterpartyPayee(context.Context, *MsgRegisterCounterpartyPayee) (*MsgRegisterCounterpartyPayeeResponse, error) // PayPacketFee defines a rpc handler method for MsgPayPacketFee // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to // incentivize the relaying of the packet at the next sequence @@ -536,8 +532,8 @@ type UnimplementedMsgServer struct { func (*UnimplementedMsgServer) RegisterPayee(ctx context.Context, req *MsgRegisterPayee) (*MsgRegisterPayeeResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RegisterPayee not implemented") } -func (*UnimplementedMsgServer) RegisterCounterpartyAddress(ctx context.Context, req *MsgRegisterCounterpartyAddress) (*MsgRegisterCounterpartyAddressResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RegisterCounterpartyAddress not implemented") +func (*UnimplementedMsgServer) RegisterCounterpartyPayee(ctx context.Context, req *MsgRegisterCounterpartyPayee) (*MsgRegisterCounterpartyPayeeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterCounterpartyPayee not implemented") } func (*UnimplementedMsgServer) PayPacketFee(ctx context.Context, req *MsgPayPacketFee) (*MsgPayPacketFeeResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method PayPacketFee not implemented") @@ -568,20 +564,20 @@ func _Msg_RegisterPayee_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } -func _Msg_RegisterCounterpartyAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgRegisterCounterpartyAddress) +func _Msg_RegisterCounterpartyPayee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRegisterCounterpartyPayee) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).RegisterCounterpartyAddress(ctx, in) + return srv.(MsgServer).RegisterCounterpartyPayee(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/ibc.applications.fee.v1.Msg/RegisterCounterpartyAddress", + FullMethod: "/ibc.applications.fee.v1.Msg/RegisterCounterpartyPayee", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).RegisterCounterpartyAddress(ctx, req.(*MsgRegisterCounterpartyAddress)) + return srv.(MsgServer).RegisterCounterpartyPayee(ctx, req.(*MsgRegisterCounterpartyPayee)) } return interceptor(ctx, in, info, handler) } @@ -631,8 +627,8 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Handler: _Msg_RegisterPayee_Handler, }, { - MethodName: "RegisterCounterpartyAddress", - Handler: _Msg_RegisterCounterpartyAddress_Handler, + MethodName: "RegisterCounterpartyPayee", + Handler: _Msg_RegisterCounterpartyPayee_Handler, }, { MethodName: "PayPacketFee", @@ -674,10 +670,10 @@ func (m *MsgRegisterPayee) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x22 } - if len(m.RelayerAddress) > 0 { - i -= len(m.RelayerAddress) - copy(dAtA[i:], m.RelayerAddress) - i = encodeVarintTx(dAtA, i, uint64(len(m.RelayerAddress))) + if len(m.Relayer) > 0 { + i -= len(m.Relayer) + copy(dAtA[i:], m.Relayer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Relayer))) i-- dAtA[i] = 0x1a } @@ -721,7 +717,7 @@ func (m *MsgRegisterPayeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error return len(dAtA) - i, nil } -func (m *MsgRegisterCounterpartyAddress) Marshal() (dAtA []byte, err error) { +func (m *MsgRegisterCounterpartyPayee) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -731,48 +727,48 @@ func (m *MsgRegisterCounterpartyAddress) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgRegisterCounterpartyAddress) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgRegisterCounterpartyPayee) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgRegisterCounterpartyAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgRegisterCounterpartyPayee) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l + if len(m.CounterpartyPayee) > 0 { + i -= len(m.CounterpartyPayee) + copy(dAtA[i:], m.CounterpartyPayee) + i = encodeVarintTx(dAtA, i, uint64(len(m.CounterpartyPayee))) + i-- + dAtA[i] = 0x22 + } + if len(m.Relayer) > 0 { + i -= len(m.Relayer) + copy(dAtA[i:], m.Relayer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Relayer))) + i-- + dAtA[i] = 0x1a + } if len(m.ChannelId) > 0 { i -= len(m.ChannelId) copy(dAtA[i:], m.ChannelId) i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x12 } if len(m.PortId) > 0 { i -= len(m.PortId) copy(dAtA[i:], m.PortId) i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) i-- - dAtA[i] = 0x1a - } - if len(m.CounterpartyAddress) > 0 { - i -= len(m.CounterpartyAddress) - copy(dAtA[i:], m.CounterpartyAddress) - i = encodeVarintTx(dAtA, i, uint64(len(m.CounterpartyAddress))) - i-- - dAtA[i] = 0x12 - } - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) - i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *MsgRegisterCounterpartyAddressResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgRegisterCounterpartyPayeeResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -782,12 +778,12 @@ func (m *MsgRegisterCounterpartyAddressResponse) Marshal() (dAtA []byte, err err return dAtA[:n], nil } -func (m *MsgRegisterCounterpartyAddressResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgRegisterCounterpartyPayeeResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgRegisterCounterpartyAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgRegisterCounterpartyPayeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -972,7 +968,7 @@ func (m *MsgRegisterPayee) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.RelayerAddress) + l = len(m.Relayer) if l > 0 { n += 1 + l + sovTx(uint64(l)) } @@ -992,32 +988,32 @@ func (m *MsgRegisterPayeeResponse) Size() (n int) { return n } -func (m *MsgRegisterCounterpartyAddress) Size() (n int) { +func (m *MsgRegisterCounterpartyPayee) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.Address) + l = len(m.PortId) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.CounterpartyAddress) + l = len(m.ChannelId) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.PortId) + l = len(m.Relayer) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ChannelId) + l = len(m.CounterpartyPayee) if l > 0 { n += 1 + l + sovTx(uint64(l)) } return n } -func (m *MsgRegisterCounterpartyAddressResponse) Size() (n int) { +func (m *MsgRegisterCounterpartyPayeeResponse) Size() (n int) { if m == nil { return 0 } @@ -1187,7 +1183,7 @@ func (m *MsgRegisterPayee) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RelayerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Relayer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1215,7 +1211,7 @@ func (m *MsgRegisterPayee) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RelayerAddress = string(dAtA[iNdEx:postIndex]) + m.Relayer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { @@ -1320,7 +1316,7 @@ func (m *MsgRegisterPayeeResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { +func (m *MsgRegisterCounterpartyPayee) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1343,15 +1339,15 @@ func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterCounterpartyAddress: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRegisterCounterpartyPayee: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterCounterpartyAddress: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRegisterCounterpartyPayee: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1379,11 +1375,11 @@ func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Address = string(dAtA[iNdEx:postIndex]) + m.PortId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1411,11 +1407,11 @@ func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CounterpartyAddress = string(dAtA[iNdEx:postIndex]) + m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Relayer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1443,11 +1439,11 @@ func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.PortId = string(dAtA[iNdEx:postIndex]) + m.Relayer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyPayee", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1475,7 +1471,7 @@ func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChannelId = string(dAtA[iNdEx:postIndex]) + m.CounterpartyPayee = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1498,7 +1494,7 @@ func (m *MsgRegisterCounterpartyAddress) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRegisterCounterpartyAddressResponse) Unmarshal(dAtA []byte) error { +func (m *MsgRegisterCounterpartyPayeeResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1521,10 +1517,10 @@ func (m *MsgRegisterCounterpartyAddressResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterCounterpartyAddressResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRegisterCounterpartyPayeeResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterCounterpartyAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRegisterCounterpartyPayeeResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: diff --git a/modules/light-clients/07-tendermint/types/tendermint.pb.go b/modules/light-clients/07-tendermint/types/tendermint.pb.go index 4be50fa8739..bcb71558313 100644 --- a/modules/light-clients/07-tendermint/types/tendermint.pb.go +++ b/modules/light-clients/07-tendermint/types/tendermint.pb.go @@ -322,75 +322,75 @@ func init() { } var fileDescriptor_c6d6cf2b288949be = []byte{ - // 1078 bytes of a gzipped FileDescriptorProto + // 1080 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcf, 0x6f, 0xe3, 0x44, 0x14, 0x6e, 0xda, 0xb2, 0x4d, 0x26, 0xe9, 0x76, 0x31, 0xa5, 0x9b, 0x96, 0x6e, 0x1c, 0x19, 0xa9, 0xe4, 0x40, 0x6d, 0x92, 0x22, 0x21, 0x55, 0x5c, 0x70, 0x77, 0x51, 0x8b, 0x58, 0xa9, 0x72, 0xf9, 0x21, 0x21, 0x21, 0x33, 0xb1, 0x27, 0xc9, 0x68, 0x6d, 0x8f, 0xe5, 0x99, 0x84, 0x96, 0xbf, 0x00, - 0x4e, 0xec, 0x11, 0x71, 0xe2, 0xc0, 0x1f, 0xb3, 0xc7, 0x1e, 0x39, 0x19, 0xd4, 0x5e, 0x39, 0xe5, - 0xc8, 0x09, 0xcd, 0x0f, 0xdb, 0xd3, 0x6c, 0x97, 0x6a, 0xb9, 0x44, 0xf3, 0xde, 0xfb, 0xde, 0xf7, - 0x65, 0xe6, 0xbd, 0x79, 0x63, 0xe0, 0xe0, 0x61, 0xe0, 0x44, 0x78, 0x3c, 0x61, 0x41, 0x84, 0x51, - 0xc2, 0xa8, 0xc3, 0x50, 0x12, 0xa2, 0x2c, 0xc6, 0x09, 0x73, 0x66, 0x7d, 0xcd, 0xb2, 0xd3, 0x8c, - 0x30, 0x62, 0x74, 0xf0, 0x30, 0xb0, 0xf5, 0x04, 0x5b, 0x83, 0xcc, 0xfa, 0x3b, 0x5d, 0x2d, 0x9f, - 0x5d, 0xa4, 0x88, 0x3a, 0x33, 0x18, 0xe1, 0x10, 0x32, 0x92, 0x49, 0x86, 0x9d, 0xdd, 0x97, 0x10, - 0xe2, 0x57, 0x45, 0x5b, 0x69, 0x46, 0xc8, 0xa8, 0xb0, 0x3a, 0x63, 0x42, 0xc6, 0x11, 0x72, 0x84, - 0x35, 0x9c, 0x8e, 0x9c, 0x70, 0x9a, 0x41, 0x86, 0x49, 0xa2, 0xe2, 0xe6, 0x62, 0x9c, 0xe1, 0x18, - 0x51, 0x06, 0xe3, 0xb4, 0x00, 0xf0, 0xfd, 0x05, 0x24, 0x43, 0x8e, 0xfc, 0xbb, 0x7c, 0x4f, 0x72, - 0xa5, 0x00, 0xef, 0x55, 0x00, 0x12, 0xc7, 0x98, 0xc5, 0x05, 0xa8, 0xb4, 0x14, 0x70, 0x73, 0x4c, - 0xc6, 0x44, 0x2c, 0x1d, 0xbe, 0x92, 0x5e, 0xeb, 0xef, 0x35, 0xd0, 0x3c, 0x12, 0x7c, 0x67, 0x0c, - 0x32, 0x64, 0x6c, 0x83, 0x7a, 0x30, 0x81, 0x38, 0xf1, 0x71, 0xd8, 0xae, 0x75, 0x6b, 0xbd, 0x86, - 0xb7, 0x26, 0xec, 0x93, 0xd0, 0x40, 0xa0, 0xc9, 0xb2, 0x29, 0x65, 0x7e, 0x84, 0x66, 0x28, 0x6a, - 0x2f, 0x77, 0x6b, 0xbd, 0xe6, 0xa0, 0x67, 0xff, 0xf7, 0x79, 0xda, 0x9f, 0x66, 0x30, 0xe0, 0x1b, - 0x76, 0x77, 0x5e, 0xe4, 0xe6, 0xd2, 0x3c, 0x37, 0x8d, 0x0b, 0x18, 0x47, 0x87, 0x96, 0x46, 0x65, - 0x79, 0x40, 0x58, 0x9f, 0x73, 0xc3, 0x18, 0x81, 0x0d, 0x61, 0xe1, 0x64, 0xec, 0xa7, 0x28, 0xc3, - 0x24, 0x6c, 0xaf, 0x08, 0xa9, 0x6d, 0x5b, 0x1e, 0x96, 0x5d, 0x1c, 0x96, 0xfd, 0x58, 0x1d, 0xa6, - 0x6b, 0x29, 0xee, 0x2d, 0x8d, 0xbb, 0xca, 0xb7, 0x7e, 0xf9, 0xd3, 0xac, 0x79, 0xf7, 0x0b, 0xef, - 0xa9, 0x70, 0x1a, 0x18, 0x3c, 0x98, 0x26, 0x43, 0x92, 0x84, 0x9a, 0xd0, 0xea, 0x5d, 0x42, 0xef, - 0x2a, 0xa1, 0x87, 0x52, 0x68, 0x91, 0x40, 0x2a, 0x6d, 0x94, 0x6e, 0x25, 0x85, 0xc0, 0x46, 0x0c, - 0xcf, 0xfd, 0x20, 0x22, 0xc1, 0x33, 0x3f, 0xcc, 0xf0, 0x88, 0xb5, 0xdf, 0x78, 0xcd, 0x2d, 0x2d, - 0xe4, 0x4b, 0xa1, 0xf5, 0x18, 0x9e, 0x1f, 0x71, 0xe7, 0x63, 0xee, 0x33, 0xbe, 0x05, 0xeb, 0xa3, - 0x8c, 0xfc, 0x80, 0x12, 0x7f, 0x82, 0x78, 0x41, 0xda, 0xf7, 0x84, 0xc8, 0x8e, 0x28, 0x11, 0x6f, - 0x11, 0x5b, 0x75, 0xce, 0xac, 0x6f, 0x1f, 0x0b, 0x84, 0xbb, 0xab, 0x54, 0x36, 0xa5, 0xca, 0x8d, - 0x74, 0xcb, 0x6b, 0x49, 0x5b, 0x62, 0x39, 0x7d, 0x04, 0x19, 0xa2, 0xac, 0xa0, 0x5f, 0x7b, 0x5d, - 0xfa, 0x1b, 0xe9, 0x96, 0xd7, 0x92, 0xb6, 0xa2, 0x3f, 0x01, 0x4d, 0x71, 0x75, 0x7c, 0x9a, 0xa2, - 0x80, 0xb6, 0xeb, 0xdd, 0x95, 0x5e, 0x73, 0xf0, 0xc0, 0xc6, 0x01, 0x1d, 0x1c, 0xd8, 0xa7, 0x3c, - 0x72, 0x96, 0xa2, 0xc0, 0xdd, 0xaa, 0x5a, 0x48, 0x83, 0x5b, 0x1e, 0x48, 0x0b, 0x08, 0x35, 0x0e, - 0x41, 0x6b, 0x9a, 0x8e, 0x33, 0x18, 0x22, 0x3f, 0x85, 0x6c, 0xd2, 0x6e, 0x74, 0x57, 0x7a, 0x0d, - 0xf7, 0xe1, 0x3c, 0x37, 0xdf, 0x52, 0x75, 0xd3, 0xa2, 0x96, 0xd7, 0x54, 0xe6, 0x29, 0x64, 0x13, - 0x03, 0x82, 0x6d, 0x18, 0x45, 0xe4, 0x7b, 0x7f, 0x9a, 0x86, 0x90, 0x21, 0x1f, 0x8e, 0x18, 0xca, - 0x7c, 0x74, 0x9e, 0xe2, 0xec, 0xa2, 0x0d, 0xba, 0xb5, 0x5e, 0xdd, 0xdd, 0x9b, 0xe7, 0x66, 0x57, - 0x12, 0xbd, 0x12, 0x6a, 0xb5, 0x6b, 0xde, 0x96, 0x88, 0x7e, 0x29, 0x82, 0x9f, 0xf0, 0xd8, 0x13, - 0x11, 0x32, 0x28, 0x30, 0x6f, 0xc9, 0x8b, 0x31, 0x1d, 0xa2, 0x09, 0x9c, 0x61, 0x32, 0xcd, 0xda, - 0x4d, 0x21, 0xf4, 0xfe, 0x3c, 0x37, 0xf7, 0x5e, 0x29, 0xa4, 0x27, 0x70, 0xb9, 0xdd, 0x45, 0xb9, - 0xa7, 0x1a, 0xe0, 0x70, 0xf5, 0xc7, 0xdf, 0xcc, 0x25, 0xeb, 0xf7, 0x65, 0x70, 0xff, 0x88, 0x24, - 0x14, 0x25, 0x74, 0x4a, 0xe5, 0x8d, 0x77, 0x41, 0xa3, 0x1c, 0x3a, 0xe2, 0xca, 0xf3, 0x92, 0x2e, - 0xb6, 0xe5, 0x17, 0x05, 0xc2, 0xad, 0xf3, 0x92, 0x3e, 0xe7, 0xdd, 0x57, 0xa5, 0x19, 0x1f, 0x83, - 0xd5, 0x8c, 0x10, 0xa6, 0x66, 0x82, 0xa5, 0x75, 0x44, 0x35, 0x85, 0x66, 0x7d, 0xfb, 0x29, 0xca, - 0x9e, 0x45, 0xc8, 0x23, 0x84, 0xb9, 0xab, 0x9c, 0xc6, 0x13, 0x59, 0xc6, 0x4f, 0x35, 0xb0, 0x99, - 0xa0, 0x73, 0xe6, 0x97, 0x93, 0x96, 0xfa, 0x13, 0x48, 0x27, 0xe2, 0xde, 0xb7, 0xdc, 0xaf, 0xe7, - 0xb9, 0xf9, 0x8e, 0x3c, 0x85, 0xdb, 0x50, 0xd6, 0x3f, 0xb9, 0xf9, 0xe1, 0x18, 0xb3, 0xc9, 0x74, - 0xc8, 0xe5, 0xf4, 0xf9, 0xaf, 0x2d, 0x23, 0x3c, 0xa4, 0xce, 0xf0, 0x82, 0x21, 0x6a, 0x1f, 0xa3, - 0x73, 0x97, 0x2f, 0x3c, 0x83, 0xd3, 0x7d, 0x55, 0xb2, 0x1d, 0x43, 0x3a, 0x51, 0xc7, 0xf4, 0xf3, - 0x32, 0x68, 0xe9, 0xa7, 0x67, 0x1c, 0x80, 0x86, 0x6c, 0xee, 0x72, 0x2e, 0x8a, 0x46, 0x7c, 0x20, - 0xff, 0x56, 0x19, 0xe2, 0x65, 0xa8, 0x4b, 0xeb, 0x24, 0x34, 0x20, 0xa8, 0x4f, 0x10, 0x0c, 0x51, - 0xe6, 0xf7, 0xd5, 0xc9, 0xec, 0xdd, 0x35, 0x2d, 0x8f, 0x05, 0xde, 0xed, 0x5c, 0xe5, 0xe6, 0x9a, - 0x5c, 0xf7, 0xe7, 0xb9, 0xb9, 0x21, 0x65, 0x0a, 0x32, 0xcb, 0x5b, 0x93, 0xcb, 0xbe, 0x26, 0x31, - 0x50, 0x53, 0xf2, 0x7f, 0x48, 0x0c, 0x5e, 0x92, 0x18, 0x94, 0x12, 0x03, 0x75, 0x22, 0xbf, 0xae, - 0x80, 0x7b, 0x12, 0x6d, 0x40, 0xb0, 0x4e, 0xf1, 0x38, 0x41, 0xa1, 0x2f, 0x21, 0xaa, 0x69, 0x3a, - 0xba, 0x8e, 0x7c, 0x11, 0xcf, 0x04, 0x4c, 0x09, 0xee, 0x5e, 0xe6, 0x66, 0xad, 0x9a, 0x05, 0x37, - 0x28, 0x2c, 0xaf, 0x45, 0x35, 0x2c, 0x1f, 0x35, 0x65, 0x95, 0x7d, 0x8a, 0x8a, 0xc6, 0xba, 0x45, - 0xa2, 0x2c, 0xdf, 0x19, 0x62, 0x6e, 0xbb, 0xa2, 0xbf, 0x91, 0x6e, 0x79, 0xad, 0x99, 0x86, 0x33, - 0xbe, 0x03, 0xf2, 0x31, 0x10, 0xfa, 0x62, 0x94, 0xad, 0xdc, 0x39, 0xca, 0x1e, 0xa9, 0x51, 0xf6, - 0xb6, 0xf6, 0xc4, 0x94, 0xf9, 0x96, 0xb7, 0xae, 0x1c, 0x6a, 0x98, 0x45, 0xc0, 0x28, 0x10, 0x55, - 0xbb, 0xaa, 0xe7, 0xe5, 0xae, 0x5d, 0x3c, 0x9a, 0xe7, 0xe6, 0xf6, 0x4d, 0x95, 0x8a, 0xc3, 0xf2, - 0xde, 0x54, 0xce, 0xaa, 0x71, 0xad, 0xcf, 0x40, 0xbd, 0x78, 0x66, 0x8d, 0x5d, 0xd0, 0x48, 0xa6, - 0x31, 0xca, 0x78, 0x44, 0x54, 0x66, 0xd5, 0xab, 0x1c, 0x46, 0x17, 0x34, 0x43, 0x94, 0x90, 0x18, - 0x27, 0x22, 0xbe, 0x2c, 0xe2, 0xba, 0xcb, 0xf5, 0x5f, 0x5c, 0x75, 0x6a, 0x97, 0x57, 0x9d, 0xda, - 0x5f, 0x57, 0x9d, 0xda, 0xf3, 0xeb, 0xce, 0xd2, 0xe5, 0x75, 0x67, 0xe9, 0x8f, 0xeb, 0xce, 0xd2, - 0x37, 0x4f, 0xb4, 0x4b, 0x16, 0x10, 0x1a, 0x13, 0xca, 0x3f, 0xbe, 0xf6, 0xc7, 0xc4, 0x99, 0x1d, - 0x38, 0x31, 0x09, 0xa7, 0x11, 0xa2, 0xf2, 0x53, 0x6c, 0xbf, 0xf8, 0x16, 0xfb, 0xe0, 0xa3, 0xfd, - 0xc5, 0x8f, 0xa5, 0xe1, 0x3d, 0x31, 0x54, 0x0e, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xdd, 0xc8, - 0x3e, 0xfe, 0xba, 0x09, 0x00, 0x00, + 0x0e, 0x48, 0x7b, 0x44, 0x9c, 0x38, 0xf0, 0xc7, 0xec, 0xb1, 0x47, 0x4e, 0x06, 0xb5, 0x57, 0x4e, + 0x39, 0x72, 0x42, 0xf3, 0xc3, 0xf6, 0x34, 0xdb, 0xa5, 0x5a, 0x2e, 0xd1, 0xbc, 0xf7, 0xbe, 0xf7, + 0x7d, 0x99, 0x37, 0x6f, 0xde, 0x18, 0x38, 0x78, 0x18, 0x38, 0x11, 0x1e, 0x4f, 0x58, 0x10, 0x61, + 0x94, 0x30, 0xea, 0x30, 0x94, 0x84, 0x28, 0x8b, 0x71, 0xc2, 0x9c, 0x59, 0x5f, 0xb3, 0xec, 0x34, + 0x23, 0x8c, 0x18, 0x1d, 0x3c, 0x0c, 0x6c, 0x3d, 0xc1, 0xd6, 0x20, 0xb3, 0xfe, 0x4e, 0x57, 0xcb, + 0x67, 0x17, 0x29, 0xa2, 0xce, 0x0c, 0x46, 0x38, 0x84, 0x8c, 0x64, 0x92, 0x61, 0x67, 0xf7, 0x25, + 0x84, 0xf8, 0x55, 0xd1, 0x56, 0x9a, 0x11, 0x32, 0x2a, 0xac, 0xce, 0x98, 0x90, 0x71, 0x84, 0x1c, + 0x61, 0x0d, 0xa7, 0x23, 0x27, 0x9c, 0x66, 0x90, 0x61, 0x92, 0xa8, 0xb8, 0xb9, 0x18, 0x67, 0x38, + 0x46, 0x94, 0xc1, 0x38, 0x2d, 0x00, 0x7c, 0x7f, 0x01, 0xc9, 0x90, 0x23, 0xff, 0x2e, 0xdf, 0x93, + 0x5c, 0x29, 0xc0, 0x7b, 0x15, 0x80, 0xc4, 0x31, 0x66, 0x71, 0x01, 0x2a, 0x2d, 0x05, 0xdc, 0x1c, + 0x93, 0x31, 0x11, 0x4b, 0x87, 0xaf, 0xa4, 0xd7, 0xfa, 0x7b, 0x0d, 0x34, 0x8f, 0x04, 0xdf, 0x19, + 0x83, 0x0c, 0x19, 0xdb, 0xa0, 0x1e, 0x4c, 0x20, 0x4e, 0x7c, 0x1c, 0xb6, 0x6b, 0xdd, 0x5a, 0xaf, + 0xe1, 0xad, 0x09, 0xfb, 0x24, 0x34, 0x10, 0x68, 0xb2, 0x6c, 0x4a, 0x99, 0x1f, 0xa1, 0x19, 0x8a, + 0xda, 0xcb, 0xdd, 0x5a, 0xaf, 0x39, 0xe8, 0xd9, 0xff, 0x5d, 0x4f, 0xfb, 0xd3, 0x0c, 0x06, 0x7c, + 0xc3, 0xee, 0xce, 0x8b, 0xdc, 0x5c, 0x9a, 0xe7, 0xa6, 0x71, 0x01, 0xe3, 0xe8, 0xd0, 0xd2, 0xa8, + 0x2c, 0x0f, 0x08, 0xeb, 0x73, 0x6e, 0x18, 0x23, 0xb0, 0x21, 0x2c, 0x9c, 0x8c, 0xfd, 0x14, 0x65, + 0x98, 0x84, 0xed, 0x15, 0x21, 0xb5, 0x6d, 0xcb, 0x62, 0xd9, 0x45, 0xb1, 0xec, 0xc7, 0xaa, 0x98, + 0xae, 0xa5, 0xb8, 0xb7, 0x34, 0xee, 0x2a, 0xdf, 0xfa, 0xe5, 0x4f, 0xb3, 0xe6, 0xdd, 0x2f, 0xbc, + 0xa7, 0xc2, 0x69, 0x60, 0xf0, 0x60, 0x9a, 0x0c, 0x49, 0x12, 0x6a, 0x42, 0xab, 0x77, 0x09, 0xbd, + 0xab, 0x84, 0x1e, 0x4a, 0xa1, 0x45, 0x02, 0xa9, 0xb4, 0x51, 0xba, 0x95, 0x14, 0x02, 0x1b, 0x31, + 0x3c, 0xf7, 0x83, 0x88, 0x04, 0xcf, 0xfc, 0x30, 0xc3, 0x23, 0xd6, 0x7e, 0xe3, 0x35, 0xb7, 0xb4, + 0x90, 0x2f, 0x85, 0xd6, 0x63, 0x78, 0x7e, 0xc4, 0x9d, 0x8f, 0xb9, 0xcf, 0xf8, 0x16, 0xac, 0x8f, + 0x32, 0xf2, 0x03, 0x4a, 0xfc, 0x09, 0xe2, 0x07, 0xd2, 0xbe, 0x27, 0x44, 0x76, 0xc4, 0x11, 0xf1, + 0x16, 0xb1, 0x55, 0xe7, 0xcc, 0xfa, 0xf6, 0xb1, 0x40, 0xb8, 0xbb, 0x4a, 0x65, 0x53, 0xaa, 0xdc, + 0x48, 0xb7, 0xbc, 0x96, 0xb4, 0x25, 0x96, 0xd3, 0x47, 0x90, 0x21, 0xca, 0x0a, 0xfa, 0xb5, 0xd7, + 0xa5, 0xbf, 0x91, 0x6e, 0x79, 0x2d, 0x69, 0x2b, 0xfa, 0x13, 0xd0, 0x14, 0x57, 0xc7, 0xa7, 0x29, + 0x0a, 0x68, 0xbb, 0xde, 0x5d, 0xe9, 0x35, 0x07, 0x0f, 0x6c, 0x1c, 0xd0, 0xc1, 0x81, 0x7d, 0xca, + 0x23, 0x67, 0x29, 0x0a, 0xdc, 0xad, 0xaa, 0x85, 0x34, 0xb8, 0xe5, 0x81, 0xb4, 0x80, 0x50, 0xe3, + 0x10, 0xb4, 0xa6, 0xe9, 0x38, 0x83, 0x21, 0xf2, 0x53, 0xc8, 0x26, 0xed, 0x46, 0x77, 0xa5, 0xd7, + 0x70, 0x1f, 0xce, 0x73, 0xf3, 0x2d, 0x75, 0x6e, 0x5a, 0xd4, 0xf2, 0x9a, 0xca, 0x3c, 0x85, 0x6c, + 0x62, 0x40, 0xb0, 0x0d, 0xa3, 0x88, 0x7c, 0xef, 0x4f, 0xd3, 0x10, 0x32, 0xe4, 0xc3, 0x11, 0x43, + 0x99, 0x8f, 0xce, 0x53, 0x9c, 0x5d, 0xb4, 0x41, 0xb7, 0xd6, 0xab, 0xbb, 0x7b, 0xf3, 0xdc, 0xec, + 0x4a, 0xa2, 0x57, 0x42, 0xad, 0x76, 0xcd, 0xdb, 0x12, 0xd1, 0x2f, 0x45, 0xf0, 0x13, 0x1e, 0x7b, + 0x22, 0x42, 0x06, 0x05, 0xe6, 0x2d, 0x79, 0x31, 0xa6, 0x43, 0x34, 0x81, 0x33, 0x4c, 0xa6, 0x59, + 0xbb, 0x29, 0x84, 0xde, 0x9f, 0xe7, 0xe6, 0xde, 0x2b, 0x85, 0xf4, 0x04, 0x2e, 0xb7, 0xbb, 0x28, + 0xf7, 0x54, 0x03, 0x1c, 0xae, 0xfe, 0xf8, 0x9b, 0xb9, 0x64, 0xfd, 0xbe, 0x0c, 0xee, 0x1f, 0x91, + 0x84, 0xa2, 0x84, 0x4e, 0xa9, 0xbc, 0xf1, 0x2e, 0x68, 0x94, 0x43, 0x47, 0x5c, 0x79, 0x7e, 0xa4, + 0x8b, 0x6d, 0xf9, 0x45, 0x81, 0x70, 0xeb, 0xfc, 0x48, 0x9f, 0xf3, 0xee, 0xab, 0xd2, 0x8c, 0x8f, + 0xc1, 0x6a, 0x46, 0x08, 0x53, 0x33, 0xc1, 0xd2, 0x3a, 0xa2, 0x9a, 0x42, 0xb3, 0xbe, 0xfd, 0x14, + 0x65, 0xcf, 0x22, 0xe4, 0x11, 0xc2, 0xdc, 0x55, 0x4e, 0xe3, 0x89, 0x2c, 0xe3, 0xa7, 0x1a, 0xd8, + 0x4c, 0xd0, 0x39, 0xf3, 0xcb, 0x49, 0x4b, 0xfd, 0x09, 0xa4, 0x13, 0x71, 0xef, 0x5b, 0xee, 0xd7, + 0xf3, 0xdc, 0x7c, 0x47, 0x56, 0xe1, 0x36, 0x94, 0xf5, 0x4f, 0x6e, 0x7e, 0x38, 0xc6, 0x6c, 0x32, + 0x1d, 0x72, 0x39, 0x7d, 0xfe, 0x6b, 0xcb, 0x08, 0x0f, 0xa9, 0x33, 0xbc, 0x60, 0x88, 0xda, 0xc7, + 0xe8, 0xdc, 0xe5, 0x0b, 0xcf, 0xe0, 0x74, 0x5f, 0x95, 0x6c, 0xc7, 0x90, 0x4e, 0x54, 0x99, 0x7e, + 0x5e, 0x06, 0x2d, 0xbd, 0x7a, 0x46, 0x1f, 0x34, 0x64, 0x73, 0x97, 0x73, 0xd1, 0xdd, 0x9c, 0xe7, + 0xe6, 0x03, 0xf9, 0xb7, 0xca, 0x90, 0xe5, 0xd5, 0xe5, 0xfa, 0x24, 0x34, 0x20, 0xa8, 0x4f, 0x10, + 0x0c, 0x51, 0xe6, 0xf7, 0x55, 0x5d, 0xf6, 0xee, 0x9a, 0x95, 0xc7, 0x02, 0xef, 0x76, 0xae, 0x72, + 0x73, 0x4d, 0xae, 0xfb, 0xf3, 0xdc, 0xdc, 0x90, 0x22, 0x05, 0x99, 0xe5, 0xad, 0xc9, 0x65, 0x5f, + 0x93, 0x18, 0xa8, 0x19, 0xf9, 0x3f, 0x24, 0x06, 0x2f, 0x49, 0x0c, 0x4a, 0x89, 0x81, 0xaa, 0xc7, + 0xaf, 0x2b, 0xe0, 0x9e, 0x44, 0x1b, 0x10, 0xac, 0x53, 0x3c, 0x4e, 0x50, 0xe8, 0x4b, 0x88, 0x6a, + 0x99, 0x8e, 0xae, 0x23, 0xdf, 0xc3, 0x33, 0x01, 0x53, 0x82, 0xbb, 0x97, 0xb9, 0x59, 0xab, 0x26, + 0xc1, 0x0d, 0x0a, 0xcb, 0x6b, 0x51, 0x0d, 0xcb, 0x07, 0x4d, 0x79, 0xc6, 0x3e, 0x45, 0x45, 0x5b, + 0xdd, 0x22, 0x51, 0x1e, 0xde, 0x19, 0x62, 0x6e, 0xbb, 0xa2, 0xbf, 0x91, 0x6e, 0x79, 0xad, 0x99, + 0x86, 0x33, 0xbe, 0x03, 0xf2, 0x29, 0x10, 0xfa, 0x62, 0x90, 0xad, 0xdc, 0x39, 0xc8, 0x1e, 0xa9, + 0x41, 0xf6, 0xb6, 0xf6, 0xc0, 0x94, 0xf9, 0x96, 0xb7, 0xae, 0x1c, 0x6a, 0x94, 0x45, 0xc0, 0x28, + 0x10, 0x55, 0xb3, 0xaa, 0xc7, 0xe5, 0xae, 0x5d, 0x3c, 0x9a, 0xe7, 0xe6, 0xf6, 0x4d, 0x95, 0x8a, + 0xc3, 0xf2, 0xde, 0x54, 0xce, 0xaa, 0x6d, 0xad, 0xcf, 0x40, 0xbd, 0x78, 0x64, 0x8d, 0x5d, 0xd0, + 0x48, 0xa6, 0x31, 0xca, 0x78, 0x44, 0x9c, 0xcc, 0xaa, 0x57, 0x39, 0x8c, 0x2e, 0x68, 0x86, 0x28, + 0x21, 0x31, 0x4e, 0x44, 0x7c, 0x59, 0xc4, 0x75, 0x97, 0xeb, 0xbf, 0xb8, 0xea, 0xd4, 0x2e, 0xaf, + 0x3a, 0xb5, 0xbf, 0xae, 0x3a, 0xb5, 0xe7, 0xd7, 0x9d, 0xa5, 0xcb, 0xeb, 0xce, 0xd2, 0x1f, 0xd7, + 0x9d, 0xa5, 0x6f, 0x9e, 0x68, 0x57, 0x2c, 0x20, 0x34, 0x26, 0x94, 0x7f, 0x7a, 0xed, 0x8f, 0x89, + 0x33, 0x3b, 0x70, 0x62, 0x12, 0x4e, 0x23, 0x44, 0xe5, 0x87, 0xd8, 0x7e, 0xf1, 0x25, 0xf6, 0xc1, + 0x47, 0xfb, 0x8b, 0x9f, 0x4a, 0xc3, 0x7b, 0x62, 0xa4, 0x1c, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, + 0x31, 0x4f, 0x07, 0x47, 0xb8, 0x09, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { diff --git a/proto/ibc/applications/fee/v1/tx.proto b/proto/ibc/applications/fee/v1/tx.proto index f7c4618f54c..f876ea50483 100644 --- a/proto/ibc/applications/fee/v1/tx.proto +++ b/proto/ibc/applications/fee/v1/tx.proto @@ -12,17 +12,17 @@ import "ibc/core/channel/v1/channel.proto"; service Msg { // RegisterPayee defines a rpc handler method for MsgRegisterPayee // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional - // payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which - // packets originate as this is where fee distribution takes place. This function may be called more than once by a - // relayer, in which case, the latest payee is always used. + // payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on + // the source chain from which packets originate as this is where fee distribution takes place. This function may be + // called more than once by a relayer, in which case, the latest payee is always used. rpc RegisterPayee(MsgRegisterPayee) returns (MsgRegisterPayeeResponse); - // RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress - // RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their - // counterparty address before relaying. This ensures they will be properly compensated for forward relaying since - // destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function - // may be called more than once by a relayer, in which case, the latest counterparty address is always used. - rpc RegisterCounterpartyAddress(MsgRegisterCounterpartyAddress) returns (MsgRegisterCounterpartyAddressResponse); + // RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee + // RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty + // payee address before relaying. This ensures they will be properly compensated for forward relaying since + // the destination chain must include the registered counterparty payee address in the acknowledgement. This function + // may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. + rpc RegisterCounterpartyPayee(MsgRegisterCounterpartyPayee) returns (MsgRegisterCounterpartyPayeeResponse); // PayPacketFee defines a rpc handler method for MsgPayPacketFee // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to @@ -47,31 +47,31 @@ message MsgRegisterPayee { // unique channel identifier string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; // the relayer address - string relayer_address = 3 [(gogoproto.moretags) = "yaml:\"relayer_address\""]; - // the fee payee address + string relayer = 3; + // the payee address string payee = 4; } // MsgRegisterPayeeResponse defines the response type for the RegisterPayee rpc message MsgRegisterPayeeResponse {} -// MsgRegisterCounterpartyAddress defines the request type for the RegisterCounterpartyAddress rpc -message MsgRegisterCounterpartyAddress { +// MsgRegisterCounterpartyPayee defines the request type for the RegisterCounterpartyPayee rpc +message MsgRegisterCounterpartyPayee { option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; - // the relayer address - string address = 1; - // the counterparty relayer address - string counterparty_address = 2 [(gogoproto.moretags) = "yaml:\"counterparty_address\""]; // unique port identifier - string port_id = 3 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; // unique channel identifier - string channel_id = 4 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + // the relayer address + string relayer = 3; + // the counterparty payee address + string counterparty_payee = 4 [(gogoproto.moretags) = "yaml:\"counterparty_payee\""]; } -// MsgRegisterCounterpartyAddressResponse defines the response type for the RegisterCounterpartyAddress rpc -message MsgRegisterCounterpartyAddressResponse {} +// MsgRegisterCounterpartyPayeeResponse defines the response type for the RegisterCounterpartyPayee rpc +message MsgRegisterCounterpartyPayeeResponse {} // MsgPayPacketFee defines the request type for the PayPacketFee rpc // This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be From 3a235af89e32322dee29cd9b06bbbe420dc8abab Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 14 Jun 2022 13:19:45 +0200 Subject: [PATCH 157/275] fix to correctly parse denoms with slashes in the base denom (#1451) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix to correctly parse denoms with slashes in the base denom * some logic refinement * review comments * add changelog entry an other review comments * review comment * Add slash migration guide (#1518) * add migration guide * Update docs/migrations/support-slashed-denoms.md Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * clarify upgrade name * remove unnecessary store loader * review comment, update migration code Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Carlos Rodriguez * rename migration file Co-authored-by: Carlos Rodriguez Co-authored-by: Aditya Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> --- CHANGELOG.md | 2 +- .../migrations/support-denoms-with-slashes.md | 101 ++++++++++++++++++ modules/apps/transfer/types/trace.go | 42 ++++++-- modules/apps/transfer/types/trace_test.go | 29 ++++- 4 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 docs/migrations/support-denoms-with-slashes.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0d73923e3..5a64a889fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,7 +80,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output * (apps/29-fee) [\#1278](https://github.com/cosmos/ibc-go/pull/1278) The URI path for the query to get all incentivized packets for a specific channel did not follow the same format as the rest of queries. -* (apps/29-fee)[\#1343](https://github.com/cosmos/ibc-go/pull/1523) Fixed an issue where a bad refund address would prevent channel closure. +* (apps/transfer) [\#1451](https://github.com/cosmos/ibc-go/pull/1451) Fixing the support for base denoms that contain slashes. ## [v3.0.0](https://github.com/cosmos/ibc-go/releases/tag/v3.0.0) - 2022-03-15 diff --git a/docs/migrations/support-denoms-with-slashes.md b/docs/migrations/support-denoms-with-slashes.md new file mode 100644 index 00000000000..829849bc25a --- /dev/null +++ b/docs/migrations/support-denoms-with-slashes.md @@ -0,0 +1,101 @@ +# Migrating from not supporing base denoms with slashes to supporting base denoms with slashes + +This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. +Any changes that must be done by a user of ibc-go should be documented here. + +There are four sections based on the four potential user groups of this document: +- Chains +- IBC Apps +- Relayers +- IBC Light Clients + +This document is necessary when chains are upgrading from a version that does not support base denoms with slashes (e.g. v3.0.0) to a version that does (e.g. v3.1.0). All versions of ibc-go smaller than v1.5.0 for the v1.x release line, v2.3.0 for the v2.x release line, and v3.1.0 for the v3.x release line do *NOT** support IBC token transfers of coins whose base denoms contain slashes. Therefore the in-place of genesis migration described in this document are required when upgrading. + +If a chain receives coins of a base denom with slashes before it upgrades to supporting it, the receive may pass however the trace information will be incorrect. + +E.g. If a base denom of `testcoin/testcoin/testcoin` is sent to a chain that does not support slashes in the base denom, the receive will be successful. However, the trace information stored on the receiving chain will be: `Trace: "transfer/{channel-id}/testcoin/testcoin", BaseDenom: "testcoin"`. + +This incorrect trace information must be corrected when the chain does upgrade to fully supporting denominations with slashes. + +To do so, chain binaries should include a migration script that will run when the chain upgrades from not supporting base denominations with slashes to supporting base denominations with slashes. + +## Chains + +### ICS20 - Transfer + +The transfer module will now support slashes in base denoms, so we must iterate over current traces to check if any of them are incorrectly formed and correct the trace information. + +### Upgrade Proposal + +```go +// Here the upgrade name is the upgrade name set by the chain +app.UpgradeKeeper.SetUpgradeHandler("supportSlashedDenomsUpgrade", + func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + // list of traces that must replace the old traces in store + var newTraces []ibctransfertypes.DenomTrace + app.TransferKeeper.IterateDenomTraces(ctx, + func(dt ibctransfertypes.DenomTrace) bool { + // check if the new way of splitting FullDenom + // into Trace and BaseDenom passes validation and + // is the same as the current DenomTrace. + // If it isn't then store the new DenomTrace in the list of new traces. + newTrace := ibctransfertypes.ParseDenomTrace(dt.GetFullDenomPath()) + if err := newTrace.Validate(); err == nil && !reflect.DeepEqual(newTrace, dt) { + newTraces = append(newTraces, newTrace) + } + + return false + }) + + // replace the outdated traces with the new trace information + for _, nt := range newTraces { + app.TransferKeeper.SetDenomTrace(ctx, nt) + } + + return app.mm.RunMigrations(ctx, app.configurator, fromVM) + }) +``` + +This is only necessary if there are denom traces in the store with incorrect trace information from previously received coins that had a slash in the base denom. However, it is recommended that any chain upgrading to support base denominations with slashes runs this code for safety. + +For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1527). + +### Genesis Migration + +If the chain chooses to add support for slashes in base denoms via genesis export, then the trace information must be corrected during genesis migration. + +The migration code required may look like: + +```go +func migrateGenesisSlashedDenomsUpgrade(appState genutiltypes.AppMap, clientCtx client.Context, genDoc *tmtypes.GenesisDoc) (genutiltypes.AppMap, error) { + if appState[ibctransfertypes.ModuleName] != nil { + transferGenState := &ibctransfertypes.GenesisState{} + clientCtx.Codec.MustUnmarshalJSON(appState[ibctransfertypes.ModuleName], transferGenState) + + substituteTraces := make([]ibctransfertypes.DenomTrace, len(transferGenState.DenomTraces)) + for i, dt := range transferGenState.DenomTraces { + // replace all previous traces with the latest trace if validation passes + // note most traces will have same value + newTrace := ibctransfertypes.ParseDenomTrace(dt.GetFullDenomPath()) + + if err := newTrace.Validate(); err != nil { + substituteTraces[i] = dt + } else { + substituteTraces[i] = newTrace + } + } + + transferGenState.DenomTraces = substituteTraces + + // delete old genesis state + delete(appState, ibctransfertypes.ModuleName) + + // set new ibc transfer genesis state + appState[ibctransfertypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(transferGenState) + } + + return appState, nil +} +``` + +For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1528). \ No newline at end of file diff --git a/modules/apps/transfer/types/trace.go b/modules/apps/transfer/types/trace.go index 303ddd3769e..e0a68ef8d9b 100644 --- a/modules/apps/transfer/types/trace.go +++ b/modules/apps/transfer/types/trace.go @@ -20,8 +20,11 @@ import ( // // Examples: // -// - "portidone/channelidone/uatom" => DenomTrace{Path: "portidone/channelidone", BaseDenom: "uatom"} -// - "uatom" => DenomTrace{Path: "", BaseDenom: "uatom"} +// - "transfer/channelidone/uatom" => DenomTrace{Path: "transfer/channelidone", BaseDenom: "uatom"} +// - "transfer/channelidone/transfer/channelidtwo/uatom" => DenomTrace{Path: "transfer/channelidone/transfer/channelidtwo", BaseDenom: "uatom"} +// - "transfer/channelidone/gamm/pool/1" => DenomTrace{Path: "transfer/channelidone", BaseDenom: "gamm/pool/1"} +// - "gamm/pool/1" => DenomTrace{Path: "", BaseDenom: "gamm/pool/1"} +// - "uatom" => DenomTrace{Path: "", BaseDenom: "uatom"} func ParseDenomTrace(rawDenom string) DenomTrace { denomSplit := strings.Split(rawDenom, "/") @@ -32,9 +35,10 @@ func ParseDenomTrace(rawDenom string) DenomTrace { } } + path, baseDenom := extractPathAndBaseFromFullDenom(denomSplit) return DenomTrace{ - Path: strings.Join(denomSplit[:len(denomSplit)-1], "/"), - BaseDenom: denomSplit[len(denomSplit)-1], + Path: path, + BaseDenom: baseDenom, } } @@ -70,6 +74,24 @@ func (dt DenomTrace) GetFullDenomPath() string { return dt.GetPrefix() + dt.BaseDenom } +// extractPathAndBaseFromFullDenom returns the trace path and the base denom from +// the elements that constitute the complete denom. +func extractPathAndBaseFromFullDenom(fullDenomItems []string) (string, string) { + var path []string + var baseDenom []string + length := len(fullDenomItems) + for i := 0; i < length; i = i + 2 { + if i < length-1 && length > 2 && fullDenomItems[i] == PortID { + path = append(path, fullDenomItems[i], fullDenomItems[i+1]) + } else { + baseDenom = fullDenomItems[i:] + break + } + } + + return strings.Join(path, "/"), strings.Join(baseDenom, "/") +} + func validateTraceIdentifiers(identifiers []string) error { if len(identifiers) == 0 || len(identifiers)%2 != 0 { return fmt.Errorf("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}', got the identifiers: %s", identifiers) @@ -143,8 +165,10 @@ func (t Traces) Sort() Traces { // ValidatePrefixedDenom checks that the denomination for an IBC fungible token packet denom is correctly prefixed. // The function will return no error if the given string follows one of the two formats: // -// - Prefixed denomination: '{portIDN}/{channelIDN}/.../{portID0}/{channelID0}/baseDenom' +// - Prefixed denomination: 'transfer/{channelIDN}/.../transfer/{channelID0}/baseDenom' // - Unprefixed denomination: 'baseDenom' +// +// 'baseDenom' may or may not contain '/'s func ValidatePrefixedDenom(denom string) error { denomSplit := strings.Split(denom, "/") if denomSplit[0] == denom && strings.TrimSpace(denom) != "" { @@ -156,7 +180,13 @@ func ValidatePrefixedDenom(denom string) error { return sdkerrors.Wrap(ErrInvalidDenomForTransfer, "base denomination cannot be blank") } - identifiers := denomSplit[:len(denomSplit)-1] + path, _ := extractPathAndBaseFromFullDenom(denomSplit) + if path == "" { + // NOTE: base denom contains slashes, so no base denomination validation + return nil + } + + identifiers := strings.Split(path, "/") return validateTraceIdentifiers(identifiers) } diff --git a/modules/apps/transfer/types/trace_test.go b/modules/apps/transfer/types/trace_test.go index e35fd33317b..6526cbd952d 100644 --- a/modules/apps/transfer/types/trace_test.go +++ b/modules/apps/transfer/types/trace_test.go @@ -14,10 +14,23 @@ func TestParseDenomTrace(t *testing.T) { }{ {"empty denom", "", DenomTrace{}}, {"base denom", "uatom", DenomTrace{BaseDenom: "uatom"}}, + {"base denom ending with '/'", "uatom/", DenomTrace{BaseDenom: "uatom/"}}, + {"base denom with single '/'s", "gamm/pool/1", DenomTrace{BaseDenom: "gamm/pool/1"}}, + {"base denom with double '/'s", "gamm//pool//1", DenomTrace{BaseDenom: "gamm//pool//1"}}, {"trace info", "transfer/channelToA/uatom", DenomTrace{BaseDenom: "uatom", Path: "transfer/channelToA"}}, - {"incomplete path", "transfer/uatom", DenomTrace{BaseDenom: "uatom", Path: "transfer"}}, + {"trace info with base denom ending in '/'", "transfer/channelToA/uatom/", DenomTrace{BaseDenom: "uatom/", Path: "transfer/channelToA"}}, + {"trace info with single '/' in base denom", "transfer/channelToA/erc20/0x85bcBCd7e79Ec36f4fBBDc54F90C643d921151AA", DenomTrace{BaseDenom: "erc20/0x85bcBCd7e79Ec36f4fBBDc54F90C643d921151AA", Path: "transfer/channelToA"}}, + {"trace info with multiple '/'s in base denom", "transfer/channelToA/gamm/pool/1", DenomTrace{BaseDenom: "gamm/pool/1", Path: "transfer/channelToA"}}, + {"trace info with multiple double '/'s in base denom", "transfer/channelToA/gamm//pool//1", DenomTrace{BaseDenom: "gamm//pool//1", Path: "transfer/channelToA"}}, + {"trace info with multiple port/channel pairs", "transfer/channelToA/transfer/channelToB/uatom", DenomTrace{BaseDenom: "uatom", Path: "transfer/channelToA/transfer/channelToB"}}, + {"incomplete path", "transfer/uatom", DenomTrace{BaseDenom: "transfer/uatom"}}, {"invalid path (1)", "transfer//uatom", DenomTrace{BaseDenom: "uatom", Path: "transfer/"}}, - {"invalid path (2)", "transfer/channelToA/uatom/", DenomTrace{BaseDenom: "", Path: "transfer/channelToA/uatom"}}, + {"invalid path (2)", "channelToA/transfer/uatom", DenomTrace{BaseDenom: "channelToA/transfer/uatom"}}, + {"invalid path (3)", "uatom/transfer", DenomTrace{BaseDenom: "uatom/transfer"}}, + {"invalid path (4)", "transfer/channelToA", DenomTrace{BaseDenom: "transfer/channelToA"}}, + {"invalid path (5)", "transfer/channelToA/", DenomTrace{Path: "transfer/channelToA"}}, + {"invalid path (6)", "transfer/channelToA/transfer", DenomTrace{BaseDenom: "transfer", Path: "transfer/channelToA"}}, + {"invalid path (7)", "transfer/channelToA/transfer/channelToB", DenomTrace{Path: "transfer/channelToA/transfer/channelToB"}}, } for _, tc := range testCases { @@ -49,6 +62,8 @@ func TestDenomTrace_Validate(t *testing.T) { expError bool }{ {"base denom only", DenomTrace{BaseDenom: "uatom"}, false}, + {"base denom only with single '/'", DenomTrace{BaseDenom: "erc20/0x85bcBCd7e79Ec36f4fBBDc54F90C643d921151AA"}, false}, + {"base denom only with multiple '/'s", DenomTrace{BaseDenom: "gamm/pool/1"}, false}, {"empty DenomTrace", DenomTrace{}, true}, {"valid single trace info", DenomTrace{BaseDenom: "uatom", Path: "transfer/channelToA"}, false}, {"valid multiple trace info", DenomTrace{BaseDenom: "uatom", Path: "transfer/channelToA/transfer/channelToB"}, false}, @@ -104,12 +119,15 @@ func TestValidatePrefixedDenom(t *testing.T) { expError bool }{ {"prefixed denom", "transfer/channelToA/uatom", false}, + {"prefixed denom with '/'", "transfer/channelToA/gamm/pool/1", false}, + {"empty prefix", "/uatom", false}, + {"empty identifiers", "//uatom", false}, {"base denom", "uatom", false}, + {"base denom with single '/'", "erc20/0x85bcBCd7e79Ec36f4fBBDc54F90C643d921151AA", false}, + {"base denom with multiple '/'s", "gamm/pool/1", false}, + {"invalid port ID", "(transfer)/channelToA/uatom", false}, {"empty denom", "", true}, - {"empty prefix", "/uatom", true}, - {"empty identifiers", "//uatom", true}, {"single trace identifier", "transfer/", true}, - {"invalid port ID", "(transfer)/channelToA/uatom", true}, {"invalid channel ID", "transfer/(channelToA)/uatom", true}, } @@ -131,6 +149,7 @@ func TestValidateIBCDenom(t *testing.T) { }{ {"denom with trace hash", "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", false}, {"base denom", "uatom", false}, + {"base denom ending with '/'", "uatom/", false}, {"base denom with single '/'s", "gamm/pool/1", false}, {"base denom with double '/'s", "gamm//pool//1", false}, {"non-ibc prefix with hash", "notibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", false}, From b8b0787f4fd79d71e58c935dc47ba9dd7ee919ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jun 2022 14:27:07 +0100 Subject: [PATCH 158/275] build(deps): bump docker/metadata-action from 3.3.0 to 4.0.1 (#1538) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4b42de16645..0ceac7f4ebc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,7 +41,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + uses: docker/metadata-action@69f6fc9d46f2f8bf0d5491e4aabe0bb8c6a4678a with: images: ${{ env.REGISTRY }}/cosmos/${{ env.IMAGE_NAME }} From de49b9a65cef38921e2c762c772e1f67fee2f7fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jun 2022 14:33:57 +0100 Subject: [PATCH 159/275] build(deps): bump docker/login-action from 1.10.0 to 2 (#1540) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0ceac7f4ebc..5bc55c53045 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Log in to the Container registry - uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} From 1efe10f651432207cd808d075c605a328d241ede Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jun 2022 14:41:18 +0100 Subject: [PATCH 160/275] build(deps): bump docker/build-push-action from 2.5.0 to 3 (#1539) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5bc55c53045..f59f0c63d25 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,7 +46,7 @@ jobs: images: ${{ env.REGISTRY }}/cosmos/${{ env.IMAGE_NAME }} - name: Build and push Docker image - uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + uses: docker/build-push-action@e551b19e49efd4e98792db7592c17c09b89db8d8 with: context: . push: true From c04adf359eb9bc5433bc3afa6a22fd8708514ceb Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 14 Jun 2022 22:21:44 +0200 Subject: [PATCH 161/275] replace reflect.DeepEqual with custom comparison function because DeepEqual might not be deterministic --- docs/migrations/support-denoms-with-slashes.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/migrations/support-denoms-with-slashes.md b/docs/migrations/support-denoms-with-slashes.md index 829849bc25a..fdbcfa64209 100644 --- a/docs/migrations/support-denoms-with-slashes.md +++ b/docs/migrations/support-denoms-with-slashes.md @@ -40,7 +40,7 @@ app.UpgradeKeeper.SetUpgradeHandler("supportSlashedDenomsUpgrade", // is the same as the current DenomTrace. // If it isn't then store the new DenomTrace in the list of new traces. newTrace := ibctransfertypes.ParseDenomTrace(dt.GetFullDenomPath()) - if err := newTrace.Validate(); err == nil && !reflect.DeepEqual(newTrace, dt) { + if err := newTrace.Validate(); err == nil && !equalTraces(newTrace, dt) { newTraces = append(newTraces, newTrace) } @@ -54,6 +54,10 @@ app.UpgradeKeeper.SetUpgradeHandler("supportSlashedDenomsUpgrade", return app.mm.RunMigrations(ctx, app.configurator, fromVM) }) + +func equalTraces(dtA, dtB ibctransfertypes.DenomTrace) bool { + return dtA.BaseDenom == dtB.BaseDenom && dtA.Path == dtB.Path +} ``` This is only necessary if there are denom traces in the store with incorrect trace information from previously received coins that had a slash in the base denom. However, it is recommended that any chain upgrading to support base denominations with slashes runs this code for safety. @@ -98,4 +102,4 @@ func migrateGenesisSlashedDenomsUpgrade(appState genutiltypes.AppMap, clientCtx } ``` -For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1528). \ No newline at end of file +For a more detailed sample, please check out the code changes in [this pull request](https://github.com/cosmos/ibc-go/pull/1528). From 2824717afd433d9a9ecfebd7ddfee2ccf5712c52 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 15 Jun 2022 09:54:06 +0200 Subject: [PATCH 162/275] docs: update ICA auth module section about RegisterInterchainAccount (#1516) --- docs/apps/interchain-accounts/auth-modules.md | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/docs/apps/interchain-accounts/auth-modules.md b/docs/apps/interchain-accounts/auth-modules.md index 0e8738f50c0..fdff2385282 100644 --- a/docs/apps/interchain-accounts/auth-modules.md +++ b/docs/apps/interchain-accounts/auth-modules.md @@ -150,13 +150,67 @@ func (im IBCModule) OnRecvPacket( The authentication module can begin registering interchain accounts by calling `RegisterInterchainAccount`: ```go -if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String()); err != nil { +if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner.String(), version); err != nil { return err } return nil ``` +The `version` argument is used to support ICS29 fee middleware for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. + +The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: + +```go +icaMetadata := icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: controllerConnectionID, + HostConnectionId: hostConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, +} + +appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) +if err != nil { + return err +} + +if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(appVersion)); err != nil { + return err +} +``` + +Similarly, if the application stack is configured to route through ICS29 fee middleware and a fee enabled channel is desired, construct the appropriate ICS29 `Metadata` type: + +```go +icaMetadata := icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: controllerConnectionID, + HostConnectionId: hostConnectionID, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, +} + +appVersion, err := icatypes.ModuleCdc.MarshalJSON(&icaMetadata) +if err != nil { + return err +} + +feeMetadata := feetypes.Metadata{ + AppVersion: string(appVersion), + FeeVersion: feetypes.Version, +} + +feeEnabledVersion, err := feetypes.ModuleCdc.MarshalJSON(&feeMetadata) +if err != nil { + return err +} + +if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, controllerConnectionID, owner.String(), string(feeEnabledVersion)); err != nil { + return err +} +``` + ## `SendTx` The authentication module can attempt to send a packet by calling `SendTx`: From 0252bfb4edd62db52b80d01b0e235ff8b51efc8f Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 Jun 2022 11:16:02 +0200 Subject: [PATCH 163/275] refactor: rename genesis type RegisteredRelayer to RegisteredCounterpartyPayee (#1514) * renaming counterparty address rpc to counterparty payee * rename genesis types for registered counterparty payees * updating counterparty payee cli * reorder cli cmd list * Apply suggestions from code review Co-authored-by: Charly * removing address suffix from msg fields, updating protodoc and godoc * updating cli args naming convention to align * propagating renaming of fields to genesis state * rename GetAllx funcs and updating godocs * reordering genesis types fields Co-authored-by: Charly --- docs/ibc/proto-docs.md | 25 +- modules/apps/29-fee/keeper/genesis.go | 22 +- modules/apps/29-fee/keeper/genesis_test.go | 65 +++-- modules/apps/29-fee/keeper/keeper.go | 30 +-- modules/apps/29-fee/keeper/keeper_test.go | 26 +- modules/apps/29-fee/types/genesis.go | 44 +-- modules/apps/29-fee/types/genesis.pb.go | 279 ++++++++++---------- modules/apps/29-fee/types/genesis_test.go | 23 +- proto/ibc/applications/fee/v1/genesis.proto | 29 +- 9 files changed, 279 insertions(+), 264 deletions(-) diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 9d0cf13eb4e..1641af76b8e 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -38,8 +38,8 @@ - [FeeEnabledChannel](#ibc.applications.fee.v1.FeeEnabledChannel) - [ForwardRelayerAddress](#ibc.applications.fee.v1.ForwardRelayerAddress) - [GenesisState](#ibc.applications.fee.v1.GenesisState) + - [RegisteredCounterpartyPayee](#ibc.applications.fee.v1.RegisteredCounterpartyPayee) - [RegisteredPayee](#ibc.applications.fee.v1.RegisteredPayee) - - [RegisteredRelayerAddress](#ibc.applications.fee.v1.RegisteredRelayerAddress) - [ibc/applications/fee/v1/metadata.proto](#ibc/applications/fee/v1/metadata.proto) - [Metadata](#ibc.applications.fee.v1.Metadata) @@ -848,7 +848,7 @@ GenesisState defines the ICS29 fee middleware genesis state | `identified_fees` | [IdentifiedPacketFees](#ibc.applications.fee.v1.IdentifiedPacketFees) | repeated | list of identified packet fees | | `fee_enabled_channels` | [FeeEnabledChannel](#ibc.applications.fee.v1.FeeEnabledChannel) | repeated | list of fee enabled channels | | `registered_payees` | [RegisteredPayee](#ibc.applications.fee.v1.RegisteredPayee) | repeated | list of registered payees | -| `registered_relayers` | [RegisteredRelayerAddress](#ibc.applications.fee.v1.RegisteredRelayerAddress) | repeated | list of registered relayer addresses | +| `registered_counterparty_payees` | [RegisteredCounterpartyPayee](#ibc.applications.fee.v1.RegisteredCounterpartyPayee) | repeated | list of registered counterparty payees | | `forward_relayers` | [ForwardRelayerAddress](#ibc.applications.fee.v1.ForwardRelayerAddress) | repeated | list of forward relayer addresses | @@ -856,34 +856,35 @@ GenesisState defines the ICS29 fee middleware genesis state - + -### RegisteredPayee -RegisteredPayee contains the relayer address and payee address for a specific channel +### RegisteredCounterpartyPayee +RegisteredCounterpartyPayee contains the relayer address and counterparty payee address for a specific channel (used +for recv fee distribution) | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `relayer_address` | [string](#string) | | the relayer address | -| `payee` | [string](#string) | | the payee address | | `channel_id` | [string](#string) | | unique channel identifier | +| `relayer` | [string](#string) | | the relayer address | +| `counterparty_payee` | [string](#string) | | the counterparty payee address | - + -### RegisteredRelayerAddress -RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) +### RegisteredPayee +RegisteredPayee contains the relayer address and payee address for a specific channel | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `address` | [string](#string) | | the relayer address | -| `counterparty_address` | [string](#string) | | the counterparty relayer address | | `channel_id` | [string](#string) | | unique channel identifier | +| `relayer` | [string](#string) | | the relayer address | +| `payee` | [string](#string) | | the payee address | diff --git a/modules/apps/29-fee/keeper/genesis.go b/modules/apps/29-fee/keeper/genesis.go index eb7b1fd7095..6d6f01b7b34 100644 --- a/modules/apps/29-fee/keeper/genesis.go +++ b/modules/apps/29-fee/keeper/genesis.go @@ -12,8 +12,12 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { k.SetFeesInEscrow(ctx, identifiedFees.PacketId, types.NewPacketFees(identifiedFees.PacketFees)) } - for _, relayer := range state.RegisteredRelayers { - k.SetCounterpartyPayeeAddress(ctx, relayer.Address, relayer.CounterpartyAddress, relayer.ChannelId) + for _, registeredPayee := range state.RegisteredPayees { + k.SetPayeeAddress(ctx, registeredPayee.Relayer, registeredPayee.Payee, registeredPayee.ChannelId) + } + + for _, registeredCounterpartyPayee := range state.RegisteredCounterpartyPayees { + k.SetCounterpartyPayeeAddress(ctx, registeredCounterpartyPayee.Relayer, registeredCounterpartyPayee.CounterpartyPayee, registeredCounterpartyPayee.ChannelId) } for _, forwardAddr := range state.ForwardRelayers { @@ -23,19 +27,15 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { for _, enabledChan := range state.FeeEnabledChannels { k.SetFeeEnabled(ctx, enabledChan.PortId, enabledChan.ChannelId) } - - for _, registeredPayee := range state.RegisteredPayees { - k.SetPayeeAddress(ctx, registeredPayee.RelayerAddress, registeredPayee.Payee, registeredPayee.ChannelId) - } } // ExportGenesis returns the fee middleware application exported genesis func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { return &types.GenesisState{ - IdentifiedFees: k.GetAllIdentifiedPacketFees(ctx), - FeeEnabledChannels: k.GetAllFeeEnabledChannels(ctx), - RegisteredRelayers: k.GetAllRelayerAddresses(ctx), - ForwardRelayers: k.GetAllForwardRelayerAddresses(ctx), - RegisteredPayees: k.GetAllPayeeAddresses(ctx), + IdentifiedFees: k.GetAllIdentifiedPacketFees(ctx), + FeeEnabledChannels: k.GetAllFeeEnabledChannels(ctx), + RegisteredPayees: k.GetAllPayeeAddresses(ctx), + RegisteredCounterpartyPayees: k.GetAllCounterpartyPayees(ctx), + ForwardRelayers: k.GetAllForwardRelayerAddresses(ctx), } } diff --git a/modules/apps/29-fee/keeper/genesis_test.go b/modules/apps/29-fee/keeper/genesis_test.go index 05b8c907bb4..f26a1b9116d 100644 --- a/modules/apps/29-fee/keeper/genesis_test.go +++ b/modules/apps/29-fee/keeper/genesis_test.go @@ -28,18 +28,18 @@ func (suite *KeeperTestSuite) TestInitGenesis() { ChannelId: ibctesting.FirstChannelID, }, }, - RegisteredRelayers: []types.RegisteredRelayerAddress{ + RegisteredPayees: []types.RegisteredPayee{ { - Address: suite.chainA.SenderAccount.GetAddress().String(), - CounterpartyAddress: suite.chainB.SenderAccount.GetAddress().String(), - ChannelId: ibctesting.FirstChannelID, + Relayer: suite.chainA.SenderAccount.GetAddress().String(), + Payee: suite.chainB.SenderAccount.GetAddress().String(), + ChannelId: ibctesting.FirstChannelID, }, }, - RegisteredPayees: []types.RegisteredPayee{ + RegisteredCounterpartyPayees: []types.RegisteredCounterpartyPayee{ { - RelayerAddress: suite.chainA.SenderAccount.GetAddress().String(), - Payee: suite.chainB.SenderAccount.GetAddress().String(), - ChannelId: ibctesting.FirstChannelID, + Relayer: suite.chainA.SenderAccount.GetAddress().String(), + CounterpartyPayee: suite.chainB.SenderAccount.GetAddress().String(), + ChannelId: ibctesting.FirstChannelID, }, }, } @@ -55,15 +55,15 @@ func (suite *KeeperTestSuite) TestInitGenesis() { isEnabled := suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), ibctesting.MockFeePort, ibctesting.FirstChannelID) suite.Require().True(isEnabled) - // check relayers - addr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) - suite.Require().True(found) - suite.Require().Equal(genesisState.RegisteredRelayers[0].CounterpartyAddress, addr) - // check payee addresses payeeAddr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) suite.Require().True(found) suite.Require().Equal(genesisState.RegisteredPayees[0].Payee, payeeAddr) + + // check relayers + counterpartyPayeeAddr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetCounterpartyPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) + suite.Require().True(found) + suite.Require().Equal(genesisState.RegisteredCounterpartyPayees[0].CounterpartyPayee, counterpartyPayeeAddr) } func (suite *KeeperTestSuite) TestExportGenesis() { @@ -78,17 +78,24 @@ func (suite *KeeperTestSuite) TestExportGenesis() { packetFee := types.NewPacketFee(fee, refundAcc.String(), []string{}) suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) - // relayer addresses - sender := suite.chainA.SenderAccount.GetAddress().String() - counterparty := suite.chainB.SenderAccount.GetAddress().String() - // set counterparty address - suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID) + // set payee address + suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + ibctesting.FirstChannelID, + ) + + // set counterparty payee address + suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + ibctesting.FirstChannelID, + ) // set forward relayer address - suite.chainA.GetSimApp().IBCFeeKeeper.SetRelayerAddressForAsyncAck(suite.chainA.GetContext(), packetID, sender) - - // set payee address - suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), ibctesting.FirstChannelID) + suite.chainA.GetSimApp().IBCFeeKeeper.SetRelayerAddressForAsyncAck(suite.chainA.GetContext(), packetID, suite.chainA.SenderAccount.GetAddress().String()) // export genesis genesisState := suite.chainA.GetSimApp().IBCFeeKeeper.ExportGenesis(suite.chainA.GetContext()) @@ -103,17 +110,17 @@ func (suite *KeeperTestSuite) TestExportGenesis() { suite.Require().Equal(refundAcc.String(), genesisState.IdentifiedFees[0].PacketFees[0].RefundAddress) suite.Require().Equal([]string(nil), genesisState.IdentifiedFees[0].PacketFees[0].Relayers) - // check registered relayer addresses - suite.Require().Equal(sender, genesisState.RegisteredRelayers[0].Address) - suite.Require().Equal(counterparty, genesisState.RegisteredRelayers[0].CounterpartyAddress) - suite.Require().Equal(ibctesting.FirstChannelID, genesisState.RegisteredRelayers[0].ChannelId) - // check forward relayer addresses - suite.Require().Equal(sender, genesisState.ForwardRelayers[0].Address) + suite.Require().Equal(suite.chainA.SenderAccount.GetAddress().String(), genesisState.ForwardRelayers[0].Address) suite.Require().Equal(packetID, genesisState.ForwardRelayers[0].PacketId) // check payee addresses - suite.Require().Equal(suite.chainA.SenderAccount.GetAddress().String(), genesisState.RegisteredPayees[0].RelayerAddress) + suite.Require().Equal(suite.chainA.SenderAccount.GetAddress().String(), genesisState.RegisteredPayees[0].Relayer) suite.Require().Equal(suite.chainB.SenderAccount.GetAddress().String(), genesisState.RegisteredPayees[0].Payee) suite.Require().Equal(ibctesting.FirstChannelID, genesisState.RegisteredPayees[0].ChannelId) + + // check registered counterparty payee addresses + suite.Require().Equal(suite.chainA.SenderAccount.GetAddress().String(), genesisState.RegisteredCounterpartyPayees[0].Relayer) + suite.Require().Equal(suite.chainB.SenderAccount.GetAddress().String(), genesisState.RegisteredCounterpartyPayees[0].CounterpartyPayee) + suite.Require().Equal(ibctesting.FirstChannelID, genesisState.RegisteredCounterpartyPayees[0].ChannelId) } diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index c8ccc9a0e6c..143acafb80d 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -165,7 +165,7 @@ func (k Keeper) SetPayeeAddress(ctx sdk.Context, relayerAddr, payeeAddr, channel store.Set(types.KeyPayee(relayerAddr, channelID), []byte(payeeAddr)) } -// GetAllPayeeAddresses returns all registered payees +// GetAllPayeeAddresses returns all registered payees addresses func (k Keeper) GetAllPayeeAddresses(ctx sdk.Context) []types.RegisteredPayee { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte(types.PayeeKeyPrefix)) @@ -173,15 +173,15 @@ func (k Keeper) GetAllPayeeAddresses(ctx sdk.Context) []types.RegisteredPayee { var registeredPayees []types.RegisteredPayee for ; iterator.Valid(); iterator.Next() { - addr, channelID, err := types.ParseKeyPayeeAddress(string(iterator.Key())) + relayerAddr, channelID, err := types.ParseKeyPayeeAddress(string(iterator.Key())) if err != nil { panic(err) } payee := types.RegisteredPayee{ - RelayerAddress: addr, - Payee: string(iterator.Value()), - ChannelId: channelID, + Relayer: relayerAddr, + Payee: string(iterator.Value()), + ChannelId: channelID, } registeredPayees = append(registeredPayees, payee) @@ -210,29 +210,29 @@ func (k Keeper) GetCounterpartyPayeeAddress(ctx sdk.Context, address, channelID return addr, true } -// GetAllRelayerAddresses returns all registered relayer addresses -func (k Keeper) GetAllRelayerAddresses(ctx sdk.Context) []types.RegisteredRelayerAddress { +// GetAllCounterpartyPayees returns all registered counterparty payee addresses +func (k Keeper) GetAllCounterpartyPayees(ctx sdk.Context) []types.RegisteredCounterpartyPayee { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte(types.CounterpartyPayeeKeyPrefix)) defer iterator.Close() - var registeredAddrArr []types.RegisteredRelayerAddress + var registeredCounterpartyPayees []types.RegisteredCounterpartyPayee for ; iterator.Valid(); iterator.Next() { - address, channelID, err := types.ParseKeyCounterpartyPayee(string(iterator.Key())) + relayerAddr, channelID, err := types.ParseKeyCounterpartyPayee(string(iterator.Key())) if err != nil { panic(err) } - addr := types.RegisteredRelayerAddress{ - Address: address, - CounterpartyAddress: string(iterator.Value()), - ChannelId: channelID, + counterpartyPayee := types.RegisteredCounterpartyPayee{ + Relayer: relayerAddr, + CounterpartyPayee: string(iterator.Value()), + ChannelId: channelID, } - registeredAddrArr = append(registeredAddrArr, addr) + registeredCounterpartyPayees = append(registeredCounterpartyPayees, counterpartyPayee) } - return registeredAddrArr + return registeredCounterpartyPayees } // SetRelayerAddressForAsyncAck sets the forward relayer address during OnRecvPacket in case of async acknowledgement diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index b322cb07c60..1b6b0ede99f 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -259,22 +259,22 @@ func (suite *KeeperTestSuite) TestGetAllFeeEnabledChannels() { } func (suite *KeeperTestSuite) TestGetAllRelayerAddresses() { - sender := suite.chainA.SenderAccount.GetAddress().String() - counterparty := suite.chainB.SenderAccount.GetAddress().String() + relayerAddr := suite.chainA.SenderAccount.GetAddress().String() + counterpartyPayee := suite.chainB.SenderAccount.GetAddress().String() - suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainA.GetContext(), sender, counterparty, ibctesting.FirstChannelID) + suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainA.GetContext(), relayerAddr, counterpartyPayee, ibctesting.FirstChannelID) - expectedAddr := []types.RegisteredRelayerAddress{ + expectedCounterpartyPayee := []types.RegisteredCounterpartyPayee{ { - Address: sender, - CounterpartyAddress: counterparty, - ChannelId: ibctesting.FirstChannelID, + Relayer: relayerAddr, + CounterpartyPayee: counterpartyPayee, + ChannelId: ibctesting.FirstChannelID, }, } - addr := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllRelayerAddresses(suite.chainA.GetContext()) - suite.Require().Len(addr, len(expectedAddr)) - suite.Require().Equal(addr, expectedAddr) + counterpartyPayeeAddr := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllCounterpartyPayees(suite.chainA.GetContext()) + suite.Require().Len(counterpartyPayeeAddr, len(expectedCounterpartyPayee)) + suite.Require().Equal(counterpartyPayeeAddr, expectedCounterpartyPayee) } func (suite *KeeperTestSuite) TestGetAllPayeeAddresses() { @@ -289,9 +289,9 @@ func (suite *KeeperTestSuite) TestGetAllPayeeAddresses() { ) registeredPayee := types.RegisteredPayee{ - RelayerAddress: suite.chainA.SenderAccounts[i].SenderAccount.GetAddress().String(), - Payee: suite.chainB.SenderAccounts[i].SenderAccount.GetAddress().String(), - ChannelId: ibctesting.FirstChannelID, + Relayer: suite.chainA.SenderAccounts[i].SenderAccount.GetAddress().String(), + Payee: suite.chainB.SenderAccounts[i].SenderAccount.GetAddress().String(), + ChannelId: ibctesting.FirstChannelID, } expectedPayees = append(expectedPayees, registeredPayee) diff --git a/modules/apps/29-fee/types/genesis.go b/modules/apps/29-fee/types/genesis.go index 74660034041..5cd081c75cb 100644 --- a/modules/apps/29-fee/types/genesis.go +++ b/modules/apps/29-fee/types/genesis.go @@ -13,27 +13,27 @@ import ( func NewGenesisState( identifiedFees []IdentifiedPacketFees, feeEnabledChannels []FeeEnabledChannel, - registeredRelayers []RegisteredRelayerAddress, - forwardRelayers []ForwardRelayerAddress, registeredPayees []RegisteredPayee, + registeredCounterpartyPayees []RegisteredCounterpartyPayee, + forwardRelayers []ForwardRelayerAddress, ) *GenesisState { return &GenesisState{ - IdentifiedFees: identifiedFees, - FeeEnabledChannels: feeEnabledChannels, - RegisteredRelayers: registeredRelayers, - ForwardRelayers: forwardRelayers, - RegisteredPayees: registeredPayees, + IdentifiedFees: identifiedFees, + FeeEnabledChannels: feeEnabledChannels, + RegisteredPayees: registeredPayees, + RegisteredCounterpartyPayees: registeredCounterpartyPayees, + ForwardRelayers: forwardRelayers, } } -// DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. +// DefaultGenesisState returns a default instance of the 29-fee GenesisState. func DefaultGenesisState() *GenesisState { return &GenesisState{ - IdentifiedFees: []IdentifiedPacketFees{}, - ForwardRelayers: []ForwardRelayerAddress{}, - FeeEnabledChannels: []FeeEnabledChannel{}, - RegisteredRelayers: []RegisteredRelayerAddress{}, - RegisteredPayees: []RegisteredPayee{}, + IdentifiedFees: []IdentifiedPacketFees{}, + ForwardRelayers: []ForwardRelayerAddress{}, + FeeEnabledChannels: []FeeEnabledChannel{}, + RegisteredPayees: []RegisteredPayee{}, + RegisteredCounterpartyPayees: []RegisteredCounterpartyPayee{}, } } @@ -65,11 +65,11 @@ func (gs GenesisState) Validate() error { // Validate RegisteredPayees for _, registeredPayee := range gs.RegisteredPayees { - if registeredPayee.RelayerAddress == registeredPayee.Payee { + if registeredPayee.Relayer == registeredPayee.Payee { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "relayer address and payee address must not be equal") } - if _, err := sdk.AccAddressFromBech32(registeredPayee.RelayerAddress); err != nil { + if _, err := sdk.AccAddressFromBech32(registeredPayee.Relayer); err != nil { return sdkerrors.Wrap(err, "failed to convert relayer address into sdk.AccAddress") } @@ -82,15 +82,19 @@ func (gs GenesisState) Validate() error { } } - // Validate RegisteredRelayers - for _, rel := range gs.RegisteredRelayers { - if _, err := sdk.AccAddressFromBech32(rel.Address); err != nil { - return sdkerrors.Wrap(err, "failed to convert source relayer address into sdk.AccAddress") + // Validate RegisteredCounterpartyPayees + for _, registeredCounterpartyPayee := range gs.RegisteredCounterpartyPayees { + if _, err := sdk.AccAddressFromBech32(registeredCounterpartyPayee.Relayer); err != nil { + return sdkerrors.Wrap(err, "failed to convert relayer address into sdk.AccAddress") } - if strings.TrimSpace(rel.CounterpartyAddress) == "" { + if strings.TrimSpace(registeredCounterpartyPayee.CounterpartyPayee) == "" { return ErrCounterpartyPayeeEmpty } + + if err := host.ChannelIdentifierValidator(registeredCounterpartyPayee.ChannelId); err != nil { + return sdkerrors.Wrapf(err, "invalid channel identifier: %s", registeredCounterpartyPayee.ChannelId) + } } // Validate ForwardRelayers diff --git a/modules/apps/29-fee/types/genesis.pb.go b/modules/apps/29-fee/types/genesis.pb.go index bd2fd2083f0..57e676e069f 100644 --- a/modules/apps/29-fee/types/genesis.pb.go +++ b/modules/apps/29-fee/types/genesis.pb.go @@ -32,8 +32,8 @@ type GenesisState struct { FeeEnabledChannels []FeeEnabledChannel `protobuf:"bytes,2,rep,name=fee_enabled_channels,json=feeEnabledChannels,proto3" json:"fee_enabled_channels" yaml:"fee_enabled_channels"` // list of registered payees RegisteredPayees []RegisteredPayee `protobuf:"bytes,3,rep,name=registered_payees,json=registeredPayees,proto3" json:"registered_payees" yaml:"registered_payees"` - // list of registered relayer addresses - RegisteredRelayers []RegisteredRelayerAddress `protobuf:"bytes,4,rep,name=registered_relayers,json=registeredRelayers,proto3" json:"registered_relayers" yaml:"registered_relayers"` + // list of registered counterparty payees + RegisteredCounterpartyPayees []RegisteredCounterpartyPayee `protobuf:"bytes,4,rep,name=registered_counterparty_payees,json=registeredCounterpartyPayees,proto3" json:"registered_counterparty_payees" yaml:"registered_counterparty_payees"` // list of forward relayer addresses ForwardRelayers []ForwardRelayerAddress `protobuf:"bytes,5,rep,name=forward_relayers,json=forwardRelayers,proto3" json:"forward_relayers" yaml:"forward_relayers"` } @@ -92,9 +92,9 @@ func (m *GenesisState) GetRegisteredPayees() []RegisteredPayee { return nil } -func (m *GenesisState) GetRegisteredRelayers() []RegisteredRelayerAddress { +func (m *GenesisState) GetRegisteredCounterpartyPayees() []RegisteredCounterpartyPayee { if m != nil { - return m.RegisteredRelayers + return m.RegisteredCounterpartyPayees } return nil } @@ -163,12 +163,12 @@ func (m *FeeEnabledChannel) GetChannelId() string { // RegisteredPayee contains the relayer address and payee address for a specific channel type RegisteredPayee struct { + // unique channel identifier + ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` // the relayer address - RelayerAddress string `protobuf:"bytes,1,opt,name=relayer_address,json=relayerAddress,proto3" json:"relayer_address,omitempty" yaml:"relayer_address"` + Relayer string `protobuf:"bytes,2,opt,name=relayer,proto3" json:"relayer,omitempty"` // the payee address - Payee string `protobuf:"bytes,2,opt,name=payee,proto3" json:"payee,omitempty"` - // unique channel identifier - ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + Payee string `protobuf:"bytes,3,opt,name=payee,proto3" json:"payee,omitempty"` } func (m *RegisteredPayee) Reset() { *m = RegisteredPayee{} } @@ -204,49 +204,50 @@ func (m *RegisteredPayee) XXX_DiscardUnknown() { var xxx_messageInfo_RegisteredPayee proto.InternalMessageInfo -func (m *RegisteredPayee) GetRelayerAddress() string { +func (m *RegisteredPayee) GetChannelId() string { if m != nil { - return m.RelayerAddress + return m.ChannelId } return "" } -func (m *RegisteredPayee) GetPayee() string { +func (m *RegisteredPayee) GetRelayer() string { if m != nil { - return m.Payee + return m.Relayer } return "" } -func (m *RegisteredPayee) GetChannelId() string { +func (m *RegisteredPayee) GetPayee() string { if m != nil { - return m.ChannelId + return m.Payee } return "" } -// RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) -type RegisteredRelayerAddress struct { - // the relayer address - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - // the counterparty relayer address - CounterpartyAddress string `protobuf:"bytes,2,opt,name=counterparty_address,json=counterpartyAddress,proto3" json:"counterparty_address,omitempty" yaml:"counterparty_address"` +// RegisteredCounterpartyPayee contains the relayer address and counterparty payee address for a specific channel (used +// for recv fee distribution) +type RegisteredCounterpartyPayee struct { // unique channel identifier - ChannelId string `protobuf:"bytes,3,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` + // the relayer address + Relayer string `protobuf:"bytes,2,opt,name=relayer,proto3" json:"relayer,omitempty"` + // the counterparty payee address + CounterpartyPayee string `protobuf:"bytes,3,opt,name=counterparty_payee,json=counterpartyPayee,proto3" json:"counterparty_payee,omitempty" yaml:"counterparty_payee"` } -func (m *RegisteredRelayerAddress) Reset() { *m = RegisteredRelayerAddress{} } -func (m *RegisteredRelayerAddress) String() string { return proto.CompactTextString(m) } -func (*RegisteredRelayerAddress) ProtoMessage() {} -func (*RegisteredRelayerAddress) Descriptor() ([]byte, []int) { +func (m *RegisteredCounterpartyPayee) Reset() { *m = RegisteredCounterpartyPayee{} } +func (m *RegisteredCounterpartyPayee) String() string { return proto.CompactTextString(m) } +func (*RegisteredCounterpartyPayee) ProtoMessage() {} +func (*RegisteredCounterpartyPayee) Descriptor() ([]byte, []int) { return fileDescriptor_7191992e856dff95, []int{3} } -func (m *RegisteredRelayerAddress) XXX_Unmarshal(b []byte) error { +func (m *RegisteredCounterpartyPayee) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *RegisteredRelayerAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *RegisteredCounterpartyPayee) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_RegisteredRelayerAddress.Marshal(b, m, deterministic) + return xxx_messageInfo_RegisteredCounterpartyPayee.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -256,35 +257,35 @@ func (m *RegisteredRelayerAddress) XXX_Marshal(b []byte, deterministic bool) ([] return b[:n], nil } } -func (m *RegisteredRelayerAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_RegisteredRelayerAddress.Merge(m, src) +func (m *RegisteredCounterpartyPayee) XXX_Merge(src proto.Message) { + xxx_messageInfo_RegisteredCounterpartyPayee.Merge(m, src) } -func (m *RegisteredRelayerAddress) XXX_Size() int { +func (m *RegisteredCounterpartyPayee) XXX_Size() int { return m.Size() } -func (m *RegisteredRelayerAddress) XXX_DiscardUnknown() { - xxx_messageInfo_RegisteredRelayerAddress.DiscardUnknown(m) +func (m *RegisteredCounterpartyPayee) XXX_DiscardUnknown() { + xxx_messageInfo_RegisteredCounterpartyPayee.DiscardUnknown(m) } -var xxx_messageInfo_RegisteredRelayerAddress proto.InternalMessageInfo +var xxx_messageInfo_RegisteredCounterpartyPayee proto.InternalMessageInfo -func (m *RegisteredRelayerAddress) GetAddress() string { +func (m *RegisteredCounterpartyPayee) GetChannelId() string { if m != nil { - return m.Address + return m.ChannelId } return "" } -func (m *RegisteredRelayerAddress) GetCounterpartyAddress() string { +func (m *RegisteredCounterpartyPayee) GetRelayer() string { if m != nil { - return m.CounterpartyAddress + return m.Relayer } return "" } -func (m *RegisteredRelayerAddress) GetChannelId() string { +func (m *RegisteredCounterpartyPayee) GetCounterpartyPayee() string { if m != nil { - return m.ChannelId + return m.CounterpartyPayee } return "" } @@ -348,7 +349,7 @@ func init() { proto.RegisterType((*GenesisState)(nil), "ibc.applications.fee.v1.GenesisState") proto.RegisterType((*FeeEnabledChannel)(nil), "ibc.applications.fee.v1.FeeEnabledChannel") proto.RegisterType((*RegisteredPayee)(nil), "ibc.applications.fee.v1.RegisteredPayee") - proto.RegisterType((*RegisteredRelayerAddress)(nil), "ibc.applications.fee.v1.RegisteredRelayerAddress") + proto.RegisterType((*RegisteredCounterpartyPayee)(nil), "ibc.applications.fee.v1.RegisteredCounterpartyPayee") proto.RegisterType((*ForwardRelayerAddress)(nil), "ibc.applications.fee.v1.ForwardRelayerAddress") } @@ -357,48 +358,48 @@ func init() { } var fileDescriptor_7191992e856dff95 = []byte{ - // 652 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x41, 0x6f, 0xd3, 0x30, - 0x18, 0x6d, 0x36, 0xb6, 0x31, 0x0f, 0xad, 0x9b, 0xd7, 0xb1, 0xa8, 0x88, 0x74, 0x18, 0x21, 0x4d, - 0xa0, 0x25, 0xea, 0x06, 0x07, 0xb8, 0xd1, 0x89, 0xa1, 0x9e, 0x98, 0x0c, 0x27, 0x2e, 0x55, 0x9a, - 0x7c, 0xe9, 0x2c, 0xda, 0x38, 0xb2, 0xbd, 0x4e, 0xe5, 0xc6, 0x05, 0x38, 0xf2, 0x1b, 0xf8, 0x21, - 0x9c, 0x77, 0xdc, 0x91, 0x53, 0x85, 0xb6, 0x7f, 0xb0, 0x5f, 0x80, 0x12, 0x3b, 0x6b, 0x9b, 0xb5, - 0x68, 0xe2, 0x66, 0xc7, 0xef, 0x7d, 0xef, 0xd9, 0xef, 0xcb, 0x87, 0x9e, 0xb0, 0x76, 0xe0, 0xf9, - 0x49, 0xd2, 0x65, 0x81, 0xaf, 0x18, 0x8f, 0xa5, 0x17, 0x01, 0x78, 0xfd, 0xba, 0xd7, 0x81, 0x18, - 0x24, 0x93, 0x6e, 0x22, 0xb8, 0xe2, 0x78, 0x8b, 0xb5, 0x03, 0x77, 0x1c, 0xe6, 0x46, 0x00, 0x6e, - 0xbf, 0x5e, 0xad, 0x74, 0x78, 0x87, 0x67, 0x18, 0x2f, 0x5d, 0x69, 0x78, 0xf5, 0xd1, 0xac, 0xaa, - 0x29, 0x6b, 0x0c, 0x12, 0x70, 0x01, 0x5e, 0x70, 0xec, 0xc7, 0x31, 0x74, 0xd3, 0x63, 0xb3, 0xd4, - 0x10, 0xf2, 0x7d, 0x01, 0xdd, 0x7b, 0xab, 0x6d, 0xbc, 0x57, 0xbe, 0x02, 0xdc, 0x47, 0x65, 0x16, - 0x42, 0xac, 0x58, 0xc4, 0x20, 0x6c, 0x45, 0x00, 0xd2, 0xb6, 0xb6, 0xe7, 0x77, 0x56, 0xf6, 0x76, - 0xdd, 0x19, 0xfe, 0xdc, 0xe6, 0x35, 0xfe, 0xc8, 0x0f, 0x3e, 0x81, 0x3a, 0x04, 0x90, 0x0d, 0xe7, - 0x6c, 0x58, 0x2b, 0x5d, 0x0d, 0x6b, 0xf7, 0x07, 0x7e, 0xaf, 0xfb, 0x8a, 0x14, 0x6a, 0x12, 0xba, - 0x3a, 0xfa, 0x92, 0xe2, 0xf1, 0x17, 0x0b, 0x55, 0x22, 0x80, 0x16, 0xc4, 0x7e, 0xbb, 0x0b, 0x61, - 0xcb, 0xd8, 0x94, 0xf6, 0x5c, 0xa6, 0xfe, 0x74, 0xa6, 0xfa, 0x21, 0xc0, 0x1b, 0xcd, 0x39, 0xd0, - 0x94, 0xc6, 0x63, 0x23, 0xfd, 0x40, 0x4b, 0x4f, 0xab, 0x4a, 0x28, 0x8e, 0x8a, 0x3c, 0x89, 0x4f, - 0xd1, 0xba, 0x80, 0x0e, 0x93, 0x0a, 0x04, 0x84, 0xad, 0xc4, 0x1f, 0xa4, 0xb7, 0x9f, 0xcf, 0xf4, - 0x77, 0x66, 0xea, 0xd3, 0x6b, 0xc6, 0x51, 0x4a, 0x68, 0x6c, 0x1b, 0x75, 0x5b, 0xab, 0xdf, 0x28, - 0x48, 0xe8, 0x9a, 0x98, 0xa4, 0x48, 0xfc, 0xd5, 0x42, 0x1b, 0x63, 0x40, 0x01, 0x5d, 0x7f, 0x00, - 0x42, 0xda, 0x77, 0x32, 0xed, 0xfa, 0x2d, 0xb4, 0xa9, 0xa6, 0xbc, 0x0e, 0x43, 0x01, 0x52, 0x36, - 0x88, 0x31, 0x51, 0xbd, 0x61, 0x22, 0xaf, 0x4d, 0x28, 0x16, 0x45, 0xb6, 0xc4, 0x9f, 0xd1, 0x5a, - 0xc4, 0xc5, 0xa9, 0x2f, 0xc6, 0x4c, 0x2c, 0x64, 0x26, 0xdc, 0xd9, 0x01, 0x68, 0x42, 0xc1, 0x41, - 0xcd, 0x38, 0xd8, 0x32, 0x21, 0x14, 0xaa, 0x12, 0x5a, 0x8e, 0x26, 0x78, 0x92, 0xf4, 0xd1, 0xfa, - 0x8d, 0x2c, 0xf1, 0x33, 0xb4, 0x94, 0x70, 0xa1, 0x5a, 0x2c, 0xb4, 0xad, 0x6d, 0x6b, 0x67, 0xb9, - 0x81, 0xaf, 0x86, 0xb5, 0x55, 0x5d, 0xd3, 0x1c, 0x10, 0xba, 0x98, 0xae, 0x9a, 0x21, 0x7e, 0x8e, - 0x90, 0x09, 0x38, 0xc5, 0xcf, 0x65, 0xf8, 0xcd, 0xab, 0x61, 0x6d, 0x5d, 0xe3, 0x47, 0x67, 0x84, - 0x2e, 0x9b, 0x4d, 0x33, 0x24, 0x3f, 0x2d, 0x54, 0x2e, 0x84, 0x88, 0x0f, 0x50, 0xd9, 0x38, 0x6d, - 0xf9, 0xfa, 0x42, 0x46, 0xbe, 0x3a, 0x6a, 0xe9, 0x02, 0x80, 0xd0, 0x55, 0x31, 0xf1, 0x04, 0xb8, - 0x82, 0x16, 0xb2, 0xc8, 0xb5, 0x13, 0xaa, 0x37, 0x05, 0x93, 0xf3, 0xb7, 0x34, 0xf9, 0xcb, 0x42, - 0xf6, 0xac, 0xb4, 0xb1, 0x8d, 0x96, 0x26, 0x5c, 0xd2, 0x7c, 0x8b, 0x29, 0xaa, 0x04, 0xfc, 0x24, - 0x56, 0x20, 0x12, 0x5f, 0xa8, 0xc1, 0xf5, 0x65, 0xf4, 0xdb, 0xd4, 0x46, 0x3f, 0xc9, 0x34, 0x14, - 0xa1, 0x1b, 0xe3, 0x9f, 0x73, 0xb5, 0xff, 0xbb, 0xc0, 0x37, 0x0b, 0x6d, 0x4e, 0xed, 0x94, 0x7f, - 0xb8, 0xff, 0x80, 0x96, 0x93, 0x6c, 0xa2, 0xe4, 0x71, 0xae, 0xec, 0x3d, 0xcc, 0xda, 0x30, 0x9d, - 0x69, 0x6e, 0x3e, 0xc8, 0xfa, 0x75, 0x57, 0xcf, 0x9d, 0x66, 0xd8, 0xb0, 0x4d, 0xd7, 0xad, 0x99, - 0x0e, 0xc9, 0xd9, 0x84, 0xde, 0x4d, 0x72, 0xcc, 0xbb, 0xb3, 0x0b, 0xc7, 0x3a, 0xbf, 0x70, 0xac, - 0x3f, 0x17, 0x8e, 0xf5, 0xe3, 0xd2, 0x29, 0x9d, 0x5f, 0x3a, 0xa5, 0xdf, 0x97, 0x4e, 0xe9, 0xe3, - 0x8b, 0x0e, 0x53, 0xc7, 0x27, 0x6d, 0x37, 0xe0, 0x3d, 0x2f, 0xe0, 0xb2, 0xc7, 0xa5, 0xc7, 0xda, - 0xc1, 0x6e, 0x87, 0x7b, 0xfd, 0x7d, 0xaf, 0xc7, 0xc3, 0x93, 0x2e, 0xc8, 0x74, 0xe4, 0x4a, 0x6f, - 0xef, 0xe5, 0x6e, 0x3a, 0x6d, 0xd5, 0x20, 0x01, 0xd9, 0x5e, 0xcc, 0x46, 0xe9, 0xfe, 0xdf, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xb6, 0xf7, 0x84, 0x44, 0xe8, 0x05, 0x00, 0x00, + // 648 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x4e, 0xd4, 0x40, + 0x1c, 0xdf, 0x82, 0x80, 0x0c, 0x06, 0xd8, 0x09, 0x48, 0x05, 0xe9, 0xe2, 0x18, 0x12, 0xa2, 0xd9, + 0x36, 0x7c, 0x78, 0xd0, 0x9b, 0x25, 0x62, 0x36, 0x31, 0x91, 0x8c, 0x9e, 0xbc, 0x6c, 0xba, 0xed, + 0xbf, 0x4b, 0xe3, 0x6e, 0xa7, 0x99, 0x19, 0x96, 0xac, 0x37, 0x4f, 0x5e, 0x7d, 0x0d, 0xe3, 0x23, + 0xf8, 0x02, 0x1c, 0x39, 0x7a, 0xda, 0x18, 0x78, 0x83, 0x7d, 0x02, 0x33, 0x9d, 0x29, 0x2c, 0xfb, + 0x61, 0x38, 0x78, 0x9b, 0xe9, 0xfc, 0xbe, 0xa6, 0xbf, 0xc9, 0x1f, 0x6d, 0x27, 0x8d, 0xd0, 0x0b, + 0xb2, 0xac, 0x95, 0x84, 0x81, 0x4c, 0x58, 0x2a, 0xbc, 0x18, 0xc0, 0xeb, 0xec, 0x7a, 0x4d, 0x48, + 0x41, 0x24, 0xc2, 0xcd, 0x38, 0x93, 0x0c, 0xaf, 0x25, 0x8d, 0xd0, 0x1d, 0x84, 0xb9, 0x31, 0x80, + 0xdb, 0xd9, 0x5d, 0x5f, 0x69, 0xb2, 0x26, 0xcb, 0x31, 0x9e, 0x5a, 0x69, 0xf8, 0xfa, 0x93, 0x49, + 0xaa, 0x8a, 0x35, 0x00, 0x09, 0x19, 0x07, 0x2f, 0x3c, 0x09, 0xd2, 0x14, 0x5a, 0xea, 0xd8, 0x2c, + 0x35, 0x84, 0xfc, 0x9c, 0x41, 0x0f, 0xde, 0xea, 0x18, 0x1f, 0x64, 0x20, 0x01, 0x77, 0xd0, 0x52, + 0x12, 0x41, 0x2a, 0x93, 0x38, 0x81, 0xa8, 0x1e, 0x03, 0x08, 0xdb, 0xda, 0x9a, 0xde, 0x59, 0xd8, + 0xab, 0xba, 0x13, 0xf2, 0xb9, 0xb5, 0x6b, 0xfc, 0x71, 0x10, 0x7e, 0x06, 0x79, 0x04, 0x20, 0x7c, + 0xe7, 0xbc, 0x57, 0x29, 0xf5, 0x7b, 0x95, 0x87, 0xdd, 0xa0, 0xdd, 0x7a, 0x45, 0x86, 0x34, 0x09, + 0x5d, 0xbc, 0xf9, 0xa2, 0xf0, 0xf8, 0xab, 0x85, 0x56, 0x62, 0x80, 0x3a, 0xa4, 0x41, 0xa3, 0x05, + 0x51, 0xdd, 0xc4, 0x14, 0xf6, 0x54, 0xee, 0xfe, 0x6c, 0xa2, 0xfb, 0x11, 0xc0, 0x1b, 0xcd, 0x39, + 0xd4, 0x14, 0xff, 0xa9, 0xb1, 0xde, 0xd0, 0xd6, 0xe3, 0x54, 0x09, 0xc5, 0xf1, 0x30, 0x4f, 0xe0, + 0x33, 0x54, 0xe6, 0xd0, 0x4c, 0x84, 0x04, 0x0e, 0x51, 0x3d, 0x0b, 0xba, 0xea, 0xf6, 0xd3, 0xb9, + 0xff, 0xce, 0x44, 0x7f, 0x7a, 0xcd, 0x38, 0x56, 0x04, 0x7f, 0xcb, 0xb8, 0xdb, 0xda, 0x7d, 0x44, + 0x90, 0xd0, 0x65, 0x7e, 0x9b, 0x22, 0xf0, 0x0f, 0x0b, 0x39, 0x03, 0xc0, 0x90, 0x9d, 0xa6, 0x12, + 0x78, 0x16, 0x70, 0xd9, 0x2d, 0x62, 0xdc, 0xcb, 0x63, 0x1c, 0xdc, 0x21, 0xc6, 0xe1, 0x00, 0x5b, + 0x47, 0xaa, 0x9a, 0x48, 0xdb, 0x23, 0x91, 0xc6, 0x38, 0x11, 0xfa, 0x98, 0x4f, 0xd6, 0x12, 0xf8, + 0x0b, 0x5a, 0x8e, 0x19, 0x3f, 0x0b, 0x78, 0x54, 0xe7, 0xd0, 0x0a, 0xba, 0xc0, 0x85, 0x3d, 0x93, + 0x87, 0x73, 0x27, 0x77, 0xa4, 0x09, 0x54, 0xe3, 0x5f, 0x47, 0x11, 0x07, 0x21, 0xfc, 0x8a, 0x89, + 0xb5, 0x66, 0x7a, 0x1a, 0x52, 0x25, 0x74, 0x29, 0xbe, 0xc5, 0x13, 0xa4, 0x83, 0xca, 0x23, 0x75, + 0xe3, 0xe7, 0x68, 0x2e, 0x63, 0x5c, 0xd6, 0x93, 0xc8, 0xb6, 0xb6, 0xac, 0x9d, 0x79, 0x1f, 0xf7, + 0x7b, 0x95, 0x45, 0xad, 0x69, 0x0e, 0x08, 0x9d, 0x55, 0xab, 0x5a, 0x84, 0x0f, 0x10, 0x32, 0x6f, + 0x40, 0xe1, 0xa7, 0x72, 0xfc, 0x6a, 0xbf, 0x57, 0x29, 0x6b, 0xfc, 0xcd, 0x19, 0xa1, 0xf3, 0x66, + 0x53, 0x8b, 0xc8, 0x19, 0x5a, 0x1a, 0xaa, 0x79, 0x48, 0xc8, 0xba, 0x9b, 0x10, 0xb6, 0xd1, 0x9c, + 0xb9, 0x9e, 0xf6, 0xa6, 0xc5, 0x16, 0xaf, 0xa0, 0x99, 0xfc, 0xff, 0xdb, 0xd3, 0xf9, 0x77, 0xbd, + 0x21, 0xbf, 0x2c, 0xb4, 0xf1, 0x8f, 0x66, 0xff, 0x7b, 0x8a, 0x77, 0x08, 0x8f, 0x3e, 0x09, 0x1d, + 0xc9, 0xdf, 0xec, 0xf7, 0x2a, 0x8f, 0x8c, 0xee, 0x08, 0x86, 0xd0, 0x72, 0x38, 0x9c, 0x8e, 0x7c, + 0xb3, 0xd0, 0xea, 0xd8, 0xea, 0x55, 0x82, 0x40, 0x2f, 0x75, 0x68, 0x5a, 0x6c, 0xf1, 0x47, 0x34, + 0x9f, 0xe5, 0x53, 0xa4, 0xe8, 0x67, 0x61, 0x6f, 0x33, 0x7f, 0x57, 0x6a, 0x8e, 0xb9, 0xc5, 0xf0, + 0xea, 0xec, 0xba, 0x7a, 0xd6, 0xd4, 0x22, 0xdf, 0x36, 0xcf, 0x68, 0xd9, 0x54, 0x5e, 0xb0, 0x09, + 0xbd, 0x9f, 0x15, 0x98, 0xf7, 0xe7, 0x97, 0x8e, 0x75, 0x71, 0xe9, 0x58, 0x7f, 0x2e, 0x1d, 0xeb, + 0xfb, 0x95, 0x53, 0xba, 0xb8, 0x72, 0x4a, 0xbf, 0xaf, 0x9c, 0xd2, 0xa7, 0x17, 0xcd, 0x44, 0x9e, + 0x9c, 0x36, 0xdc, 0x90, 0xb5, 0xbd, 0x90, 0x89, 0x36, 0x13, 0x5e, 0xd2, 0x08, 0xab, 0x4d, 0xe6, + 0x75, 0xf6, 0xbd, 0x36, 0x8b, 0x4e, 0x5b, 0x20, 0xd4, 0x98, 0x15, 0xde, 0xde, 0xcb, 0xaa, 0x9a, + 0xb0, 0xb2, 0x9b, 0x81, 0x68, 0xcc, 0xe6, 0xe3, 0x73, 0xff, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x87, 0x75, 0xda, 0x18, 0xdc, 0x05, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -435,10 +436,10 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x2a } } - if len(m.RegisteredRelayers) > 0 { - for iNdEx := len(m.RegisteredRelayers) - 1; iNdEx >= 0; iNdEx-- { + if len(m.RegisteredCounterpartyPayees) > 0 { + for iNdEx := len(m.RegisteredCounterpartyPayees) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.RegisteredRelayers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.RegisteredCounterpartyPayees[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -551,31 +552,31 @@ func (m *RegisteredPayee) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.ChannelId) > 0 { - i -= len(m.ChannelId) - copy(dAtA[i:], m.ChannelId) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId))) - i-- - dAtA[i] = 0x1a - } if len(m.Payee) > 0 { i -= len(m.Payee) copy(dAtA[i:], m.Payee) i = encodeVarintGenesis(dAtA, i, uint64(len(m.Payee))) i-- + dAtA[i] = 0x1a + } + if len(m.Relayer) > 0 { + i -= len(m.Relayer) + copy(dAtA[i:], m.Relayer) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Relayer))) + i-- dAtA[i] = 0x12 } - if len(m.RelayerAddress) > 0 { - i -= len(m.RelayerAddress) - copy(dAtA[i:], m.RelayerAddress) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.RelayerAddress))) + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *RegisteredRelayerAddress) Marshal() (dAtA []byte, err error) { +func (m *RegisteredCounterpartyPayee) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -585,34 +586,34 @@ func (m *RegisteredRelayerAddress) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RegisteredRelayerAddress) MarshalTo(dAtA []byte) (int, error) { +func (m *RegisteredCounterpartyPayee) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *RegisteredRelayerAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *RegisteredCounterpartyPayee) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.ChannelId) > 0 { - i -= len(m.ChannelId) - copy(dAtA[i:], m.ChannelId) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId))) + if len(m.CounterpartyPayee) > 0 { + i -= len(m.CounterpartyPayee) + copy(dAtA[i:], m.CounterpartyPayee) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.CounterpartyPayee))) i-- dAtA[i] = 0x1a } - if len(m.CounterpartyAddress) > 0 { - i -= len(m.CounterpartyAddress) - copy(dAtA[i:], m.CounterpartyAddress) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.CounterpartyAddress))) + if len(m.Relayer) > 0 { + i -= len(m.Relayer) + copy(dAtA[i:], m.Relayer) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Relayer))) i-- dAtA[i] = 0x12 } - if len(m.Address) > 0 { - i -= len(m.Address) - copy(dAtA[i:], m.Address) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.Address))) + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChannelId))) i-- dAtA[i] = 0xa } @@ -694,8 +695,8 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } - if len(m.RegisteredRelayers) > 0 { - for _, e := range m.RegisteredRelayers { + if len(m.RegisteredCounterpartyPayees) > 0 { + for _, e := range m.RegisteredCounterpartyPayees { l = e.Size() n += 1 + l + sovGenesis(uint64(l)) } @@ -732,36 +733,36 @@ func (m *RegisteredPayee) Size() (n int) { } var l int _ = l - l = len(m.RelayerAddress) + l = len(m.ChannelId) if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - l = len(m.Payee) + l = len(m.Relayer) if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - l = len(m.ChannelId) + l = len(m.Payee) if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } return n } -func (m *RegisteredRelayerAddress) Size() (n int) { +func (m *RegisteredCounterpartyPayee) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.Address) + l = len(m.ChannelId) if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - l = len(m.CounterpartyAddress) + l = len(m.Relayer) if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } - l = len(m.ChannelId) + l = len(m.CounterpartyPayee) if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } @@ -922,7 +923,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RegisteredRelayers", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RegisteredCounterpartyPayees", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -949,8 +950,8 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RegisteredRelayers = append(m.RegisteredRelayers, RegisteredRelayerAddress{}) - if err := m.RegisteredRelayers[len(m.RegisteredRelayers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.RegisteredCounterpartyPayees = append(m.RegisteredCounterpartyPayees, RegisteredCounterpartyPayee{}) + if err := m.RegisteredCounterpartyPayees[len(m.RegisteredCounterpartyPayees)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -1154,7 +1155,7 @@ func (m *RegisteredPayee) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RelayerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1182,11 +1183,11 @@ func (m *RegisteredPayee) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RelayerAddress = string(dAtA[iNdEx:postIndex]) + m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Payee", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Relayer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1214,11 +1215,11 @@ func (m *RegisteredPayee) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Payee = string(dAtA[iNdEx:postIndex]) + m.Relayer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Payee", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1246,7 +1247,7 @@ func (m *RegisteredPayee) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChannelId = string(dAtA[iNdEx:postIndex]) + m.Payee = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1269,7 +1270,7 @@ func (m *RegisteredPayee) Unmarshal(dAtA []byte) error { } return nil } -func (m *RegisteredRelayerAddress) Unmarshal(dAtA []byte) error { +func (m *RegisteredCounterpartyPayee) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1292,15 +1293,15 @@ func (m *RegisteredRelayerAddress) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: RegisteredRelayerAddress: wiretype end group for non-group") + return fmt.Errorf("proto: RegisteredCounterpartyPayee: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: RegisteredRelayerAddress: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: RegisteredCounterpartyPayee: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1328,11 +1329,11 @@ func (m *RegisteredRelayerAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Address = string(dAtA[iNdEx:postIndex]) + m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Relayer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1360,11 +1361,11 @@ func (m *RegisteredRelayerAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CounterpartyAddress = string(dAtA[iNdEx:postIndex]) + m.Relayer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyPayee", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1392,7 +1393,7 @@ func (m *RegisteredRelayerAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChannelId = string(dAtA[iNdEx:postIndex]) + m.CounterpartyPayee = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/modules/apps/29-fee/types/genesis_test.go b/modules/apps/29-fee/types/genesis_test.go index fa6ca6d1dd2..d0f6b7ab115 100644 --- a/modules/apps/29-fee/types/genesis_test.go +++ b/modules/apps/29-fee/types/genesis_test.go @@ -82,7 +82,7 @@ func TestValidateGenesis(t *testing.T) { { "invalid registered payee: invalid relayer address", func() { - genState.RegisteredPayees[0].RelayerAddress = "" + genState.RegisteredPayees[0].Relayer = "" }, false, }, @@ -101,16 +101,16 @@ func TestValidateGenesis(t *testing.T) { false, }, { - "invalid registered relayers: invalid sender", + "invalid registered counterparty payees: invalid relayer address", func() { - genState.RegisteredRelayers[0].Address = "" + genState.RegisteredCounterpartyPayees[0].Relayer = "" }, false, }, { - "invalid registered relayers: invalid counterparty", + "invalid registered counterparty payees: invalid counterparty payee", func() { - genState.RegisteredRelayers[0].CounterpartyAddress = "" + genState.RegisteredCounterpartyPayees[0].CounterpartyPayee = "" }, false, }, @@ -144,10 +144,11 @@ func TestValidateGenesis(t *testing.T) { ChannelId: ibctesting.FirstChannelID, }, }, - RegisteredRelayers: []types.RegisteredRelayerAddress{ + RegisteredCounterpartyPayees: []types.RegisteredCounterpartyPayee{ { - Address: defaultAccAddress, - CounterpartyAddress: defaultAccAddress, + Relayer: defaultAccAddress, + CounterpartyPayee: defaultAccAddress, + ChannelId: ibctesting.FirstChannelID, }, }, ForwardRelayers: []types.ForwardRelayerAddress{ @@ -158,9 +159,9 @@ func TestValidateGenesis(t *testing.T) { }, RegisteredPayees: []types.RegisteredPayee{ { - RelayerAddress: sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String(), - Payee: sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String(), - ChannelId: ibctesting.FirstChannelID, + Relayer: sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String(), + Payee: sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String(), + ChannelId: ibctesting.FirstChannelID, }, }, } diff --git a/proto/ibc/applications/fee/v1/genesis.proto b/proto/ibc/applications/fee/v1/genesis.proto index 57af52f32d9..601f32ca5d0 100644 --- a/proto/ibc/applications/fee/v1/genesis.proto +++ b/proto/ibc/applications/fee/v1/genesis.proto @@ -19,9 +19,9 @@ message GenesisState { // list of registered payees repeated RegisteredPayee registered_payees = 3 [(gogoproto.moretags) = "yaml:\"registered_payees\"", (gogoproto.nullable) = false]; - // list of registered relayer addresses - repeated RegisteredRelayerAddress registered_relayers = 4 - [(gogoproto.moretags) = "yaml:\"registered_relayers\"", (gogoproto.nullable) = false]; + // list of registered counterparty payees + repeated RegisteredCounterpartyPayee registered_counterparty_payees = 4 + [(gogoproto.moretags) = "yaml:\"registered_counterparty_payees\"", (gogoproto.nullable) = false]; // list of forward relayer addresses repeated ForwardRelayerAddress forward_relayers = 5 [(gogoproto.moretags) = "yaml:\"forward_relayers\"", (gogoproto.nullable) = false]; @@ -37,22 +37,23 @@ message FeeEnabledChannel { // RegisteredPayee contains the relayer address and payee address for a specific channel message RegisteredPayee { + // unique channel identifier + string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; // the relayer address - string relayer_address = 1 [(gogoproto.moretags) = "yaml:\"relayer_address\""]; + string relayer = 2; // the payee address - string payee = 2; - // unique channel identifier - string channel_id = 3 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string payee = 3; } -// RegisteredRelayerAddress contains the address and counterparty address for a specific relayer (for distributing fees) -message RegisteredRelayerAddress { - // the relayer address - string address = 1; - // the counterparty relayer address - string counterparty_address = 2 [(gogoproto.moretags) = "yaml:\"counterparty_address\""]; +// RegisteredCounterpartyPayee contains the relayer address and counterparty payee address for a specific channel (used +// for recv fee distribution) +message RegisteredCounterpartyPayee { // unique channel identifier - string channel_id = 3 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + // the relayer address + string relayer = 2; + // the counterparty payee address + string counterparty_payee = 3 [(gogoproto.moretags) = "yaml:\"counterparty_payee\""]; } // ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements From a71fc1029ad1fc6d377d642781d02ad3cbfa0910 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 Jun 2022 12:09:04 +0200 Subject: [PATCH 164/275] refactor: rename CounterpartyAddress query to CounterpartyPayee (#1522) * renaming counterparty address rpc to counterparty payee * rename genesis types for registered counterparty payees * renaming counterparty address query to counterparty payee * updating counterparty payee cli * reorder cli cmd list * Apply suggestions from code review Co-authored-by: Charly * removing address suffix from msg fields, updating protodoc and godoc * updating cli args naming convention to align * propagating renaming of fields to genesis state * rename GetAllx funcs and updating godocs * aligning naming of GetAll functions Co-authored-by: Charly --- docs/client/swagger-ui/swagger.yaml | 34 +- docs/ibc/proto-docs.md | 26 +- modules/apps/29-fee/client/cli/cli.go | 2 +- modules/apps/29-fee/client/cli/query.go | 26 +- modules/apps/29-fee/keeper/genesis.go | 2 +- modules/apps/29-fee/keeper/grpc_query.go | 16 +- modules/apps/29-fee/keeper/grpc_query_test.go | 26 +- modules/apps/29-fee/keeper/keeper.go | 4 +- modules/apps/29-fee/keeper/keeper_test.go | 42 +- modules/apps/29-fee/types/query.pb.go | 359 +++++++++--------- modules/apps/29-fee/types/query.pb.gw.go | 62 +-- proto/ibc/applications/fee/v1/query.proto | 25 +- 12 files changed, 312 insertions(+), 312 deletions(-) diff --git a/docs/client/swagger-ui/swagger.yaml b/docs/client/swagger-ui/swagger.yaml index 409bddcafc2..ca13125f6fa 100644 --- a/docs/client/swagger-ui/swagger.yaml +++ b/docs/client/swagger-ui/swagger.yaml @@ -1046,24 +1046,26 @@ paths: format: uint64 tags: - Query - '/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address': + '/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/counterparty_payee': get: summary: >- - CounterpartyAddress returns the registered counterparty address for - forward relaying - operationId: CounterpartyAddress + CounterpartyPayee returns the registered counterparty payee for forward + relaying + operationId: CounterpartyPayee responses: '200': description: A successful response. schema: type: object properties: - counterparty_address: + counterparty_payee: type: string - title: the counterparty address used to compensate forward relaying + title: >- + the counterparty payee address used to compensate forward + relaying title: >- - QueryCounterpartyAddressResponse defines the response type for the - CounterpartyAddress rpc + QueryCounterpartyPayeeResponse defines the response type for the + CounterpartyPayee rpc default: description: An unexpected error response schema: @@ -1259,14 +1261,14 @@ paths: in: path required: true type: string - - name: relayer_address + - name: relayer description: the relayer address to which the counterparty is registered in: path required: true type: string tags: - Query - '/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/payee': + '/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/payee': get: summary: >- Payee returns the registered payee address for a specific channel given @@ -1477,7 +1479,7 @@ paths: in: path required: true type: string - - name: relayer_address + - name: relayer description: the relayer address to which the distribution address is registered in: path required: true @@ -13524,15 +13526,15 @@ definitions: title: >- PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers - ibc.applications.fee.v1.QueryCounterpartyAddressResponse: + ibc.applications.fee.v1.QueryCounterpartyPayeeResponse: type: object properties: - counterparty_address: + counterparty_payee: type: string - title: the counterparty address used to compensate forward relaying + title: the counterparty payee address used to compensate forward relaying title: >- - QueryCounterpartyAddressResponse defines the response type for the - CounterpartyAddress rpc + QueryCounterpartyPayeeResponse defines the response type for the + CounterpartyPayee rpc ibc.applications.fee.v1.QueryFeeEnabledChannelResponse: type: object properties: diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 1641af76b8e..30c6d350bd1 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -45,8 +45,8 @@ - [Metadata](#ibc.applications.fee.v1.Metadata) - [ibc/applications/fee/v1/query.proto](#ibc/applications/fee/v1/query.proto) - - [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) - - [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) + - [QueryCounterpartyPayeeRequest](#ibc.applications.fee.v1.QueryCounterpartyPayeeRequest) + - [QueryCounterpartyPayeeResponse](#ibc.applications.fee.v1.QueryCounterpartyPayeeResponse) - [QueryFeeEnabledChannelRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelRequest) - [QueryFeeEnabledChannelResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelResponse) - [QueryFeeEnabledChannelsRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest) @@ -940,31 +940,31 @@ See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel- - + -### QueryCounterpartyAddressRequest -QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc +### QueryCounterpartyPayeeRequest +QueryCounterpartyPayeeRequest defines the request type for the CounterpartyPayee rpc | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `channel_id` | [string](#string) | | unique channel identifier | -| `relayer_address` | [string](#string) | | the relayer address to which the counterparty is registered | +| `relayer` | [string](#string) | | the relayer address to which the counterparty is registered | - + -### QueryCounterpartyAddressResponse -QueryCounterpartyAddressResponse defines the response type for the CounterpartyAddress rpc +### QueryCounterpartyPayeeResponse +QueryCounterpartyPayeeResponse defines the response type for the CounterpartyPayee rpc | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `counterparty_address` | [string](#string) | | the counterparty address used to compensate forward relaying | +| `counterparty_payee` | [string](#string) | | the counterparty payee address used to compensate forward relaying | @@ -1138,7 +1138,7 @@ QueryPayeeRequest defines the request type for the Payee rpc | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `channel_id` | [string](#string) | | unique channel identifier | -| `relayer_address` | [string](#string) | | the relayer address to which the distribution address is registered | +| `relayer` | [string](#string) | | the relayer address to which the distribution address is registered | @@ -1269,8 +1269,8 @@ Query defines the ICS29 gRPC querier service. | `TotalRecvFees` | [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) | [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) | TotalRecvFees returns the total receive fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_recv_fees| | `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_ack_fees| | `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_timeout_fees| -| `Payee` | [QueryPayeeRequest](#ibc.applications.fee.v1.QueryPayeeRequest) | [QueryPayeeResponse](#ibc.applications.fee.v1.QueryPayeeResponse) | Payee returns the registered payee address for a specific channel given the relayer address | GET|/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/payee| -| `CounterpartyAddress` | [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) | [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) | CounterpartyAddress returns the registered counterparty address for forward relaying | GET|/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address| +| `Payee` | [QueryPayeeRequest](#ibc.applications.fee.v1.QueryPayeeRequest) | [QueryPayeeResponse](#ibc.applications.fee.v1.QueryPayeeResponse) | Payee returns the registered payee address for a specific channel given the relayer address | GET|/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/payee| +| `CounterpartyPayee` | [QueryCounterpartyPayeeRequest](#ibc.applications.fee.v1.QueryCounterpartyPayeeRequest) | [QueryCounterpartyPayeeResponse](#ibc.applications.fee.v1.QueryCounterpartyPayeeResponse) | CounterpartyPayee returns the registered counterparty payee for forward relaying | GET|/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/counterparty_payee| | `FeeEnabledChannels` | [QueryFeeEnabledChannelsRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest) | [QueryFeeEnabledChannelsResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse) | FeeEnabledChannels returns a list of all fee enabled channels | GET|/ibc/apps/fee/v1/fee_enabled| | `FeeEnabledChannel` | [QueryFeeEnabledChannelRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelRequest) | [QueryFeeEnabledChannelResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelResponse) | FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel | GET|/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled| diff --git a/modules/apps/29-fee/client/cli/cli.go b/modules/apps/29-fee/client/cli/cli.go index d609104ba67..332493deec8 100644 --- a/modules/apps/29-fee/client/cli/cli.go +++ b/modules/apps/29-fee/client/cli/cli.go @@ -22,7 +22,7 @@ func GetQueryCmd() *cobra.Command { GetCmdTotalTimeoutFees(), GetCmdIncentivizedPacketsForChannel(), GetCmdPayee(), - GetCmdCounterpartyAddress(), + GetCmdCounterpartyPayee(), GetCmdFeeEnabledChannel(), GetCmdFeeEnabledChannels(), ) diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index 3cfdcb27b33..3714c576748 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -242,7 +242,7 @@ func GetCmdTotalTimeoutFees() *cobra.Command { // GetCmdPayee returns the command handler for the Query/Payee rpc. func GetCmdPayee() *cobra.Command { cmd := &cobra.Command{ - Use: "payee [channel-id] [relayer-address]", + Use: "payee [channel-id] [relayer]", Short: "Query the relayer payee address on a given channel", Long: "Query the relayer payee address on a given channel", Args: cobra.ExactArgs(2), @@ -260,8 +260,8 @@ func GetCmdPayee() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) req := &types.QueryPayeeRequest{ - ChannelId: args[0], - RelayerAddress: args[1], + ChannelId: args[0], + Relayer: args[1], } res, err := queryClient.Payee(cmd.Context(), req) @@ -278,14 +278,14 @@ func GetCmdPayee() *cobra.Command { return cmd } -// GetCmdCounterpartyAddress returns the command handler for the Query/CounterpartyAddress rpc. -func GetCmdCounterpartyAddress() *cobra.Command { +// GetCmdCounterpartyPayee returns the command handler for the Query/CounterpartyPayee rpc. +func GetCmdCounterpartyPayee() *cobra.Command { cmd := &cobra.Command{ - Use: "counterparty-address [channel-id] [address]", - Short: "Query the relayer counterparty address on a given channel", - Long: "Query the relayer counterparty address on a given channel", + Use: "counterparty-payee [channel-id] [relayer]", + Short: "Query the relayer counterparty payee on a given channel", + Long: "Query the relayer counterparty payee on a given channel", Args: cobra.ExactArgs(2), - Example: fmt.Sprintf("%s query ibc-fee counterparty-address channel-5 cosmos1layxcsmyye0dc0har9sdfzwckaz8sjwlfsj8zs", version.AppName), + Example: fmt.Sprintf("%s query ibc-fee counterparty-payee channel-5 cosmos1layxcsmyye0dc0har9sdfzwckaz8sjwlfsj8zs", version.AppName), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { @@ -298,12 +298,12 @@ func GetCmdCounterpartyAddress() *cobra.Command { queryClient := types.NewQueryClient(clientCtx) - req := &types.QueryCounterpartyAddressRequest{ - ChannelId: args[0], - RelayerAddress: args[1], + req := &types.QueryCounterpartyPayeeRequest{ + ChannelId: args[0], + Relayer: args[1], } - res, err := queryClient.CounterpartyAddress(cmd.Context(), req) + res, err := queryClient.CounterpartyPayee(cmd.Context(), req) if err != nil { return err } diff --git a/modules/apps/29-fee/keeper/genesis.go b/modules/apps/29-fee/keeper/genesis.go index 6d6f01b7b34..24e5ddd1ece 100644 --- a/modules/apps/29-fee/keeper/genesis.go +++ b/modules/apps/29-fee/keeper/genesis.go @@ -34,7 +34,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { return &types.GenesisState{ IdentifiedFees: k.GetAllIdentifiedPacketFees(ctx), FeeEnabledChannels: k.GetAllFeeEnabledChannels(ctx), - RegisteredPayees: k.GetAllPayeeAddresses(ctx), + RegisteredPayees: k.GetAllPayees(ctx), RegisteredCounterpartyPayees: k.GetAllCounterpartyPayees(ctx), ForwardRelayers: k.GetAllForwardRelayerAddresses(ctx), } diff --git a/modules/apps/29-fee/keeper/grpc_query.go b/modules/apps/29-fee/keeper/grpc_query.go index ec8bf2ea656..4abe16cbe90 100644 --- a/modules/apps/29-fee/keeper/grpc_query.go +++ b/modules/apps/29-fee/keeper/grpc_query.go @@ -179,9 +179,9 @@ func (k Keeper) Payee(goCtx context.Context, req *types.QueryPayeeRequest) (*typ ctx := sdk.UnwrapSDKContext(goCtx) - payeeAddr, found := k.GetPayeeAddress(ctx, req.RelayerAddress, req.ChannelId) + payeeAddr, found := k.GetPayeeAddress(ctx, req.Relayer, req.ChannelId) if !found { - return nil, status.Errorf(codes.NotFound, "payee address not found for address: %s on channel: %s", req.RelayerAddress, req.ChannelId) + return nil, status.Errorf(codes.NotFound, "payee address not found for address: %s on channel: %s", req.Relayer, req.ChannelId) } return &types.QueryPayeeResponse{ @@ -189,21 +189,21 @@ func (k Keeper) Payee(goCtx context.Context, req *types.QueryPayeeRequest) (*typ }, nil } -// CounterpartyAddress implements the Query/CounterpartyAddress gRPC method and returns the registered counterparty address for forward relaying -func (k Keeper) CounterpartyAddress(goCtx context.Context, req *types.QueryCounterpartyAddressRequest) (*types.QueryCounterpartyAddressResponse, error) { +// CounterpartyPayee implements the Query/CounterpartyPayee gRPC method and returns the registered counterparty payee address for forward relaying +func (k Keeper) CounterpartyPayee(goCtx context.Context, req *types.QueryCounterpartyPayeeRequest) (*types.QueryCounterpartyPayeeResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } ctx := sdk.UnwrapSDKContext(goCtx) - counterpartyAddr, found := k.GetCounterpartyPayeeAddress(ctx, req.RelayerAddress, req.ChannelId) + counterpartyPayeeAddr, found := k.GetCounterpartyPayeeAddress(ctx, req.Relayer, req.ChannelId) if !found { - return nil, status.Errorf(codes.NotFound, "counterparty address not found for address: %s on channel: %s", req.RelayerAddress, req.ChannelId) + return nil, status.Errorf(codes.NotFound, "counterparty payee address not found for address: %s on channel: %s", req.Relayer, req.ChannelId) } - return &types.QueryCounterpartyAddressResponse{ - CounterpartyAddress: counterpartyAddr, + return &types.QueryCounterpartyPayeeResponse{ + CounterpartyPayee: counterpartyPayeeAddr, }, nil } diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index 2f7b4f3f4bc..42a9091178a 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -432,7 +432,7 @@ func (suite *KeeperTestSuite) TestQueryPayee() { { "payee address not found: invalid relayer address", func() { - req.RelayerAddress = "invalid-addr" + req.Relayer = "invalid-addr" }, false, }, @@ -453,8 +453,8 @@ func (suite *KeeperTestSuite) TestQueryPayee() { ) req = &types.QueryPayeeRequest{ - ChannelId: suite.path.EndpointA.ChannelID, - RelayerAddress: suite.chainA.SenderAccount.GetAddress().String(), + ChannelId: suite.path.EndpointA.ChannelID, + Relayer: suite.chainA.SenderAccount.GetAddress().String(), } tc.malleate() @@ -472,8 +472,8 @@ func (suite *KeeperTestSuite) TestQueryPayee() { } } -func (suite *KeeperTestSuite) TestQueryCounterpartyAddress() { - var req *types.QueryCounterpartyAddressRequest +func (suite *KeeperTestSuite) TestQueryCounterpartyPayee() { + var req *types.QueryCounterpartyPayeeRequest testCases := []struct { name string @@ -495,7 +495,7 @@ func (suite *KeeperTestSuite) TestQueryCounterpartyAddress() { { "counterparty address not found: invalid address", func() { - req.RelayerAddress = "invalid-addr" + req.Relayer = "invalid-addr" }, false, }, @@ -506,28 +506,28 @@ func (suite *KeeperTestSuite) TestQueryCounterpartyAddress() { suite.SetupTest() // reset pk := secp256k1.GenPrivKey().PubKey() - expectedCounterpartyAddr := sdk.AccAddress(pk.Address()) + expCounterpartyPayeeAddr := sdk.AccAddress(pk.Address()) suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress( suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), - expectedCounterpartyAddr.String(), + expCounterpartyPayeeAddr.String(), suite.path.EndpointA.ChannelID, ) - req = &types.QueryCounterpartyAddressRequest{ - ChannelId: suite.path.EndpointA.ChannelID, - RelayerAddress: suite.chainA.SenderAccount.GetAddress().String(), + req = &types.QueryCounterpartyPayeeRequest{ + ChannelId: suite.path.EndpointA.ChannelID, + Relayer: suite.chainA.SenderAccount.GetAddress().String(), } tc.malleate() ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) - res, err := suite.queryClient.CounterpartyAddress(ctx, req) + res, err := suite.queryClient.CounterpartyPayee(ctx, req) if tc.expPass { suite.Require().NoError(err) - suite.Require().Equal(expectedCounterpartyAddr.String(), res.CounterpartyAddress) + suite.Require().Equal(expCounterpartyPayeeAddr.String(), res.CounterpartyPayee) } else { suite.Require().Error(err) } diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index 143acafb80d..c94f661c904 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -165,8 +165,8 @@ func (k Keeper) SetPayeeAddress(ctx sdk.Context, relayerAddr, payeeAddr, channel store.Set(types.KeyPayee(relayerAddr, channelID), []byte(payeeAddr)) } -// GetAllPayeeAddresses returns all registered payees addresses -func (k Keeper) GetAllPayeeAddresses(ctx sdk.Context) []types.RegisteredPayee { +// GetAllPayees returns all registered payees addresses +func (k Keeper) GetAllPayees(ctx sdk.Context) []types.RegisteredPayee { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, []byte(types.PayeeKeyPrefix)) defer iterator.Close() diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index 1b6b0ede99f..f72888599e8 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -258,26 +258,7 @@ func (suite *KeeperTestSuite) TestGetAllFeeEnabledChannels() { suite.Require().Equal(ch, expectedCh) } -func (suite *KeeperTestSuite) TestGetAllRelayerAddresses() { - relayerAddr := suite.chainA.SenderAccount.GetAddress().String() - counterpartyPayee := suite.chainB.SenderAccount.GetAddress().String() - - suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainA.GetContext(), relayerAddr, counterpartyPayee, ibctesting.FirstChannelID) - - expectedCounterpartyPayee := []types.RegisteredCounterpartyPayee{ - { - Relayer: relayerAddr, - CounterpartyPayee: counterpartyPayee, - ChannelId: ibctesting.FirstChannelID, - }, - } - - counterpartyPayeeAddr := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllCounterpartyPayees(suite.chainA.GetContext()) - suite.Require().Len(counterpartyPayeeAddr, len(expectedCounterpartyPayee)) - suite.Require().Equal(counterpartyPayeeAddr, expectedCounterpartyPayee) -} - -func (suite *KeeperTestSuite) TestGetAllPayeeAddresses() { +func (suite *KeeperTestSuite) TestGetAllPayees() { var expectedPayees []types.RegisteredPayee for i := 0; i < 3; i++ { @@ -297,7 +278,26 @@ func (suite *KeeperTestSuite) TestGetAllPayeeAddresses() { expectedPayees = append(expectedPayees, registeredPayee) } - registeredPayees := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllPayeeAddresses(suite.chainA.GetContext()) + registeredPayees := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllPayees(suite.chainA.GetContext()) suite.Require().Len(registeredPayees, len(expectedPayees)) suite.Require().ElementsMatch(expectedPayees, registeredPayees) } + +func (suite *KeeperTestSuite) TestGetAllCounterpartyPayees() { + relayerAddr := suite.chainA.SenderAccount.GetAddress().String() + counterpartyPayee := suite.chainB.SenderAccount.GetAddress().String() + + suite.chainA.GetSimApp().IBCFeeKeeper.SetCounterpartyPayeeAddress(suite.chainA.GetContext(), relayerAddr, counterpartyPayee, ibctesting.FirstChannelID) + + expectedCounterpartyPayee := []types.RegisteredCounterpartyPayee{ + { + Relayer: relayerAddr, + CounterpartyPayee: counterpartyPayee, + ChannelId: ibctesting.FirstChannelID, + }, + } + + counterpartyPayeeAddr := suite.chainA.GetSimApp().IBCFeeKeeper.GetAllCounterpartyPayees(suite.chainA.GetContext()) + suite.Require().Len(counterpartyPayeeAddr, len(expectedCounterpartyPayee)) + suite.Require().Equal(counterpartyPayeeAddr, expectedCounterpartyPayee) +} diff --git a/modules/apps/29-fee/types/query.pb.go b/modules/apps/29-fee/types/query.pb.go index 9d0de9110a5..46e12a4e437 100644 --- a/modules/apps/29-fee/types/query.pb.go +++ b/modules/apps/29-fee/types/query.pb.go @@ -642,7 +642,7 @@ type QueryPayeeRequest struct { // unique channel identifier ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` // the relayer address to which the distribution address is registered - RelayerAddress string `protobuf:"bytes,2,opt,name=relayer_address,json=relayerAddress,proto3" json:"relayer_address,omitempty" yaml:"relayer_address"` + Relayer string `protobuf:"bytes,2,opt,name=relayer,proto3" json:"relayer,omitempty"` } func (m *QueryPayeeRequest) Reset() { *m = QueryPayeeRequest{} } @@ -685,9 +685,9 @@ func (m *QueryPayeeRequest) GetChannelId() string { return "" } -func (m *QueryPayeeRequest) GetRelayerAddress() string { +func (m *QueryPayeeRequest) GetRelayer() string { if m != nil { - return m.RelayerAddress + return m.Relayer } return "" } @@ -738,26 +738,26 @@ func (m *QueryPayeeResponse) GetPayeeAddress() string { return "" } -// QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc -type QueryCounterpartyAddressRequest struct { +// QueryCounterpartyPayeeRequest defines the request type for the CounterpartyPayee rpc +type QueryCounterpartyPayeeRequest struct { // unique channel identifier ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty" yaml:"channel_id"` // the relayer address to which the counterparty is registered - RelayerAddress string `protobuf:"bytes,2,opt,name=relayer_address,json=relayerAddress,proto3" json:"relayer_address,omitempty" yaml:"relayer_address"` + Relayer string `protobuf:"bytes,2,opt,name=relayer,proto3" json:"relayer,omitempty"` } -func (m *QueryCounterpartyAddressRequest) Reset() { *m = QueryCounterpartyAddressRequest{} } -func (m *QueryCounterpartyAddressRequest) String() string { return proto.CompactTextString(m) } -func (*QueryCounterpartyAddressRequest) ProtoMessage() {} -func (*QueryCounterpartyAddressRequest) Descriptor() ([]byte, []int) { +func (m *QueryCounterpartyPayeeRequest) Reset() { *m = QueryCounterpartyPayeeRequest{} } +func (m *QueryCounterpartyPayeeRequest) String() string { return proto.CompactTextString(m) } +func (*QueryCounterpartyPayeeRequest) ProtoMessage() {} +func (*QueryCounterpartyPayeeRequest) Descriptor() ([]byte, []int) { return fileDescriptor_0638a8a78ca2503c, []int{14} } -func (m *QueryCounterpartyAddressRequest) XXX_Unmarshal(b []byte) error { +func (m *QueryCounterpartyPayeeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryCounterpartyAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryCounterpartyPayeeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryCounterpartyAddressRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryCounterpartyPayeeRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -767,50 +767,50 @@ func (m *QueryCounterpartyAddressRequest) XXX_Marshal(b []byte, deterministic bo return b[:n], nil } } -func (m *QueryCounterpartyAddressRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryCounterpartyAddressRequest.Merge(m, src) +func (m *QueryCounterpartyPayeeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCounterpartyPayeeRequest.Merge(m, src) } -func (m *QueryCounterpartyAddressRequest) XXX_Size() int { +func (m *QueryCounterpartyPayeeRequest) XXX_Size() int { return m.Size() } -func (m *QueryCounterpartyAddressRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryCounterpartyAddressRequest.DiscardUnknown(m) +func (m *QueryCounterpartyPayeeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCounterpartyPayeeRequest.DiscardUnknown(m) } -var xxx_messageInfo_QueryCounterpartyAddressRequest proto.InternalMessageInfo +var xxx_messageInfo_QueryCounterpartyPayeeRequest proto.InternalMessageInfo -func (m *QueryCounterpartyAddressRequest) GetChannelId() string { +func (m *QueryCounterpartyPayeeRequest) GetChannelId() string { if m != nil { return m.ChannelId } return "" } -func (m *QueryCounterpartyAddressRequest) GetRelayerAddress() string { +func (m *QueryCounterpartyPayeeRequest) GetRelayer() string { if m != nil { - return m.RelayerAddress + return m.Relayer } return "" } -// QueryCounterpartyAddressResponse defines the response type for the CounterpartyAddress rpc -type QueryCounterpartyAddressResponse struct { - // the counterparty address used to compensate forward relaying - CounterpartyAddress string `protobuf:"bytes,1,opt,name=counterparty_address,json=counterpartyAddress,proto3" json:"counterparty_address,omitempty" yaml:"counterparty_address"` +// QueryCounterpartyPayeeResponse defines the response type for the CounterpartyPayee rpc +type QueryCounterpartyPayeeResponse struct { + // the counterparty payee address used to compensate forward relaying + CounterpartyPayee string `protobuf:"bytes,1,opt,name=counterparty_payee,json=counterpartyPayee,proto3" json:"counterparty_payee,omitempty" yaml:"counterparty_payee"` } -func (m *QueryCounterpartyAddressResponse) Reset() { *m = QueryCounterpartyAddressResponse{} } -func (m *QueryCounterpartyAddressResponse) String() string { return proto.CompactTextString(m) } -func (*QueryCounterpartyAddressResponse) ProtoMessage() {} -func (*QueryCounterpartyAddressResponse) Descriptor() ([]byte, []int) { +func (m *QueryCounterpartyPayeeResponse) Reset() { *m = QueryCounterpartyPayeeResponse{} } +func (m *QueryCounterpartyPayeeResponse) String() string { return proto.CompactTextString(m) } +func (*QueryCounterpartyPayeeResponse) ProtoMessage() {} +func (*QueryCounterpartyPayeeResponse) Descriptor() ([]byte, []int) { return fileDescriptor_0638a8a78ca2503c, []int{15} } -func (m *QueryCounterpartyAddressResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryCounterpartyPayeeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryCounterpartyAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryCounterpartyPayeeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryCounterpartyAddressResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryCounterpartyPayeeResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -820,21 +820,21 @@ func (m *QueryCounterpartyAddressResponse) XXX_Marshal(b []byte, deterministic b return b[:n], nil } } -func (m *QueryCounterpartyAddressResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryCounterpartyAddressResponse.Merge(m, src) +func (m *QueryCounterpartyPayeeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCounterpartyPayeeResponse.Merge(m, src) } -func (m *QueryCounterpartyAddressResponse) XXX_Size() int { +func (m *QueryCounterpartyPayeeResponse) XXX_Size() int { return m.Size() } -func (m *QueryCounterpartyAddressResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryCounterpartyAddressResponse.DiscardUnknown(m) +func (m *QueryCounterpartyPayeeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCounterpartyPayeeResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryCounterpartyAddressResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryCounterpartyPayeeResponse proto.InternalMessageInfo -func (m *QueryCounterpartyAddressResponse) GetCounterpartyAddress() string { +func (m *QueryCounterpartyPayeeResponse) GetCounterpartyPayee() string { if m != nil { - return m.CounterpartyAddress + return m.CounterpartyPayee } return "" } @@ -1056,8 +1056,8 @@ func init() { proto.RegisterType((*QueryTotalTimeoutFeesResponse)(nil), "ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse") proto.RegisterType((*QueryPayeeRequest)(nil), "ibc.applications.fee.v1.QueryPayeeRequest") proto.RegisterType((*QueryPayeeResponse)(nil), "ibc.applications.fee.v1.QueryPayeeResponse") - proto.RegisterType((*QueryCounterpartyAddressRequest)(nil), "ibc.applications.fee.v1.QueryCounterpartyAddressRequest") - proto.RegisterType((*QueryCounterpartyAddressResponse)(nil), "ibc.applications.fee.v1.QueryCounterpartyAddressResponse") + proto.RegisterType((*QueryCounterpartyPayeeRequest)(nil), "ibc.applications.fee.v1.QueryCounterpartyPayeeRequest") + proto.RegisterType((*QueryCounterpartyPayeeResponse)(nil), "ibc.applications.fee.v1.QueryCounterpartyPayeeResponse") proto.RegisterType((*QueryFeeEnabledChannelsRequest)(nil), "ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest") proto.RegisterType((*QueryFeeEnabledChannelsResponse)(nil), "ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse") proto.RegisterType((*QueryFeeEnabledChannelRequest)(nil), "ibc.applications.fee.v1.QueryFeeEnabledChannelRequest") @@ -1069,92 +1069,91 @@ func init() { } var fileDescriptor_0638a8a78ca2503c = []byte{ - // 1358 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcd, 0x6f, 0x1b, 0x45, - 0x1c, 0xcd, 0xa4, 0x5f, 0xc9, 0x24, 0xfd, 0xc8, 0x38, 0xb4, 0xa9, 0x49, 0xec, 0x74, 0x4a, 0x21, - 0xa4, 0xca, 0xae, 0xe2, 0xd0, 0xa6, 0x45, 0x42, 0xa2, 0x76, 0x49, 0x09, 0x08, 0x35, 0x6c, 0x2b, - 0x04, 0x08, 0x70, 0xd7, 0xbb, 0x63, 0x67, 0x15, 0x67, 0x67, 0xbb, 0xbb, 0xb6, 0x70, 0xd3, 0x00, - 0xad, 0x88, 0x40, 0x80, 0x00, 0x09, 0x89, 0x03, 0xe2, 0x8a, 0x90, 0x90, 0x38, 0x70, 0xe4, 0x3f, - 0xe8, 0x09, 0x45, 0xe2, 0xc2, 0xc9, 0xa0, 0x84, 0x13, 0x47, 0x9f, 0x38, 0x00, 0x42, 0x3b, 0x33, - 0x6b, 0xaf, 0xb3, 0xbb, 0x89, 0x9d, 0x46, 0x81, 0x53, 0xec, 0xf9, 0x7d, 0xcc, 0x7b, 0x6f, 0x7e, - 0xbb, 0xf3, 0x1c, 0x78, 0xd6, 0x28, 0x68, 0xb2, 0x6a, 0x59, 0x65, 0x43, 0x53, 0x5d, 0x83, 0x9a, - 0x8e, 0x5c, 0x24, 0x44, 0xae, 0x4e, 0xcb, 0xb7, 0x2b, 0xc4, 0xae, 0x49, 0x96, 0x4d, 0x5d, 0x8a, - 0x4e, 0x19, 0x05, 0x4d, 0x0a, 0x26, 0x49, 0x45, 0x42, 0xa4, 0xea, 0x74, 0x72, 0xb8, 0x44, 0x4b, - 0x94, 0xe5, 0xc8, 0xde, 0x27, 0x9e, 0x9e, 0x1c, 0x2d, 0x51, 0x5a, 0x2a, 0x13, 0x59, 0xb5, 0x0c, - 0x59, 0x35, 0x4d, 0xea, 0x8a, 0x22, 0x1e, 0x4d, 0x69, 0xd4, 0x59, 0xa6, 0x8e, 0x5c, 0x50, 0x1d, - 0x6f, 0xa3, 0x02, 0x71, 0xd5, 0x69, 0x59, 0xa3, 0x86, 0x29, 0xe2, 0x93, 0xc1, 0x38, 0x43, 0xd1, - 0xcc, 0xb2, 0xd4, 0x92, 0x61, 0xb2, 0x66, 0x22, 0xf7, 0x4c, 0x1c, 0x7a, 0x0f, 0x1f, 0x4f, 0x39, - 0x17, 0x97, 0x52, 0x22, 0x26, 0x71, 0x0c, 0x27, 0xd8, 0x49, 0xa3, 0x36, 0x91, 0xb5, 0x45, 0xd5, - 0x34, 0x49, 0xd9, 0x4b, 0x11, 0x1f, 0x79, 0x0a, 0xfe, 0x04, 0xc0, 0xf4, 0xcb, 0x1e, 0x9e, 0x79, - 0x53, 0x23, 0xa6, 0x6b, 0x54, 0x8d, 0x3b, 0x44, 0x5f, 0x50, 0xb5, 0x25, 0xe2, 0x3a, 0x0a, 0xb9, - 0x5d, 0x21, 0x8e, 0x8b, 0xe6, 0x20, 0x6c, 0x81, 0x1c, 0x01, 0xe3, 0x60, 0x62, 0x20, 0xf3, 0xb8, - 0xc4, 0x19, 0x49, 0x1e, 0x23, 0x89, 0xeb, 0x2a, 0x18, 0x49, 0x0b, 0x6a, 0x89, 0x88, 0x5a, 0x25, - 0x50, 0x89, 0xce, 0xc0, 0x41, 0x96, 0x98, 0x5f, 0x24, 0x46, 0x69, 0xd1, 0x1d, 0xe9, 0x1d, 0x07, - 0x13, 0x07, 0x95, 0x01, 0xb6, 0xf6, 0x3c, 0x5b, 0xc2, 0x1f, 0x01, 0x38, 0x1e, 0x0f, 0xc7, 0xb1, - 0xa8, 0xe9, 0x10, 0x54, 0x84, 0xc3, 0x46, 0x20, 0x9c, 0xb7, 0x78, 0x7c, 0x04, 0x8c, 0x1f, 0x98, - 0x18, 0xc8, 0x4c, 0x49, 0x31, 0x07, 0x2b, 0xcd, 0xeb, 0x5e, 0x4d, 0xd1, 0xf0, 0x3b, 0xce, 0x11, - 0xe2, 0x64, 0x0f, 0x3e, 0xa8, 0xa7, 0x7b, 0x94, 0x84, 0x11, 0xde, 0x0f, 0xaf, 0x01, 0x98, 0x8a, - 0x01, 0xe3, 0x4b, 0xf3, 0x2c, 0xec, 0xe7, 0xbb, 0xe7, 0x0d, 0x5d, 0x28, 0x33, 0xc6, 0xf6, 0xf7, - 0x54, 0x97, 0x7c, 0xa9, 0xab, 0x9e, 0x26, 0x5e, 0xd6, 0xbc, 0x2e, 0xf6, 0xeb, 0xb3, 0xc4, 0xf7, - 0x4e, 0x44, 0xf9, 0x20, 0xfe, 0x8c, 0x9a, 0x9a, 0xe8, 0x30, 0x11, 0xa1, 0x89, 0x80, 0xb4, 0x2b, - 0x49, 0x50, 0x58, 0x12, 0xfc, 0x13, 0x80, 0x4f, 0xc6, 0x1d, 0xcf, 0x1c, 0xb5, 0x73, 0x9c, 0xef, - 0x5e, 0xcf, 0xcd, 0x29, 0x78, 0xc4, 0xa2, 0x36, 0x93, 0xd8, 0x53, 0xa7, 0x5f, 0x39, 0xec, 0x7d, - 0x9d, 0xd7, 0xd1, 0x18, 0x84, 0x42, 0x62, 0x2f, 0x76, 0x80, 0xc5, 0xfa, 0xc5, 0x4a, 0x84, 0xb4, - 0x07, 0xc3, 0xd2, 0x7e, 0x0a, 0xe0, 0x64, 0x27, 0x84, 0x84, 0xca, 0xb7, 0xf6, 0x70, 0xf2, 0xa2, - 0x67, 0xee, 0x4d, 0x78, 0x9a, 0xe1, 0xb9, 0x49, 0x5d, 0xb5, 0xac, 0x10, 0xad, 0xca, 0x52, 0xf7, - 0x6a, 0xda, 0xf0, 0x57, 0x00, 0x26, 0xa3, 0xfa, 0x0b, 0x7e, 0x77, 0x61, 0xbf, 0x4d, 0xb4, 0x6a, - 0xbe, 0x48, 0x88, 0x4f, 0xea, 0x74, 0xdb, 0x81, 0xf9, 0x47, 0x95, 0xa3, 0x86, 0x99, 0xbd, 0xea, - 0x35, 0x6f, 0xd4, 0xd3, 0x27, 0x6a, 0xea, 0x72, 0xf9, 0x69, 0xdc, 0xac, 0xc4, 0xdf, 0xfd, 0x9a, - 0x9e, 0x28, 0x19, 0xee, 0x62, 0xa5, 0x20, 0x69, 0x74, 0x59, 0x16, 0xef, 0x3e, 0xfe, 0x67, 0xca, - 0xd1, 0x97, 0x64, 0xb7, 0x66, 0x11, 0x87, 0x35, 0x71, 0x94, 0x3e, 0x5b, 0xa0, 0xc0, 0x6f, 0xc0, - 0x91, 0x16, 0xb6, 0x2b, 0xda, 0xd2, 0xde, 0x52, 0xff, 0x12, 0x04, 0xa5, 0x6d, 0xb6, 0x17, 0xcc, - 0x6b, 0xb0, 0x4f, 0xd5, 0x96, 0x3a, 0x24, 0x9e, 0x13, 0xc4, 0x8f, 0x73, 0xe2, 0x7e, 0x61, 0x77, - 0xbc, 0x8f, 0xa8, 0x1c, 0x02, 0xbe, 0x05, 0x47, 0x5b, 0xb8, 0x6e, 0x1a, 0xcb, 0x84, 0x56, 0xdc, - 0xbd, 0xa5, 0xfe, 0x2d, 0x80, 0x63, 0x31, 0x5b, 0x08, 0xfa, 0x6b, 0x00, 0x0e, 0xba, 0x7c, 0xbd, - 0x43, 0x0d, 0xae, 0x09, 0x0d, 0x12, 0x5c, 0x83, 0x60, 0x71, 0x77, 0x3a, 0x0c, 0xb8, 0x2d, 0x3c, - 0xde, 0xf3, 0x38, 0xc4, 0x90, 0x2e, 0xa8, 0x35, 0xe2, 0xbf, 0x0c, 0xd0, 0x53, 0x6d, 0xcf, 0xb9, - 0x27, 0x41, 0x7f, 0xf6, 0x91, 0x46, 0x3d, 0x3d, 0xc4, 0xf7, 0x6e, 0xc5, 0x70, 0xf0, 0xf1, 0xcf, - 0xc1, 0xe3, 0x36, 0x29, 0xab, 0x35, 0x62, 0xe7, 0x55, 0x5d, 0xb7, 0x89, 0xe3, 0xf0, 0xd7, 0x47, - 0x36, 0xd9, 0xa8, 0xa7, 0x4f, 0xfa, 0x33, 0xdb, 0x96, 0x80, 0x95, 0x63, 0x62, 0xe5, 0x8a, 0x58, - 0xb8, 0x01, 0x51, 0x10, 0x8f, 0x90, 0xeb, 0x19, 0x78, 0xd4, 0xf2, 0x16, 0x9a, 0x8d, 0x39, 0xa6, - 0x91, 0x46, 0x3d, 0x3d, 0xcc, 0x1b, 0xb7, 0x85, 0xb1, 0x32, 0xc8, 0xbe, 0xfb, 0x4d, 0xbf, 0xf6, - 0x5f, 0xe8, 0x39, 0x5a, 0x31, 0x5d, 0x62, 0x5b, 0xaa, 0xed, 0xd6, 0x44, 0xf0, 0x7f, 0xc0, 0xb9, - 0x2a, 0xee, 0xe0, 0x48, 0x74, 0x42, 0x01, 0x05, 0x0e, 0x6b, 0x81, 0xf0, 0x16, 0x21, 0xd2, 0x8d, - 0x7a, 0xfa, 0x51, 0x01, 0x34, 0x22, 0x0b, 0x2b, 0x09, 0x2d, 0xdc, 0x1b, 0x7f, 0xec, 0xdf, 0xb7, - 0x73, 0x84, 0x3c, 0x67, 0xaa, 0x85, 0x32, 0xd1, 0xc5, 0x0b, 0xf8, 0xbf, 0xb0, 0x22, 0xdf, 0xf8, - 0x87, 0x14, 0x85, 0x46, 0xa8, 0x70, 0x0f, 0xc0, 0xe1, 0x22, 0x21, 0x79, 0xc2, 0xe3, 0x79, 0x71, - 0x10, 0xfe, 0xe3, 0x33, 0x19, 0x7b, 0x21, 0x84, 0x7a, 0x66, 0xcf, 0x8a, 0xe7, 0x49, 0xc8, 0x16, - 0xd5, 0x15, 0x2b, 0xa8, 0x18, 0xc2, 0x82, 0xef, 0xfb, 0x0f, 0x77, 0xa8, 0xa7, 0x2f, 0xda, 0xf9, - 0xd6, 0xfd, 0xc9, 0x8f, 0x07, 0x35, 0xea, 0xe9, 0x63, 0x62, 0x4e, 0x79, 0x00, 0x37, 0xef, 0xd4, - 0xf6, 0xb9, 0xeb, 0xed, 0x6c, 0xee, 0xf0, 0x6b, 0x71, 0x27, 0xd7, 0x94, 0x6a, 0x16, 0x0e, 0x04, - 0x38, 0x31, 0x20, 0x7d, 0xd9, 0x93, 0x8d, 0x7a, 0x1a, 0x85, 0x08, 0x63, 0x05, 0xb6, 0x78, 0x66, - 0xfe, 0x19, 0x82, 0x87, 0x58, 0x6f, 0xf4, 0x23, 0x80, 0x89, 0x88, 0x7b, 0x1a, 0x5d, 0x8a, 0x95, - 0x79, 0x07, 0x67, 0x9b, 0xbc, 0xbc, 0x8b, 0x4a, 0xce, 0x07, 0x4f, 0xdd, 0xff, 0xf9, 0xf7, 0x2f, - 0x7a, 0x9f, 0x40, 0xe7, 0x64, 0xe1, 0xc5, 0x9b, 0x1e, 0x3c, 0xca, 0x21, 0xa0, 0xcf, 0x7a, 0x21, - 0x0a, 0xb7, 0x43, 0xb3, 0xdd, 0x02, 0xf0, 0x91, 0x5f, 0xea, 0xbe, 0x50, 0x00, 0x5f, 0x03, 0x0c, - 0xf9, 0xbb, 0x68, 0x35, 0x84, 0xdc, 0x1f, 0x34, 0x79, 0xa5, 0x79, 0xe1, 0x48, 0xad, 0x03, 0x5f, - 0x95, 0xbd, 0x11, 0x69, 0x0b, 0x8a, 0xe9, 0x59, 0x95, 0x1d, 0x0f, 0x96, 0xa9, 0x91, 0xb6, 0xa8, - 0xbf, 0xb8, 0x1a, 0x25, 0x09, 0xfa, 0x1b, 0xc0, 0xb1, 0x6d, 0x5d, 0x17, 0xca, 0x76, 0x7d, 0x3a, - 0x21, 0x0f, 0x9a, 0xcc, 0x3d, 0x54, 0x0f, 0x21, 0xd9, 0x0d, 0xa6, 0xd8, 0x4b, 0xe8, 0xc5, 0x6d, - 0x14, 0x8b, 0xd2, 0xc9, 0x57, 0x27, 0x72, 0x22, 0xfe, 0x02, 0xf0, 0x68, 0x9b, 0x0b, 0x43, 0x99, - 0xed, 0xb1, 0x46, 0x59, 0xc2, 0xe4, 0x4c, 0x57, 0x35, 0x82, 0xcf, 0x3d, 0x3e, 0x02, 0x2b, 0xa8, - 0xb6, 0x7f, 0x23, 0xe0, 0x7a, 0x48, 0xf2, 0x4d, 0x8f, 0x88, 0xfe, 0x04, 0x70, 0x30, 0xe8, 0xc4, - 0xd0, 0x74, 0x07, 0x4c, 0xda, 0x4d, 0x61, 0x32, 0xd3, 0x4d, 0x89, 0xe0, 0xfe, 0x1e, 0xe7, 0x7e, - 0x07, 0xbd, 0xbd, 0xdf, 0xdc, 0x7d, 0x9b, 0x88, 0x3e, 0xec, 0x85, 0x27, 0xb6, 0x3a, 0x31, 0x74, - 0xa1, 0x03, 0x2e, 0x61, 0x73, 0x98, 0xbc, 0xd8, 0x6d, 0x99, 0x90, 0xe1, 0x7d, 0x2e, 0xc3, 0x3b, - 0xe8, 0xee, 0x7e, 0xcb, 0x10, 0x74, 0x8a, 0xe8, 0x07, 0x00, 0x0f, 0x31, 0x6b, 0x85, 0x26, 0xb7, - 0x27, 0x12, 0xf4, 0x83, 0xc9, 0xf3, 0x1d, 0xe5, 0x0a, 0xa6, 0xd7, 0x19, 0xd1, 0x79, 0x74, 0xad, - 0xc3, 0x87, 0x57, 0x98, 0x21, 0x47, 0x5e, 0xd9, 0x62, 0x94, 0x56, 0x65, 0x66, 0xe2, 0xd0, 0x1f, - 0x00, 0x26, 0x22, 0xac, 0xd1, 0x4e, 0xd7, 0x50, 0xbc, 0xd7, 0xdb, 0xe9, 0x1a, 0xda, 0xc6, 0x87, - 0xe1, 0xb7, 0x18, 0xbb, 0x57, 0xd1, 0x2b, 0x0f, 0xcf, 0x2e, 0xca, 0xa9, 0xa1, 0xef, 0x01, 0x44, - 0x61, 0x03, 0xb4, 0xd3, 0xbd, 0x15, 0x6b, 0xe0, 0x76, 0xba, 0xb7, 0xe2, 0xbd, 0x16, 0x7e, 0x8c, - 0x31, 0x4d, 0xa1, 0xd1, 0x10, 0xd3, 0x80, 0x75, 0x40, 0xeb, 0x00, 0x0e, 0x85, 0x9a, 0xa0, 0x8b, - 0x5d, 0xee, 0xea, 0xa3, 0x9d, 0xed, 0xba, 0x4e, 0x80, 0x7d, 0x81, 0x81, 0xbd, 0x8a, 0xb2, 0xbb, - 0xbc, 0x31, 0x02, 0x94, 0xb2, 0xd7, 0x1f, 0x6c, 0xa4, 0xc0, 0xfa, 0x46, 0x0a, 0xfc, 0xb6, 0x91, - 0x02, 0x9f, 0x6f, 0xa6, 0x7a, 0xd6, 0x37, 0x53, 0x3d, 0xbf, 0x6c, 0xa6, 0x7a, 0x5e, 0xbf, 0x10, - 0xfe, 0x91, 0x65, 0x14, 0xb4, 0xa9, 0x12, 0x95, 0xab, 0x33, 0xf2, 0x32, 0xd5, 0x2b, 0x65, 0xe2, - 0xf0, 0xcd, 0x33, 0x97, 0xa7, 0xbc, 0xfd, 0xd9, 0xef, 0xae, 0xc2, 0x61, 0xf6, 0xaf, 0xbf, 0x99, - 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x64, 0x8c, 0x96, 0x8a, 0x27, 0x15, 0x00, 0x00, + // 1338 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x5d, 0x6f, 0xdb, 0x54, + 0x18, 0xee, 0xe9, 0x3e, 0xda, 0x9e, 0x76, 0xb0, 0x9c, 0x16, 0x96, 0x86, 0x36, 0xe9, 0x3c, 0x06, + 0xa5, 0x53, 0x6d, 0x35, 0x65, 0x74, 0x43, 0x42, 0xd0, 0x74, 0x74, 0x14, 0x06, 0x94, 0xac, 0x37, + 0x20, 0x50, 0xe6, 0x38, 0x27, 0xa9, 0xd5, 0xd4, 0xc7, 0xb3, 0x9d, 0x88, 0xac, 0x2b, 0xb0, 0x89, + 0x0a, 0x04, 0x08, 0x90, 0x90, 0xb8, 0xe0, 0x1e, 0x21, 0x90, 0xf8, 0x01, 0xfc, 0x83, 0x5d, 0xa1, + 0x4a, 0xdc, 0x20, 0x2e, 0x02, 0x6a, 0x11, 0x3f, 0x20, 0x57, 0x5c, 0x80, 0x84, 0x7c, 0xce, 0xeb, + 0xc4, 0x99, 0xed, 0x36, 0x29, 0xa5, 0x5c, 0xd5, 0xf6, 0x79, 0x3f, 0x9e, 0xe7, 0x39, 0xaf, 0x7d, + 0x9e, 0x14, 0x9f, 0xd3, 0xf3, 0x9a, 0xa2, 0x9a, 0x66, 0x59, 0xd7, 0x54, 0x47, 0x67, 0x86, 0xad, + 0x14, 0x29, 0x55, 0xaa, 0x33, 0xca, 0xcd, 0x0a, 0xb5, 0x6a, 0xb2, 0x69, 0x31, 0x87, 0x91, 0x33, + 0x7a, 0x5e, 0x93, 0xfd, 0x41, 0x72, 0x91, 0x52, 0xb9, 0x3a, 0x93, 0x18, 0x29, 0xb1, 0x12, 0xe3, + 0x31, 0x8a, 0x7b, 0x25, 0xc2, 0x13, 0x63, 0x25, 0xc6, 0x4a, 0x65, 0xaa, 0xa8, 0xa6, 0xae, 0xa8, + 0x86, 0xc1, 0x1c, 0x48, 0x12, 0xab, 0x49, 0x8d, 0xd9, 0xeb, 0xcc, 0x56, 0xf2, 0xaa, 0xed, 0x36, + 0xca, 0x53, 0x47, 0x9d, 0x51, 0x34, 0xa6, 0x1b, 0xb0, 0x3e, 0xe5, 0x5f, 0xe7, 0x28, 0x9a, 0x51, + 0xa6, 0x5a, 0xd2, 0x0d, 0x5e, 0x0c, 0x62, 0xcf, 0x46, 0xa1, 0x77, 0xf1, 0x89, 0x90, 0xf3, 0x51, + 0x21, 0x25, 0x6a, 0x50, 0x5b, 0xb7, 0xfd, 0x95, 0x34, 0x66, 0x51, 0x45, 0x5b, 0x55, 0x0d, 0x83, + 0x96, 0xdd, 0x10, 0xb8, 0x14, 0x21, 0xd2, 0x27, 0x08, 0xa7, 0x5e, 0x73, 0xf1, 0x2c, 0x19, 0x1a, + 0x35, 0x1c, 0xbd, 0xaa, 0xdf, 0xa2, 0x85, 0x65, 0x55, 0x5b, 0xa3, 0x8e, 0x9d, 0xa5, 0x37, 0x2b, + 0xd4, 0x76, 0xc8, 0x22, 0xc6, 0x2d, 0x90, 0x71, 0x34, 0x81, 0x26, 0x07, 0xd3, 0x8f, 0xc9, 0x82, + 0x91, 0xec, 0x32, 0x92, 0x85, 0xae, 0xc0, 0x48, 0x5e, 0x56, 0x4b, 0x14, 0x72, 0xb3, 0xbe, 0x4c, + 0x72, 0x16, 0x0f, 0xf1, 0xc0, 0xdc, 0x2a, 0xd5, 0x4b, 0xab, 0x4e, 0xbc, 0x77, 0x02, 0x4d, 0x1e, + 0xcf, 0x0e, 0xf2, 0x67, 0x2f, 0xf0, 0x47, 0xd2, 0x47, 0x08, 0x4f, 0x44, 0xc3, 0xb1, 0x4d, 0x66, + 0xd8, 0x94, 0x14, 0xf1, 0x88, 0xee, 0x5b, 0xce, 0x99, 0x62, 0x3d, 0x8e, 0x26, 0x8e, 0x4d, 0x0e, + 0xa6, 0xa7, 0xe5, 0x88, 0x8d, 0x95, 0x97, 0x0a, 0x6e, 0x4e, 0x51, 0xf7, 0x2a, 0x2e, 0x52, 0x6a, + 0x67, 0x8e, 0xdf, 0xab, 0xa7, 0x7a, 0xb2, 0xc3, 0x7a, 0xb0, 0x9f, 0xb4, 0x85, 0x70, 0x32, 0x02, + 0x8c, 0x27, 0xcd, 0x73, 0x78, 0x40, 0x74, 0xcf, 0xe9, 0x05, 0x50, 0x66, 0x9c, 0xf7, 0x77, 0x55, + 0x97, 0x3d, 0xa9, 0xab, 0xae, 0x26, 0x6e, 0xd4, 0x52, 0x01, 0xfa, 0xf5, 0x9b, 0x70, 0xdf, 0x89, + 0x28, 0x1f, 0x44, 0xef, 0x51, 0x53, 0x93, 0x02, 0x1e, 0x0e, 0xd1, 0x04, 0x20, 0x1d, 0x48, 0x12, + 0x12, 0x94, 0x44, 0xfa, 0x11, 0xe1, 0x27, 0xa2, 0xb6, 0x67, 0x91, 0x59, 0x0b, 0x82, 0xef, 0x61, + 0xcf, 0xcd, 0x19, 0xdc, 0x67, 0x32, 0x8b, 0x4b, 0xec, 0xaa, 0x33, 0x90, 0x3d, 0xe9, 0xde, 0x2e, + 0x15, 0xc8, 0x38, 0xc6, 0x20, 0xb1, 0xbb, 0x76, 0x8c, 0xaf, 0x0d, 0xc0, 0x93, 0x10, 0x69, 0x8f, + 0x07, 0xa5, 0xfd, 0x14, 0xe1, 0xa9, 0x4e, 0x08, 0x81, 0xca, 0x37, 0x0e, 0x71, 0xf2, 0xc2, 0x67, + 0xee, 0x2d, 0x3c, 0xca, 0xf1, 0xac, 0x30, 0x47, 0x2d, 0x67, 0xa9, 0x56, 0xe5, 0xa1, 0x87, 0x35, + 0x6d, 0xd2, 0x57, 0x08, 0x27, 0xc2, 0xea, 0x03, 0xbf, 0xdb, 0x78, 0xc0, 0xa2, 0x5a, 0x35, 0x57, + 0xa4, 0xd4, 0x23, 0x35, 0xda, 0xb6, 0x61, 0xde, 0x56, 0x2d, 0x30, 0xdd, 0xc8, 0x5c, 0x71, 0x8b, + 0x37, 0xea, 0xa9, 0xd3, 0x35, 0x75, 0xbd, 0xfc, 0xb4, 0xd4, 0xcc, 0x94, 0xbe, 0xfb, 0x35, 0x35, + 0x59, 0xd2, 0x9d, 0xd5, 0x4a, 0x5e, 0xd6, 0xd8, 0xba, 0x02, 0xdf, 0x3e, 0xf1, 0x67, 0xda, 0x2e, + 0xac, 0x29, 0x4e, 0xcd, 0xa4, 0x36, 0x2f, 0x62, 0x67, 0xfb, 0x2d, 0x40, 0x21, 0xbd, 0x89, 0xe3, + 0x2d, 0x6c, 0xf3, 0xda, 0xda, 0xe1, 0x52, 0xff, 0x12, 0xf9, 0xa5, 0x6d, 0x96, 0x07, 0xe6, 0x35, + 0xdc, 0xaf, 0x6a, 0x6b, 0x1d, 0x12, 0x5f, 0x00, 0xe2, 0x0f, 0x0a, 0xe2, 0x5e, 0x62, 0x77, 0xbc, + 0xfb, 0x54, 0x01, 0x41, 0xba, 0x81, 0xc7, 0x5a, 0xb8, 0x56, 0xf4, 0x75, 0xca, 0x2a, 0xce, 0xe1, + 0x52, 0xff, 0x06, 0xe1, 0xf1, 0x88, 0x16, 0x40, 0x7f, 0x0b, 0xe1, 0x21, 0x47, 0x3c, 0xef, 0x50, + 0x83, 0xab, 0xa0, 0xc1, 0xb0, 0xd0, 0xc0, 0x9f, 0xdc, 0x9d, 0x0e, 0x83, 0x4e, 0x0b, 0x8f, 0xa4, + 0xe1, 0x18, 0x07, 0xba, 0xac, 0xd6, 0xa8, 0xf7, 0x2d, 0x20, 0x4f, 0xb6, 0xbd, 0xe6, 0xae, 0x02, + 0x03, 0x99, 0x87, 0x1a, 0xf5, 0x54, 0x4c, 0xb4, 0x6e, 0xad, 0x49, 0xfe, 0xb7, 0x3f, 0x8e, 0xfb, + 0x2c, 0x5a, 0x56, 0x6b, 0xd4, 0x82, 0xaf, 0x86, 0x77, 0x2b, 0x5d, 0xc7, 0xc4, 0xdf, 0x04, 0x24, + 0x78, 0x06, 0x9f, 0x32, 0xdd, 0x07, 0x39, 0xb5, 0x50, 0xb0, 0xa8, 0x6d, 0x43, 0xa3, 0x78, 0xa3, + 0x9e, 0x1a, 0x11, 0x8d, 0xda, 0x96, 0xa5, 0xec, 0x10, 0xbf, 0x9f, 0x87, 0x5b, 0x06, 0x12, 0x2f, + 0xb0, 0x8a, 0xe1, 0x50, 0xcb, 0x54, 0x2d, 0xe7, 0xbf, 0x65, 0x61, 0xc0, 0xe1, 0x14, 0xd2, 0x10, + 0x18, 0x5d, 0xc3, 0x44, 0xf3, 0x2d, 0xe6, 0x38, 0x5e, 0xe8, 0x3c, 0xde, 0xa8, 0xa7, 0x46, 0xa1, + 0x73, 0x20, 0x46, 0xca, 0xc6, 0xb4, 0xfb, 0xab, 0x4a, 0x1f, 0x7b, 0xa7, 0xe1, 0x22, 0xa5, 0xcf, + 0x1b, 0x6a, 0xbe, 0x4c, 0x0b, 0xf0, 0x79, 0xfc, 0x3f, 0x8c, 0xc2, 0xd7, 0xde, 0x99, 0x18, 0x86, + 0x06, 0xf8, 0xdf, 0x41, 0x78, 0xa4, 0x48, 0x69, 0x8e, 0x8a, 0xf5, 0x1c, 0xa8, 0xea, 0x0d, 0xf7, + 0x54, 0xe4, 0xe7, 0x3a, 0x50, 0x33, 0x73, 0x0e, 0xa6, 0xfd, 0x11, 0x21, 0x59, 0x58, 0x55, 0x29, + 0x4b, 0x8a, 0x01, 0x2c, 0xd2, 0x5d, 0xef, 0xd5, 0x0b, 0xd4, 0xf4, 0x44, 0xbb, 0xd0, 0x3a, 0xdd, + 0xc4, 0xd6, 0x90, 0x46, 0x3d, 0xf5, 0x00, 0x4c, 0x9c, 0x58, 0x90, 0x9a, 0x27, 0x5e, 0xfb, 0x10, + 0xf5, 0x76, 0x36, 0x44, 0xd2, 0xeb, 0x51, 0x3b, 0xd7, 0x94, 0x6a, 0x0e, 0x0f, 0xfa, 0x38, 0x71, + 0x20, 0xfd, 0x99, 0x87, 0x1b, 0xf5, 0x14, 0x09, 0x10, 0x96, 0xb2, 0xb8, 0xc5, 0x33, 0xfd, 0x47, + 0x0c, 0x9f, 0xe0, 0xb5, 0xc9, 0x0f, 0x08, 0x0f, 0x87, 0x9c, 0xa2, 0xe4, 0x52, 0xa4, 0xcc, 0xfb, + 0xf8, 0xce, 0xc4, 0xe5, 0x03, 0x64, 0x0a, 0x3e, 0xd2, 0xf4, 0xdd, 0x9f, 0x7e, 0xff, 0xa2, 0xf7, + 0x71, 0x72, 0x5e, 0x01, 0xa7, 0xdc, 0x74, 0xc8, 0x61, 0xe7, 0x37, 0xf9, 0xac, 0x17, 0x93, 0x60, + 0x39, 0x32, 0xd7, 0x2d, 0x00, 0x0f, 0xf9, 0xa5, 0xee, 0x13, 0x01, 0xf8, 0x16, 0xe2, 0xc8, 0xdf, + 0x25, 0x9b, 0x01, 0xe4, 0xde, 0xa0, 0x29, 0x1b, 0xcd, 0xe3, 0x40, 0x6e, 0x6d, 0xf8, 0xa6, 0xe2, + 0x8e, 0x48, 0xdb, 0x22, 0x4c, 0xcf, 0xa6, 0x62, 0xbb, 0xb0, 0x0c, 0x8d, 0xb6, 0xad, 0x7a, 0x0f, + 0x37, 0xc3, 0x24, 0x21, 0x7f, 0x23, 0x3c, 0xbe, 0xa7, 0x27, 0x22, 0x99, 0xae, 0x77, 0x27, 0xe0, + 0x10, 0x13, 0x0b, 0xff, 0xaa, 0x06, 0x48, 0x76, 0x9d, 0x2b, 0xf6, 0x32, 0x79, 0x69, 0x0f, 0xc5, + 0xc2, 0x74, 0xf2, 0xd4, 0x09, 0x9d, 0x88, 0xbf, 0x10, 0x3e, 0xd5, 0xe6, 0x91, 0x48, 0x7a, 0x6f, + 0xac, 0x61, 0x86, 0x2d, 0x31, 0xdb, 0x55, 0x0e, 0xf0, 0xb9, 0x23, 0x46, 0x60, 0x83, 0xd4, 0x8e, + 0x6e, 0x04, 0x1c, 0x17, 0x49, 0xae, 0xe9, 0xe0, 0xc8, 0x9f, 0x08, 0x0f, 0xf9, 0x7d, 0x12, 0x99, + 0xe9, 0x80, 0x49, 0xbb, 0x65, 0x4b, 0xa4, 0xbb, 0x49, 0x01, 0xee, 0xef, 0x09, 0xee, 0xb7, 0xc8, + 0xdb, 0x47, 0xcd, 0xdd, 0x33, 0x71, 0xe4, 0xc3, 0x5e, 0x7c, 0xfa, 0x7e, 0x9f, 0x44, 0x2e, 0x76, + 0xc0, 0x25, 0x68, 0xdd, 0x12, 0x4f, 0x75, 0x9b, 0x06, 0x32, 0xbc, 0x2f, 0x64, 0x78, 0x87, 0xdc, + 0x3e, 0x6a, 0x19, 0xfc, 0x3e, 0x8e, 0x7c, 0x8b, 0xf0, 0x09, 0x7e, 0xf8, 0x93, 0xa9, 0xbd, 0x89, + 0xf8, 0x8d, 0x4e, 0xe2, 0x42, 0x47, 0xb1, 0xc0, 0xf4, 0x2a, 0x27, 0x3a, 0x4f, 0x9e, 0xed, 0xf0, + 0xe5, 0x05, 0xf7, 0x63, 0x2b, 0x1b, 0x70, 0xb5, 0xa9, 0x70, 0xcb, 0x42, 0x7e, 0x41, 0x38, 0x16, + 0xb0, 0x42, 0x64, 0x9f, 0x0d, 0x88, 0x32, 0x6b, 0x89, 0xb9, 0xae, 0xf3, 0x80, 0xcf, 0x0a, 0xe7, + 0xf3, 0x0a, 0xb9, 0x76, 0x70, 0x3e, 0x41, 0x3f, 0x46, 0xbe, 0x47, 0x98, 0x04, 0x8d, 0xce, 0x7e, + 0xe7, 0x53, 0xa4, 0x51, 0xdb, 0xef, 0x7c, 0x8a, 0xf6, 0x54, 0xd2, 0xa3, 0x9c, 0x5f, 0x92, 0x8c, + 0x05, 0xf8, 0xf9, 0x2c, 0x02, 0xd9, 0x46, 0x38, 0x16, 0x28, 0xb2, 0xdf, 0x66, 0x44, 0x39, 0xa4, + 0xc4, 0x5c, 0xd7, 0x79, 0x00, 0xf6, 0x45, 0x0e, 0xf6, 0x0a, 0xc9, 0x1c, 0xf0, 0x64, 0xf0, 0x51, + 0xca, 0xbc, 0x7a, 0x6f, 0x27, 0x89, 0xb6, 0x77, 0x92, 0xe8, 0xb7, 0x9d, 0x24, 0xfa, 0x7c, 0x37, + 0xd9, 0xb3, 0xbd, 0x9b, 0xec, 0xf9, 0x79, 0x37, 0xd9, 0xf3, 0xc6, 0xc5, 0xe0, 0x4f, 0x1d, 0x3d, + 0xaf, 0x4d, 0x97, 0x98, 0x52, 0x9d, 0x55, 0xd6, 0x59, 0xa1, 0x52, 0xa6, 0xb6, 0x68, 0x9e, 0xbe, + 0x3c, 0xed, 0xf6, 0xe7, 0xbf, 0x7e, 0xf2, 0x27, 0xf9, 0x3f, 0xe0, 0x66, 0xff, 0x09, 0x00, 0x00, + 0xff, 0xff, 0x15, 0xfb, 0x28, 0xf6, 0xad, 0x14, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1183,8 +1182,8 @@ type QueryClient interface { TotalTimeoutFees(ctx context.Context, in *QueryTotalTimeoutFeesRequest, opts ...grpc.CallOption) (*QueryTotalTimeoutFeesResponse, error) // Payee returns the registered payee address for a specific channel given the relayer address Payee(ctx context.Context, in *QueryPayeeRequest, opts ...grpc.CallOption) (*QueryPayeeResponse, error) - // CounterpartyAddress returns the registered counterparty address for forward relaying - CounterpartyAddress(ctx context.Context, in *QueryCounterpartyAddressRequest, opts ...grpc.CallOption) (*QueryCounterpartyAddressResponse, error) + // CounterpartyPayee returns the registered counterparty payee for forward relaying + CounterpartyPayee(ctx context.Context, in *QueryCounterpartyPayeeRequest, opts ...grpc.CallOption) (*QueryCounterpartyPayeeResponse, error) // FeeEnabledChannels returns a list of all fee enabled channels FeeEnabledChannels(ctx context.Context, in *QueryFeeEnabledChannelsRequest, opts ...grpc.CallOption) (*QueryFeeEnabledChannelsResponse, error) // FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel @@ -1262,9 +1261,9 @@ func (c *queryClient) Payee(ctx context.Context, in *QueryPayeeRequest, opts ... return out, nil } -func (c *queryClient) CounterpartyAddress(ctx context.Context, in *QueryCounterpartyAddressRequest, opts ...grpc.CallOption) (*QueryCounterpartyAddressResponse, error) { - out := new(QueryCounterpartyAddressResponse) - err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/CounterpartyAddress", in, out, opts...) +func (c *queryClient) CounterpartyPayee(ctx context.Context, in *QueryCounterpartyPayeeRequest, opts ...grpc.CallOption) (*QueryCounterpartyPayeeResponse, error) { + out := new(QueryCounterpartyPayeeResponse) + err := c.cc.Invoke(ctx, "/ibc.applications.fee.v1.Query/CounterpartyPayee", in, out, opts...) if err != nil { return nil, err } @@ -1305,8 +1304,8 @@ type QueryServer interface { TotalTimeoutFees(context.Context, *QueryTotalTimeoutFeesRequest) (*QueryTotalTimeoutFeesResponse, error) // Payee returns the registered payee address for a specific channel given the relayer address Payee(context.Context, *QueryPayeeRequest) (*QueryPayeeResponse, error) - // CounterpartyAddress returns the registered counterparty address for forward relaying - CounterpartyAddress(context.Context, *QueryCounterpartyAddressRequest) (*QueryCounterpartyAddressResponse, error) + // CounterpartyPayee returns the registered counterparty payee for forward relaying + CounterpartyPayee(context.Context, *QueryCounterpartyPayeeRequest) (*QueryCounterpartyPayeeResponse, error) // FeeEnabledChannels returns a list of all fee enabled channels FeeEnabledChannels(context.Context, *QueryFeeEnabledChannelsRequest) (*QueryFeeEnabledChannelsResponse, error) // FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel @@ -1338,8 +1337,8 @@ func (*UnimplementedQueryServer) TotalTimeoutFees(ctx context.Context, req *Quer func (*UnimplementedQueryServer) Payee(ctx context.Context, req *QueryPayeeRequest) (*QueryPayeeResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Payee not implemented") } -func (*UnimplementedQueryServer) CounterpartyAddress(ctx context.Context, req *QueryCounterpartyAddressRequest) (*QueryCounterpartyAddressResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CounterpartyAddress not implemented") +func (*UnimplementedQueryServer) CounterpartyPayee(ctx context.Context, req *QueryCounterpartyPayeeRequest) (*QueryCounterpartyPayeeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CounterpartyPayee not implemented") } func (*UnimplementedQueryServer) FeeEnabledChannels(ctx context.Context, req *QueryFeeEnabledChannelsRequest) (*QueryFeeEnabledChannelsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method FeeEnabledChannels not implemented") @@ -1478,20 +1477,20 @@ func _Query_Payee_Handler(srv interface{}, ctx context.Context, dec func(interfa return interceptor(ctx, in, info, handler) } -func _Query_CounterpartyAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryCounterpartyAddressRequest) +func _Query_CounterpartyPayee_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryCounterpartyPayeeRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).CounterpartyAddress(ctx, in) + return srv.(QueryServer).CounterpartyPayee(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/ibc.applications.fee.v1.Query/CounterpartyAddress", + FullMethod: "/ibc.applications.fee.v1.Query/CounterpartyPayee", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).CounterpartyAddress(ctx, req.(*QueryCounterpartyAddressRequest)) + return srv.(QueryServer).CounterpartyPayee(ctx, req.(*QueryCounterpartyPayeeRequest)) } return interceptor(ctx, in, info, handler) } @@ -1565,8 +1564,8 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Handler: _Query_Payee_Handler, }, { - MethodName: "CounterpartyAddress", - Handler: _Query_CounterpartyAddress_Handler, + MethodName: "CounterpartyPayee", + Handler: _Query_CounterpartyPayee_Handler, }, { MethodName: "FeeEnabledChannels", @@ -2050,10 +2049,10 @@ func (m *QueryPayeeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.RelayerAddress) > 0 { - i -= len(m.RelayerAddress) - copy(dAtA[i:], m.RelayerAddress) - i = encodeVarintQuery(dAtA, i, uint64(len(m.RelayerAddress))) + if len(m.Relayer) > 0 { + i -= len(m.Relayer) + copy(dAtA[i:], m.Relayer) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Relayer))) i-- dAtA[i] = 0x12 } @@ -2097,7 +2096,7 @@ func (m *QueryPayeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryCounterpartyAddressRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryCounterpartyPayeeRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2107,20 +2106,20 @@ func (m *QueryCounterpartyAddressRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryCounterpartyAddressRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryCounterpartyPayeeRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryCounterpartyAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryCounterpartyPayeeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.RelayerAddress) > 0 { - i -= len(m.RelayerAddress) - copy(dAtA[i:], m.RelayerAddress) - i = encodeVarintQuery(dAtA, i, uint64(len(m.RelayerAddress))) + if len(m.Relayer) > 0 { + i -= len(m.Relayer) + copy(dAtA[i:], m.Relayer) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Relayer))) i-- dAtA[i] = 0x12 } @@ -2134,7 +2133,7 @@ func (m *QueryCounterpartyAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int return len(dAtA) - i, nil } -func (m *QueryCounterpartyAddressResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryCounterpartyPayeeResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2144,20 +2143,20 @@ func (m *QueryCounterpartyAddressResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryCounterpartyAddressResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryCounterpartyPayeeResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryCounterpartyAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryCounterpartyPayeeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.CounterpartyAddress) > 0 { - i -= len(m.CounterpartyAddress) - copy(dAtA[i:], m.CounterpartyAddress) - i = encodeVarintQuery(dAtA, i, uint64(len(m.CounterpartyAddress))) + if len(m.CounterpartyPayee) > 0 { + i -= len(m.CounterpartyPayee) + copy(dAtA[i:], m.CounterpartyPayee) + i = encodeVarintQuery(dAtA, i, uint64(len(m.CounterpartyPayee))) i-- dAtA[i] = 0xa } @@ -2505,7 +2504,7 @@ func (m *QueryPayeeRequest) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } - l = len(m.RelayerAddress) + l = len(m.Relayer) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } @@ -2525,7 +2524,7 @@ func (m *QueryPayeeResponse) Size() (n int) { return n } -func (m *QueryCounterpartyAddressRequest) Size() (n int) { +func (m *QueryCounterpartyPayeeRequest) Size() (n int) { if m == nil { return 0 } @@ -2535,20 +2534,20 @@ func (m *QueryCounterpartyAddressRequest) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } - l = len(m.RelayerAddress) + l = len(m.Relayer) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } return n } -func (m *QueryCounterpartyAddressResponse) Size() (n int) { +func (m *QueryCounterpartyPayeeResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.CounterpartyAddress) + l = len(m.CounterpartyPayee) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } @@ -3812,7 +3811,7 @@ func (m *QueryPayeeRequest) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RelayerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Relayer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -3840,7 +3839,7 @@ func (m *QueryPayeeRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RelayerAddress = string(dAtA[iNdEx:postIndex]) + m.Relayer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -3945,7 +3944,7 @@ func (m *QueryPayeeResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryCounterpartyAddressRequest) Unmarshal(dAtA []byte) error { +func (m *QueryCounterpartyPayeeRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3968,10 +3967,10 @@ func (m *QueryCounterpartyAddressRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryCounterpartyAddressRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryCounterpartyPayeeRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryCounterpartyAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryCounterpartyPayeeRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -4008,7 +4007,7 @@ func (m *QueryCounterpartyAddressRequest) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RelayerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Relayer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4036,7 +4035,7 @@ func (m *QueryCounterpartyAddressRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RelayerAddress = string(dAtA[iNdEx:postIndex]) + m.Relayer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -4059,7 +4058,7 @@ func (m *QueryCounterpartyAddressRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryCounterpartyAddressResponse) Unmarshal(dAtA []byte) error { +func (m *QueryCounterpartyPayeeResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4082,15 +4081,15 @@ func (m *QueryCounterpartyAddressResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryCounterpartyAddressResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryCounterpartyPayeeResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryCounterpartyAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryCounterpartyPayeeResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CounterpartyPayee", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4118,7 +4117,7 @@ func (m *QueryCounterpartyAddressResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CounterpartyAddress = string(dAtA[iNdEx:postIndex]) + m.CounterpartyPayee = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/modules/apps/29-fee/types/query.pb.gw.go b/modules/apps/29-fee/types/query.pb.gw.go index 309fab4da17..d6e723f9bdd 100644 --- a/modules/apps/29-fee/types/query.pb.gw.go +++ b/modules/apps/29-fee/types/query.pb.gw.go @@ -647,15 +647,15 @@ func request_Query_Payee_0(ctx context.Context, marshaler runtime.Marshaler, cli return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["relayer_address"] + val, ok = pathParams["relayer"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer") } - protoReq.RelayerAddress, err = runtime.String(val) + protoReq.Relayer, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer", err) } msg, err := client.Payee(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) @@ -685,15 +685,15 @@ func local_request_Query_Payee_0(ctx context.Context, marshaler runtime.Marshale return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["relayer_address"] + val, ok = pathParams["relayer"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer") } - protoReq.RelayerAddress, err = runtime.String(val) + protoReq.Relayer, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer", err) } msg, err := server.Payee(ctx, &protoReq) @@ -701,8 +701,8 @@ func local_request_Query_Payee_0(ctx context.Context, marshaler runtime.Marshale } -func request_Query_CounterpartyAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryCounterpartyAddressRequest +func request_Query_CounterpartyPayee_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCounterpartyPayeeRequest var metadata runtime.ServerMetadata var ( @@ -723,24 +723,24 @@ func request_Query_CounterpartyAddress_0(ctx context.Context, marshaler runtime. return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["relayer_address"] + val, ok = pathParams["relayer"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer") } - protoReq.RelayerAddress, err = runtime.String(val) + protoReq.Relayer, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer", err) } - msg, err := client.CounterpartyAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.CounterpartyPayee(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Query_CounterpartyAddress_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryCounterpartyAddressRequest +func local_request_Query_CounterpartyPayee_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCounterpartyPayeeRequest var metadata runtime.ServerMetadata var ( @@ -761,18 +761,18 @@ func local_request_Query_CounterpartyAddress_0(ctx context.Context, marshaler ru return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "channel_id", err) } - val, ok = pathParams["relayer_address"] + val, ok = pathParams["relayer"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer_address") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "relayer") } - protoReq.RelayerAddress, err = runtime.String(val) + protoReq.Relayer, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer_address", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "relayer", err) } - msg, err := server.CounterpartyAddress(ctx, &protoReq) + msg, err := server.CounterpartyPayee(ctx, &protoReq) return msg, metadata, err } @@ -1035,7 +1035,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_CounterpartyAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_CounterpartyPayee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -1044,14 +1044,14 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_CounterpartyAddress_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_CounterpartyPayee_0(rctx, inboundMarshaler, server, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_CounterpartyAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_CounterpartyPayee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -1276,7 +1276,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_CounterpartyAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_CounterpartyPayee_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -1285,14 +1285,14 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_CounterpartyAddress_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_CounterpartyPayee_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_CounterpartyAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_CounterpartyPayee_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -1352,9 +1352,9 @@ var ( pattern_Query_TotalTimeoutFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8, 1, 0, 4, 1, 5, 9, 2, 10}, []string{"ibc", "apps", "fee", "v1", "channels", "packet_id.channel_id", "ports", "packet_id.port_id", "sequences", "packet_id.sequence", "total_timeout_fees"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_Payee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "fee", "v1", "channels", "channel_id", "relayers", "relayer_address", "payee"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_Payee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "fee", "v1", "channels", "channel_id", "relayers", "relayer", "payee"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_CounterpartyAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "fee", "v1", "channels", "channel_id", "relayers", "relayer_address", "counterparty_address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_Query_CounterpartyPayee_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6, 1, 0, 4, 1, 5, 7, 2, 8}, []string{"ibc", "apps", "fee", "v1", "channels", "channel_id", "relayers", "relayer", "counterparty_payee"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_FeeEnabledChannels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"ibc", "apps", "fee", "v1", "fee_enabled"}, "", runtime.AssumeColonVerbOpt(true))) @@ -1376,7 +1376,7 @@ var ( forward_Query_Payee_0 = runtime.ForwardResponseMessage - forward_Query_CounterpartyAddress_0 = runtime.ForwardResponseMessage + forward_Query_CounterpartyPayee_0 = runtime.ForwardResponseMessage forward_Query_FeeEnabledChannels_0 = runtime.ForwardResponseMessage diff --git a/proto/ibc/applications/fee/v1/query.proto b/proto/ibc/applications/fee/v1/query.proto index e08eee99816..ffa447ffd68 100644 --- a/proto/ibc/applications/fee/v1/query.proto +++ b/proto/ibc/applications/fee/v1/query.proto @@ -52,13 +52,12 @@ service Query { // Payee returns the registered payee address for a specific channel given the relayer address rpc Payee(QueryPayeeRequest) returns (QueryPayeeResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/payee"; + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/payee"; } - // CounterpartyAddress returns the registered counterparty address for forward relaying - rpc CounterpartyAddress(QueryCounterpartyAddressRequest) returns (QueryCounterpartyAddressResponse) { - option (google.api.http).get = - "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address"; + // CounterpartyPayee returns the registered counterparty payee for forward relaying + rpc CounterpartyPayee(QueryCounterpartyPayeeRequest) returns (QueryCounterpartyPayeeResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/counterparty_payee"; } // FeeEnabledChannels returns a list of all fee enabled channels @@ -170,7 +169,7 @@ message QueryPayeeRequest { // unique channel identifier string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; // the relayer address to which the distribution address is registered - string relayer_address = 2 [(gogoproto.moretags) = "yaml:\"relayer_address\""]; + string relayer = 2; } // QueryPayeeResponse defines the response type for the Payee rpc @@ -179,18 +178,18 @@ message QueryPayeeResponse { string payee_address = 1 [(gogoproto.moretags) = "yaml:\"payee_address\""]; } -// QueryCounterpartyAddressRequest defines the request type for the CounterpartyAddress rpc -message QueryCounterpartyAddressRequest { +// QueryCounterpartyPayeeRequest defines the request type for the CounterpartyPayee rpc +message QueryCounterpartyPayeeRequest { // unique channel identifier string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; // the relayer address to which the counterparty is registered - string relayer_address = 2 [(gogoproto.moretags) = "yaml:\"relayer_address\""]; + string relayer = 2; } -// QueryCounterpartyAddressResponse defines the response type for the CounterpartyAddress rpc -message QueryCounterpartyAddressResponse { - // the counterparty address used to compensate forward relaying - string counterparty_address = 1 [(gogoproto.moretags) = "yaml:\"counterparty_address\""]; +// QueryCounterpartyPayeeResponse defines the response type for the CounterpartyPayee rpc +message QueryCounterpartyPayeeResponse { + // the counterparty payee address used to compensate forward relaying + string counterparty_payee = 1 [(gogoproto.moretags) = "yaml:\"counterparty_payee\""]; } // QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc From 223f9d2eb4d4c342a65541b4f88850ce7ae93745 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 15 Jun 2022 20:25:10 +0200 Subject: [PATCH 165/275] chore: update changelog, versions for docs site and stable release table (#1541) * chore: update changelog and versions for docs site * add new release lines to stable release policy Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 182 +++++++++++++++++++++++++++++++++++++++++++++----- RELEASES.md | 5 +- docs/versions | 3 + 3 files changed, 171 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a64a889fe4..552d9abc9c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,8 +38,6 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies -* [\#1300](https://github.com/cosmos/ibc-go/pull/1300) Bump SDK version to v0.45.4 - ### API Breaking * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. @@ -53,35 +51,72 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements * (cleanup) [\#1335](https://github.com/cosmos/ibc-go/pull/1335/) `gofumpt -w -l .` to standardize the code layout more strictly than `go fmt ./...` -* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. -* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. * (middleware) [\#1022](https://github.com/cosmos/ibc-go/pull/1022) Add `GetAppVersion` to the ICS4Wrapper interface. This function should be used by IBC applications to obtain their own version since the version set in the channel structure may be wrapped many times by middleware. -* (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. -* (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. -* (modules/core/04-channel) [\#1279](https://github.com/cosmos/ibc-go/pull/1279) Add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse. Emit channel version during OpenInit/OpenTry +* (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees -* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. -* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. -* (modules/light-clients/07-tendermint) [\#1118](https://github.com/cosmos/ibc-go/pull/1118) Deprecating `AllowUpdateAfterExpiry and AllowUpdateAfterMisbehaviour`. See ADR-026 for context. ### Features -* (modules/core/02-client) [\#1336](https://github.com/cosmos/ibc-go/pull/1336) Adding Query/ConsensusStateHeights gRPC for fetching the height of every consensus state associated with a client. * [\#276](https://github.com/cosmos/ibc-go/pull/276) Adding the Fee Middleware module v1 * (apps/29-fee) [\#1229](https://github.com/cosmos/ibc-go/pull/1229) Adding CLI commands for getting all unrelayed incentivized packets and packet by packet-id. * (apps/29-fee) [\#1224](https://github.com/cosmos/ibc-go/pull/1224) Adding Query/CounterpartyAddress and CLI to ICS29 fee middleware * (apps/29-fee) [\#1225](https://github.com/cosmos/ibc-go/pull/1225) Adding Query/FeeEnabledChannel and Query/FeeEnabledChannels with CLIs to ICS29 fee middleware. * (modules/apps/29-fee) [\#1230](https://github.com/cosmos/ibc-go/pull/1230) Adding CLI command for getting incentivized packets for a specific channel-id. + +### Bug Fixes + +* (apps/29-fee) [\#1278](https://github.com/cosmos/ibc-go/pull/1278) The URI path for the query to get all incentivized packets for a specific channel did not follow the same format as the rest of queries. + +## [v3.1.0](https://github.com/cosmos/ibc-go/releases/tag/v3.1.0) - 2022-04-16 + +### Dependencies + +* [\#1300](https://github.com/cosmos/ibc-go/pull/1300) Bump SDK version to v0.45.4 + +### API Breaking + +### State Machine Breaking + +### Improvements + +* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. +* (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. +* (modules/core/04-channel) [\#1279](https://github.com/cosmos/ibc-go/pull/1279) Add selected channel version to MsgChanOpenInitResponse and MsgChanOpenTryResponse. Emit channel version during OpenInit/OpenTry +* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. +* (modules/light-clients/07-tendermint) [\#1118](https://github.com/cosmos/ibc-go/pull/1118) Deprecating `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehaviour`. See ADR-026 for context. + +### Features + +* (modules/core/02-client) [\#1336](https://github.com/cosmos/ibc-go/pull/1336) Adding Query/ConsensusStateHeights gRPC for fetching the height of every consensus state associated with a client. * (modules/apps/transfer) [\#1416](https://github.com/cosmos/ibc-go/pull/1416) Adding gRPC endpoint for getting an escrow account for a given port-id and channel-id. * (modules/apps/27-interchain-accounts) [\#1512](https://github.com/cosmos/ibc-go/pull/1512) Allowing ICA modules to handle all message types with "*". ### Bug Fixes * (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output -* (apps/29-fee) [\#1278](https://github.com/cosmos/ibc-go/pull/1278) The URI path for the query to get all incentivized packets for a specific channel did not follow the same format as the rest of queries. * (apps/transfer) [\#1451](https://github.com/cosmos/ibc-go/pull/1451) Fixing the support for base denoms that contain slashes. +## [v3.0.1](https://github.com/cosmos/ibc-go/releases/tag/v3.0.1) - 2022-04-16 + +### Dependencies + +* [\#1300](https://github.com/cosmos/ibc-go/pull/1300) Bump SDK version to v0.45.4 + +### Improvements + +* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. +* (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. +* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. + +### Bug Fixes + +* (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output + ## [v3.0.0](https://github.com/cosmos/ibc-go/releases/tag/v3.0.0) - 2022-03-15 ### Dependencies @@ -93,7 +128,6 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking -* (testing) [\#1003](https://github.com/cosmos/ibc-go/pull/1003) `CreateTMClientHeader` takes an additional `nextVals *tmtypes.ValidatorSet` as an argument * (testing) [\#939](https://github.com/cosmos/ibc-go/pull/939) Support custom power reduction for testing. * (modules/core/05-port) [\#1086](https://github.com/cosmos/ibc-go/pull/1086) Added `counterpartyChannelID` argument to IBCModule.OnChanOpenAck * (channel) [\#848](https://github.com/cosmos/ibc-go/pull/848) Added `ChannelId` to MsgChannelOpenInitResponse @@ -117,9 +151,6 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements * (interchain-accounts) [\#1037](https://github.com/cosmos/ibc-go/pull/1037) Add a function `InitModule` to the interchain accounts `AppModule`. This function should be called within the upgrade handler when adding the interchain accounts module to a chain. It should be called in place of InitGenesis (set the consensus version in the version map). -* (testing) [\#1003](https://github.com/cosmos/ibc-go/pull/1003) Testing chain's `Signer` fields has changed from `[]tmtypes.PrivValidator` to `map[string]tmtypes.PrivValidator` to accomodate valset updates changing the order of the ValidatorSet. -* (testing) [\#1003](https://github.com/cosmos/ibc-go/pull/1003) `SignAndDeliver` will now just deliver the transaction without creating and committing a block. Thus, it requires that `BeginBlock` MUST be called before `SignAndDeliver` -* (testing) [\#1003](https://github.com/cosmos/ibc-go/pull/1003) `NextBlock` will now call `EndBlock` and `Commit` internally and apply validator updates to the `NextVals` of `TestChain` and the `NextValsHash` of the current header. Test writers can now make changes to validator set and have them reflected in the `TestChain` and handled appropriately in `UpdateClient` * (testing) [\#942](https://github.com/cosmos/ibc-go/pull/942) `NewTestChain` will create 4 validators in validator set by default. A new constructor function `NewTestChainWithValSet` is provided for test writers who want custom control over the validator set of test chains. * (testing) [\#904](https://github.com/cosmos/ibc-go/pull/904) Add `ParsePacketFromEvents` function to the testing package. Useful when sending/relaying packets via the testing package. * (testing) [\#893](https://github.com/cosmos/ibc-go/pull/893) Support custom private keys for testing. @@ -129,7 +160,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#383](https://github.com/cosmos/ibc-go/pull/383) Adds helper functions for merging and splitting middleware versions from the underlying app version. * (modules/core/05-port) [\#288](https://github.com/cosmos/ibc-go/issues/288) Making the 05-port keeper function IsBound public. The IsBound function checks if the provided portID is already binded to a module. * (channel) [\#644](https://github.com/cosmos/ibc-go/pull/644) Adds `GetChannelConnection` to the ChannelKeeper. This function returns the connectionID and connection state associated with a channel. -* (channel) [\#647](https://github.com/cosmos/ibc-go/pull/647) Reorganizes channel handshake handling to set channel state after IBC application callbacks. +* (channel) [\647](https://github.com/cosmos/ibc-go/pull/647) Reorganizes channel handshake handling to set channel state after IBC application callbacks. * (client) [\#724](https://github.com/cosmos/ibc-go/pull/724) `IsRevisionFormat` and `IsClientIDFormat` have been updated to disallow newlines before the dash used to separate the chainID and revision number, and the client type and client sequence. * (interchain-accounts) [\#1466](https://github.com/cosmos/ibc-go/pull/1466) Emit event when there is an acknowledgement during `OnRecvPacket`. @@ -146,12 +177,69 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (client) [\#941](https://github.com/cosmos/ibc-go/pull/941) Classify client states without consensus states as expired * (channel) [\#995](https://github.com/cosmos/ibc-go/pull/995) Call `packet.GetSequence()` rather than passing func in `AcknowledgePacket` log output +## [v2.3.0](https://github.com/cosmos/ibc-go/releases/tag/v2.3.0) - 2022-04-16 + +### Dependencies + +* [\#404](https://github.com/cosmos/ibc-go/pull/404) Bump Go version to 1.17 +* [\#1300](https://github.com/cosmos/ibc-go/pull/1300) Bump SDK version to v0.45.4 + +### Improvements + +* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. +* (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. +* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. +* (modules/light-clients/07-tendermint) [\#1118](https://github.com/cosmos/ibc-go/pull/1118) Deprecating `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehaviour`. See ADR-026 for context. + +### Features + +* (modules/core/02-client) [\#1336](https://github.com/cosmos/ibc-go/pull/1336) Adding Query/ConsensusStateHeights gRPC for fetching the height of every consensus state associated with a client. +* (modules/apps/transfer) [\#1416](https://github.com/cosmos/ibc-go/pull/1416) Adding gRPC endpoint for getting an escrow account for a given port-id and channel-id. + +### Bug Fixes + +* (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output +* (apps/transfer) [\#1451](https://github.com/cosmos/ibc-go/pull/1451) Fixing the support for base denoms that contain slashes. + +## [v2.2.1](https://github.com/cosmos/ibc-go/releases/tag/v2.2.1) - 2022-04-16 + +### Improvements + +* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. +* (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. +* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. + +### Bug Fixes + +* (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output + ## [v2.2.0](https://github.com/cosmos/ibc-go/releases/tag/v2.2.0) - 2022-03-15 ### Dependencies * [\#851](https://github.com/cosmos/ibc-go/pull/851) Bump SDK version to v0.45.1 +## [v2.1.1](https://github.com/cosmos/ibc-go/releases/tag/v2.1.1) - 2022-04-16 + +### Dependencies + +* [\#1268](https://github.com/cosmos/ibc-go/pull/1268) Bump SDK version to v0.44.8 and Tendermint to version 0.34.19 + +### Improvements + +* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. +* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. + +### Bug Fixes + +* (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output + ## [v2.1.0](https://github.com/cosmos/ibc-go/releases/tag/v2.1.0) - 2022-03-15 ### Dependencies @@ -173,7 +261,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (transfer) [\#978](https://github.com/cosmos/ibc-go/pull/978) Support base denoms with slashes in denom validation * (channel) [\#995](https://github.com/cosmos/ibc-go/pull/995) Call `packet.GetSequence()` rather than passing func in `AcknowledgePacket` log output -## [v2.0.3](https://github.com/cosmos/ibc-go/releases/tag/v2.0.2) - 2022-02-03 +## [v2.0.3](https://github.com/cosmos/ibc-go/releases/tag/v2.0.3) - 2022-02-03 ### Improvements @@ -220,12 +308,70 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#384](https://github.com/cosmos/ibc-go/pull/384) Added `NegotiateAppVersion` method to `IBCModule` interface supported by a gRPC query service in `05-port`. This provides routing of requests to the desired application module callback, which in turn performs application version negotiation. +## [v1.5.0](https://github.com/cosmos/ibc-go/releases/tag/v1.5.0) - 2022-06-14 + +### Dependencies + +* [\#404](https://github.com/cosmos/ibc-go/pull/404) Bump Go version to 1.17 +* [\#1300](https://github.com/cosmos/ibc-go/pull/1300) Bump SDK version to v0.45.4 + +### Improvements + +* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. +* (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. +* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. +* (modules/light-clients/07-tendermint) [\#1118](https://github.com/cosmos/ibc-go/pull/1118) Deprecating `AllowUpdateAfterExpiry` and `AllowUpdateAfterMisbehaviour`. See ADR-026 for context. + +### Features + +* (modules/core/02-client) [\#1336](https://github.com/cosmos/ibc-go/pull/1336) Adding Query/ConsensusStateHeights gRPC for fetching the height of every consensus state associated with a client. +* (modules/apps/transfer) [\#1416](https://github.com/cosmos/ibc-go/pull/1416) Adding gRPC endpoint for getting an escrow account for a given port-id and channel-id. + +### Bug Fixes + +* (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output +* (apps/transfer) [\#1451](https://github.com/cosmos/ibc-go/pull/1451) Fixing the support for base denoms that contain slashes. + +## [v1.4.1](https://github.com/cosmos/ibc-go/releases/tag/v1.4.1) - 2022-06-14 + +### Improvements + +* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. +* (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. +* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. + +### Bug Fixes + +* (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output + ## [v1.4.0](https://github.com/cosmos/ibc-go/releases/tag/v1.4.0) - 2022-03-15 ### Dependencies * [\#851](https://github.com/cosmos/ibc-go/pull/851) Bump SDK version to v0.45.1 +## [v1.3.1](https://github.com/cosmos/ibc-go/releases/tag/v1.3.1) - 2022-06-14 + +### Dependencies + +* [\#1267](https://github.com/cosmos/ibc-go/pull/1267) Bump SDK version to v0.44.8 and Tendermint to version 0.34.19 + +### Improvements + +* (transfer) [\#1342](https://github.com/cosmos/ibc-go/pull/1342) `DenomTrace` grpc now takes in either an `ibc denom` or a `hash` instead of only accepting a `hash`. +* (modules/core/04-channel) [\#1160](https://github.com/cosmos/ibc-go/pull/1160) Improve `uint64 -> string` performance in `Logger`. +* (modules/core/keeper) [\#1284](https://github.com/cosmos/ibc-go/pull/1284) Add sanity check for the keepers passed into `ibckeeper.NewKeeper`. `ibckeeper.NewKeeper` now panics if any of the keepers passed in is empty. +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. +* (modules/core/04-channel) [\#1464](https://github.com/cosmos/ibc-go/pull/1464) Emit a channel close event when an ordered channel is closed. + +### Bug Fixes + +* (modules/core/04-channel) [\#1130](https://github.com/cosmos/ibc-go/pull/1130) Call `packet.GetSequence()` rather than passing func in `WriteAcknowledgement` log output + ## [v1.3.0](https://github.com/cosmos/ibc-go/releases/tag/v1.3.0) - 2022-03-15 ### Dependencies diff --git a/RELEASES.md b/RELEASES.md index c92cc13aed0..cb8ccb18224 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -64,12 +64,15 @@ For example, if the current major release series is v1 and was released on Janua Only the following major release series have a stable release status: |Release|End of Life Date| -|-------|-------| +|-------|----------------| |`v1.3.x`|July 01, 2022| |`v1.4.x`|July 01, 2022| +|`v1.5.x`|July 01, 2022| |`v2.1.x`|February 01, 2023| |`v2.2.x`|February 01, 2023| +|`v2.3.x`|February 01, 2023| |`v3.0.x`|March 15, 2023| +|`v3.1.x`|March 15, 2023| **Note**: The v1 major release series will reach end of life 6 months after merging this policy. v2 will reach end of life one year after merging this policy. diff --git a/docs/versions b/docs/versions index e568f9a716f..7771cabc308 100644 --- a/docs/versions +++ b/docs/versions @@ -1,7 +1,10 @@ +release/v3.1.x v3.1.0 release/v3.0.x v3.0.0 +release/v2.3.x v2.3.0 release/v2.2.x v2.2.0 release/v2.1.x v2.1.0 release/v2.0.x v2.0.0 +release/v1.5.x v1.5.0 release/v1.4.x v1.4.0 release/v1.3.x v1.3.0 release/v1.2.x v1.2.0 From 681a558e3d2da314313c0edde93b29d59b3b18be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jun 2022 20:43:28 +0200 Subject: [PATCH 166/275] build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.4 to 0.45.5 (#1525) * build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.4 to 0.45.5 Bumps [github.com/cosmos/cosmos-sdk](https://github.com/cosmos/cosmos-sdk) from 0.45.4 to 0.45.5. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.45.5/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/v0.45.4...v0.45.5) --- updated-dependencies: - dependency-name: github.com/cosmos/cosmos-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * updating changelog to reflect SDK v0.45.5 upgrade Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Damian Nolan Co-authored-by: Carlos Rodriguez --- CHANGELOG.md | 2 ++ go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 552d9abc9c9..e33c591d130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies +* [\#1525](https://github.com/cosmos/ibc-go/pull/1525) Bump SDK version to v0.45.5 + ### API Breaking * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. diff --git a/go.mod b/go.mod index 52253cfd620..454eb5d7614 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alp require ( github.com/armon/go-metrics v0.4.0 github.com/confio/ics23/go v0.7.0 - github.com/cosmos/cosmos-sdk v0.45.4 + github.com/cosmos/cosmos-sdk v0.45.5 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 diff --git a/go.sum b/go.sum index f79484ffd40..7da06990689 100644 --- a/go.sum +++ b/go.sum @@ -232,8 +232,8 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= -github.com/cosmos/cosmos-sdk v0.45.4 h1:eStDAhJdMY8n5arbBRe+OwpNeBSunxSBHp1g55ulfdA= -github.com/cosmos/cosmos-sdk v0.45.4/go.mod h1:WOqtDxN3eCCmnYLVla10xG7lEXkFjpTaqm2a2WasgCc= +github.com/cosmos/cosmos-sdk v0.45.5 h1:GVrZM+lss6y626Pq6loxh/3KLRgK/J6/alTkcKkYmGU= +github.com/cosmos/cosmos-sdk v0.45.5/go.mod h1:WOqtDxN3eCCmnYLVla10xG7lEXkFjpTaqm2a2WasgCc= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= From 1be4519a4129d71a462557d01ec4b9e9bd7c196e Mon Sep 17 00:00:00 2001 From: Charly Date: Thu, 16 Jun 2022 13:47:42 +0200 Subject: [PATCH 167/275] docs: overview of fee middleware (#1549) * fix broken link * fix: rm AllowUpdateAfter... check (#1118) * update code & test * update proto and adr026 * update CHANGELOG * update cli docs * update broken milestone link --- docs/.vuepress/config.js | 17 ++++++++++++ docs/middleware/ics29-fee/overview.md | 37 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 docs/middleware/ics29-fee/overview.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 43bd93590cd..7bb36d7c0f8 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -166,6 +166,23 @@ module.exports = { }, ] }, + { + title: "IBC Middleware Modules", + children: [ + { + title: "ICS29 Fee Middleware", + directory: true, + path: "/middleware", + children: [ + { + title: "Overview", + directory: false, + path: "/middleware/ics29-fee/overview.html" + }, + ] + }, + ] + }, { title: "Migrations", children: [ diff --git a/docs/middleware/ics29-fee/overview.md b/docs/middleware/ics29-fee/overview.md new file mode 100644 index 00000000000..e23261c712e --- /dev/null +++ b/docs/middleware/ics29-fee/overview.md @@ -0,0 +1,37 @@ + + +# Overview + +Learn about what the Fee Middleware module is, and how to build custom modules that utilize the Fee Middleware functionality {synopsis} + +## What is the Fee Middleware module? + +IBC does not depend on relayer operators for transaction verification. However, the relayer infrastructure ensures liveness of the Interchain network — operators listen for packets sent through channels opened between chains, and perform the vital service of ferrying these packets (and proof of the transaction on the sending chain/receipt on the receiving chain) to the clients on each side of the channel. + +Though relaying is permissionless and completely decentralized and accessible, it does come with operational costs. Running full nodes to query transaction proofs and paying for transaction fees associated with IBC packets are two of the primary cost burdens which have driven the overall discussion on a general, in-protocol incentivization mechanism for relayers. + +Initially, a [simple proposal](https://github.com/cosmos/ibc/pull/577/files) was created to incentivize relaying on ICS20 token transfers on the destination chain. However, the proposal was specific to ICS20 token transfers and would have to be reimplemented in this format on every other IBC application module. + +After much discussion, the proposal was expanded to a [general incentivisation design](https://github.com/cosmos/ibc/tree/master/spec/app/ics-029-fee-payment) that can be adopted by any ICS application protocol as [middleware](../../ibc/middleware/develop.md). + +## Concepts + +ICS29 fee payments in this middleware design are built on the assumption that sender chains are the source of incentives — the chain on which packets are sent is the same chain that fee distribution to relayer operators takes place. Therefore, the middleware enables the registering of addresses associated with each party involved in relaying the packet on the source chain, and the escrowing of fees by any party which will be paid out to each party on completion of the packet lifecycle. This registration process can be automated on start up of relayer infrastructure. + +`Forward relayer`: The relayer that submits the `MsgRecvPacket` message for a given packet (on the destination chain). + +`Reverse relayer`: The relayer that submits the `MsgAcknowledgement` message for a given packet (on the source chain). + +`Timeout relayer`: The relayer that submits the `MsgTimeout` or `MsgTimeoutOnClose` messages for a given packet (on the source chain). + +`Payee`: The account address on the source chain to be paid on completion of the packet lifecycle. The packet lifecycle on the source chain completes with the receipt of a `MsgTimeout`/`MsgTimeoutOnClose` or a `MsgAcknowledgement`. + +`Counterparty payee`: The account address to be paid on completion of the packet lifecycle on the destination chain. The package lifecycle on the destination chain completes with a successful `MsgRecvPacket`. + +`Refund address`: The address of the account paying for the incentivization of packet relaying. The account is refunded timeout fees upon successful acknowledgement. In the event of a packet timeout, both acknowledgement and receive fees are refunded. + +## Known Limitations + +The first version of fee payments middleware will only support incentivisation of new channels, however, channel upgradeability will enable incentivisation of all existing channels. From 9680cb91a61384593c4521484a071ad3c95c9b34 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Fri, 17 Jun 2022 15:40:08 +0200 Subject: [PATCH 168/275] feat: implement registered payee fee distribution (#1526) * adding distribution logic with new registered payees * updating ack test cases * removing commented out test * adding additional testcase to TestOnAcknowledgementPacket * cleaning up distribution logic and adapting tests * updating timeout test cases * updating timeout logic and adding application callback failure test cases * Apply suggestions from code review Co-authored-by: Charly * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * Update modules/apps/29-fee/ibc_middleware_test.go * adding missing comma from suggested testcases Co-authored-by: Cian Hatton Co-authored-by: Charly Co-authored-by: Carlos Rodriguez --- modules/apps/29-fee/ibc_middleware.go | 36 +- modules/apps/29-fee/ibc_middleware_test.go | 465 ++++++++++++--------- 2 files changed, 302 insertions(+), 199 deletions(-) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index d9161d7caba..6a0477f5508 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -267,10 +267,26 @@ func (im IBCMiddleware) OnAcknowledgementPacket( packetID := channeltypes.NewPacketId(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) - if found { + if !found { + // call underlying callback + return im.app.OnAcknowledgementPacket(ctx, packet, ack.AppAcknowledgement, relayer) + } + + payee, found := im.keeper.GetPayeeAddress(ctx, relayer.String(), packet.SourceChannel) + if !found { im.keeper.DistributePacketFeesOnAcknowledgement(ctx, ack.ForwardRelayerAddress, relayer, feesInEscrow.PacketFees, packetID) + + // call underlying callback + return im.app.OnAcknowledgementPacket(ctx, packet, ack.AppAcknowledgement, relayer) } + payeeAddr, err := sdk.AccAddressFromBech32(payee) + if err != nil { + return sdkerrors.Wrapf(err, "failed to create sdk.Address from payee: %s", payee) + } + + im.keeper.DistributePacketFeesOnAcknowledgement(ctx, ack.ForwardRelayerAddress, payeeAddr, feesInEscrow.PacketFees, packetID) + // call underlying callback return im.app.OnAcknowledgementPacket(ctx, packet, ack.AppAcknowledgement, relayer) } @@ -293,10 +309,26 @@ func (im IBCMiddleware) OnTimeoutPacket( packetID := channeltypes.NewPacketId(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) - if found { + if !found { + // call underlying callback + return im.app.OnTimeoutPacket(ctx, packet, relayer) + } + + payee, found := im.keeper.GetPayeeAddress(ctx, relayer.String(), packet.SourceChannel) + if !found { im.keeper.DistributePacketFeesOnTimeout(ctx, relayer, feesInEscrow.PacketFees, packetID) + + // call underlying callback + return im.app.OnTimeoutPacket(ctx, packet, relayer) } + payeeAddr, err := sdk.AccAddressFromBech32(payee) + if err != nil { + return sdkerrors.Wrapf(err, "failed to create sdk.Address from payee: %s", payee) + } + + im.keeper.DistributePacketFeesOnTimeout(ctx, payeeAddr, feesInEscrow.PacketFees, packetID) + // call underlying callback return im.app.OnTimeoutPacket(ctx, packet, relayer) } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 1aa8810453e..b5478fb1c51 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -607,112 +607,189 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { } } -// different channel than sending chain func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { var ( - ack []byte - packetFee types.PacketFee - originalBalance sdk.Coins - expectedBalance sdk.Coins - expectedRelayerBalance sdk.Coins - expLocked bool + ack []byte + packetID channeltypes.PacketId + packetFee types.PacketFee + refundAddr sdk.AccAddress + relayerAddr sdk.AccAddress + expRefundAccBalance sdk.Coins + expPayeeAccBalance sdk.Coins ) testCases := []struct { - name string - malleate func() - expFeesDistributed bool - expPass bool + name string + malleate func() + expPass bool + expResult func() }{ { "success", func() { - expectedRelayerBalance = packetFee.Fee.RecvFee.Add(packetFee.Fee.AckFee[0]) + // retrieve the relayer acc balance and add the expected recv and ack fees + relayerAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom)) + expPayeeAccBalance = relayerAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.AckFee...) + + // retrieve the refund acc balance and add the expected timeout fees + refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) + expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.TimeoutFee...) }, true, + func() { + // assert that the packet fees have been distributed + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + + relayerAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(relayerAccBalance)) + + refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expRefundAccBalance, sdk.NewCoins(refundAccBalance)) + }, + }, + { + "success: with registered payee address", + func() { + payeeAddr := suite.chainA.SenderAccounts[2].SenderAccount.GetAddress() + suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + payeeAddr.String(), + suite.path.EndpointA.ChannelID, + ) + + // reassign ack.ForwardRelayerAddress to the registered payee address + ack = types.NewIncentivizedAcknowledgement(payeeAddr.String(), ibcmock.MockAcknowledgement.Acknowledgement(), true).Acknowledgement() + + // retrieve the payee acc balance and add the expected recv and ack fees + payeeAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), payeeAddr, sdk.DefaultBondDenom)) + expPayeeAccBalance = payeeAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.AckFee...) + + // retrieve the refund acc balance and add the expected timeout fees + refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) + expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.TimeoutFee...) + }, true, + func() { + // assert that the packet fees have been distributed + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + + payeeAddr := suite.chainA.SenderAccounts[2].SenderAccount.GetAddress() + payeeAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), payeeAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(payeeAccBalance)) + + refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expRefundAccBalance, sdk.NewCoins(refundAccBalance)) + }, }, { - "no op success without a packet fee", + "success: no op without a packet fee", func() { - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetSequence()) suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeesInEscrow(suite.chainA.GetContext(), packetID) ack = types.IncentivizedAcknowledgement{ AppAcknowledgement: ibcmock.MockAcknowledgement.Acknowledgement(), - ForwardRelayerAddress: suite.chainA.SenderAccount.GetAddress().String(), + ForwardRelayerAddress: "", }.Acknowledgement() - - expectedBalance = originalBalance }, true, - true, - }, - { - "ack wrong format", func() { - ack = []byte("unsupported acknowledgement format") - - expectedBalance = originalBalance + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) }, - false, - false, }, { - "channel is not fee not enabled, success", + "success: channel is not fee enabled", func() { suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) ack = ibcmock.MockAcknowledgement.Acknowledgement() - - expectedBalance = originalBalance }, - false, true, + func() {}, }, { "success: fee module is disabled, skip fee logic", func() { lockFeeModule(suite.chainA) - expLocked = true - - expectedBalance = originalBalance }, - false, true, + func() { + suite.Require().Equal(true, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + }, }, { - "fail on distribute receive fee (blocked address)", + "success: fail to distribute recv fee (blocked address), returned to refund account", func() { blockedAddr := suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() - ack = types.IncentivizedAcknowledgement{ - AppAcknowledgement: ibcmock.MockAcknowledgement.Acknowledgement(), - ForwardRelayerAddress: blockedAddr.String(), - }.Acknowledgement() + // reassign ack.ForwardRelayerAddress to a blocked address + ack = types.NewIncentivizedAcknowledgement(blockedAddr.String(), ibcmock.MockAcknowledgement.Acknowledgement(), true).Acknowledgement() + + // retrieve the relayer acc balance and add the expected ack fees + relayerAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom)) + expPayeeAccBalance = relayerAccBalance.Add(packetFee.Fee.AckFee...) - expectedRelayerBalance = packetFee.Fee.AckFee - expectedBalance = expectedBalance.Add(packetFee.Fee.RecvFee...) + // retrieve the refund acc balance and add the expected recv fees and timeout fees + refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) + expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.TimeoutFee...) }, - false, true, + func() { + // assert that the packet fees have been distributed + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + + relayerAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(relayerAccBalance)) + + refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expRefundAccBalance, sdk.NewCoins(refundAccBalance)) + }, }, { - "fail on no distribution by escrow account out of balance", + "fail: fee distribution fails and fee module is locked when escrow account does not have sufficient funds", func() { - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetSequence()) err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, suite.chainA.SenderAccount.GetAddress(), smallAmount) suite.Require().NoError(err) - - // expectedBalance and expectedRelayerBalance don't change - expectedBalance = originalBalance.Add(smallAmount...) - expectedRelayerBalance = sdk.NewCoins() - - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) - - expLocked = true }, - false, true, + func() { + suite.Require().Equal(true, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + }, + }, + { + "ack wrong format", + func() { + ack = []byte("unsupported acknowledgement format") + }, + false, + func() {}, + }, + { + "invalid registered payee address", + func() { + payeeAddr := "invalid-address" + suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + payeeAddr, + suite.path.EndpointA.ChannelID, + ) + }, + false, + func() {}, + }, + { + "application callback fails", + func() { + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnAcknowledgementPacket = func(_ sdk.Context, _ channeltypes.Packet, _ []byte, _ sdk.AccAddress) error { + return fmt.Errorf("mock fee app callback fails") + } + }, + false, + func() {}, }, } @@ -720,53 +797,30 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { tc := tc suite.Run(tc.name, func() { suite.SetupTest() - expLocked = false - suite.coordinator.Setup(suite.path) - packet := suite.CreateMockPacket() - - expectedRelayerBalance = sdk.Coins{} // reset - // set up module and callbacks - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) + relayerAddr = suite.chainA.SenderAccounts[0].SenderAccount.GetAddress() + refundAddr = suite.chainA.SenderAccounts[1].SenderAccount.GetAddress() - // escrow the packet fee - packetID := channeltypes.NewPacketId(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - packetFee = types.NewPacketFee( - types.Fee{ - RecvFee: defaultRecvFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, - }, - suite.chainA.SenderAccount.GetAddress().String(), - []string{}, - ) + packet := suite.CreateMockPacket() + packetID = channeltypes.NewPacketId(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + packetFee = types.NewPacketFee(types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee), refundAddr.String(), nil) suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) - err = suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, packetFee.Fee.Total()) - suite.Require().NoError(err) - relayerAddr := suite.chainB.SenderAccount.GetAddress() + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAddr, types.ModuleName, packetFee.Fee.Total()) + suite.Require().NoError(err) - // must be changed explicitly - ack = types.IncentivizedAcknowledgement{ - AppAcknowledgement: ibcmock.MockAcknowledgement.Acknowledgement(), - ForwardRelayerAddress: relayerAddr.String(), - }.Acknowledgement() + ack = types.NewIncentivizedAcknowledgement(relayerAddr.String(), ibcmock.MockAcknowledgement.Acknowledgement(), true).Acknowledgement() - // log original sender balance - // NOTE: balance is logged after escrowing tokens - originalBalance = sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + tc.malleate() // malleate mutates test data - // default to success case - expectedBalance = originalBalance.Add(packetFee.Fee.TimeoutFee[0]) + // retrieve module callbacks + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) + suite.Require().NoError(err) - // malleate test case - tc.malleate() + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) err = cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, ack, relayerAddr) @@ -776,103 +830,152 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { suite.Require().Error(err) } - suite.Require().Equal(expLocked, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) - - suite.Require().Equal( - expectedBalance, - sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), - ) - - relayerBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, ibctesting.TestCoin.Denom)) - if tc.expFeesDistributed { - // there should no longer be a fee in escrow for this packet - found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) - suite.Require().False(found) - } - - suite.Require().Equal( - expectedRelayerBalance, - relayerBalance, - ) + tc.expResult() }) } } func (suite *FeeTestSuite) TestOnTimeoutPacket() { var ( - relayerAddr sdk.AccAddress - packetFee types.PacketFee - originalBalance sdk.Coins - expectedBalance sdk.Coins - expLocked bool + packetID channeltypes.PacketId + packetFee types.PacketFee + refundAddr sdk.AccAddress + relayerAddr sdk.AccAddress + expRefundAccBalance sdk.Coins + expPayeeAccBalance sdk.Coins ) + testCases := []struct { - name string - malleate func() - expFeeDistributed bool + name string + malleate func() + expPass bool + expResult func() }{ { "success", - func() {}, + func() { + // retrieve the relayer acc balance and add the expected timeout fees + relayerAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom)) + expPayeeAccBalance = relayerAccBalance.Add(packetFee.Fee.TimeoutFee...) + + // retrieve the refund acc balance and add the expected recv and ack fees + refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) + expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.AckFee...) + }, true, + func() { + // assert that the packet fees have been distributed + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + + relayerAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(relayerAccBalance)) + + refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expRefundAccBalance, sdk.NewCoins(refundAccBalance)) + }, }, { - "fee not enabled", + "success: with registered payee address", func() { - suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + payeeAddr := suite.chainA.SenderAccounts[2].SenderAccount.GetAddress() + suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + payeeAddr.String(), + suite.path.EndpointA.ChannelID, + ) + + // retrieve the relayer acc balance and add the expected timeout fees + payeeAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), payeeAddr, sdk.DefaultBondDenom)) + expPayeeAccBalance = payeeAccBalance.Add(packetFee.Fee.TimeoutFee...) + + // retrieve the refund acc balance and add the expected recv and ack fees + refundAccBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom)) + expRefundAccBalance = refundAccBalance.Add(packetFee.Fee.RecvFee...).Add(packetFee.Fee.AckFee...) + }, + true, + func() { + // assert that the packet fees have been distributed + found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) + suite.Require().False(found) + + payeeAddr := suite.chainA.SenderAccounts[2].SenderAccount.GetAddress() + payeeAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), payeeAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expPayeeAccBalance, sdk.NewCoins(payeeAccBalance)) - expectedBalance = originalBalance + refundAccBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAddr, sdk.DefaultBondDenom) + suite.Require().Equal(expRefundAccBalance, sdk.NewCoins(refundAccBalance)) }, - false, }, { - "fee module is disabled, skip fee logic", + "success: channel is not fee enabled", + func() { + suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) + }, + true, + func() {}, + }, + { + "success: fee module is disabled, skip fee logic", func() { lockFeeModule(suite.chainA) - expLocked = true - - expectedBalance = originalBalance }, - false, + true, + func() { + suite.Require().Equal(true, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + }, }, { - "no op if identified packet fee doesn't exist", + "success: no op if identified packet fee doesn't exist", func() { - // delete packet fee - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetSequence()) suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeesInEscrow(suite.chainA.GetContext(), packetID) - - expectedBalance = originalBalance }, - false, + true, + func() {}, }, { - "distribute fee fails for timeout fee (blocked address)", + "success: fail to distribute timeout fee (blocked address), returned to refund account", func() { relayerAddr = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() - - expectedBalance = originalBalance. - Add(packetFee.Fee.RecvFee...). - Add(packetFee.Fee.AckFee...). - Add(packetFee.Fee.TimeoutFee...) }, - false, + true, + func() {}, }, { - "fail on no distribution by escrow account out of balance", + "fee distribution fails and fee module is locked when escrow account does not have sufficient funds", func() { - packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetSequence()) err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, suite.chainA.SenderAccount.GetAddress(), smallAmount) suite.Require().NoError(err) - - // expectedBalance don't change - expectedBalance = originalBalance.Add(smallAmount...) - - suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) - - expLocked = true + }, + true, + func() { + suite.Require().Equal(true, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) + }, + }, + { + "invalid registered payee address", + func() { + payeeAddr := "invalid-address" + suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress( + suite.chainA.GetContext(), + suite.chainA.SenderAccount.GetAddress().String(), + payeeAddr, + suite.path.EndpointA.ChannelID, + ) + }, + false, + func() {}, + }, + { + "application callback fails", + func() { + suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnTimeoutPacket = func(_ sdk.Context, _ channeltypes.Packet, _ sdk.AccAddress) error { + return fmt.Errorf("mock fee app callback fails") + } }, false, + func() {}, }, } @@ -880,69 +983,37 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { tc := tc suite.Run(tc.name, func() { suite.SetupTest() - expLocked = false - suite.coordinator.Setup(suite.path) - packet := suite.CreateMockPacket() - - // set up module and callbacks - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) - suite.Require().True(ok) - - packetID := channeltypes.NewPacketId(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) - // must be explicitly changed - relayerAddr = suite.chainB.SenderAccount.GetAddress() + relayerAddr = suite.chainA.SenderAccounts[0].SenderAccount.GetAddress() + refundAddr = suite.chainA.SenderAccounts[1].SenderAccount.GetAddress() - packetFee = types.NewPacketFee( - types.Fee{ - RecvFee: defaultRecvFee, - AckFee: defaultAckFee, - TimeoutFee: defaultTimeoutFee, - }, - suite.chainA.SenderAccount.GetAddress().String(), - []string{}, - ) + packet := suite.CreateMockPacket() + packetID = channeltypes.NewPacketId(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + packetFee = types.NewPacketFee(types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee), refundAddr.String(), nil) suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees([]types.PacketFee{packetFee})) - err = suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, packetFee.Fee.Total()) + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), types.ModuleName, packetFee.Fee.Total()) suite.Require().NoError(err) - // log original sender balance - // NOTE: balance is logged after escrowing tokens - originalBalance = sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) - - // default to success case - expectedBalance = originalBalance. - Add(packetFee.Fee.RecvFee[0]). - Add(packetFee.Fee.AckFee[0]) - - // malleate test case - tc.malleate() + tc.malleate() // malleate mutates test data - err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, relayerAddr) + // retrieve module callbacks + module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) suite.Require().NoError(err) - suite.Require().Equal(expLocked, suite.chainA.GetSimApp().IBCFeeKeeper.IsLocked(suite.chainA.GetContext())) - - suite.Require().Equal( - expectedBalance, - sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), - ) + cbs, ok := suite.chainA.App.GetIBCKeeper().Router.GetRoute(module) + suite.Require().True(ok) - relayerBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, ibctesting.TestCoin.Denom)) - if tc.expFeeDistributed { - // there should no longer be a fee in escrow for this packet - found := suite.chainA.GetSimApp().IBCFeeKeeper.HasFeesInEscrow(suite.chainA.GetContext(), packetID) - suite.Require().False(found) + err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, relayerAddr) - suite.Require().Equal(packetFee.Fee.TimeoutFee, relayerBalance) + if tc.expPass { + suite.Require().NoError(err) } else { - suite.Require().Empty(relayerBalance) + suite.Require().Error(err) } + + tc.expResult() }) } } From 6c034bc085e1701a7cbaa26476eb33e958b3a57c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 20 Jun 2022 10:07:52 +0200 Subject: [PATCH 169/275] add migration for base denoms with slashes to docs site (#1544) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- docs/.vuepress/config.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 7bb36d7c0f8..c0640213804 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -186,6 +186,11 @@ module.exports = { { title: "Migrations", children: [ + { + title: "Support transfer of coins whose base denom contains slashes", + directory: false, + path: "/migrations/support-denoms-with-slashes.html" + }, { title: "SDK v0.43 to IBC-Go v1", directory: false, From b9f3d958afaac162f7bf8f6294f8deeee97e22c8 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 20 Jun 2022 12:51:26 +0200 Subject: [PATCH 170/275] add migration of v3 to v4 to docs site (#1548) Co-authored-by: Carlos Rodriguez --- docs/.vuepress/config.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index c0640213804..db8621621bb 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -206,6 +206,11 @@ module.exports = { directory: false, path: "/migrations/v2-to-v3.html" }, + { + title: "IBC-Go v3 to v4", + directory: false, + path: "/migrations/v3-to-v4.html" + }, ] }, { From 44ca48d1c2d28fc8fe735954da3369dab07bab78 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 20 Jun 2022 15:53:23 +0200 Subject: [PATCH 171/275] add new release lines to dropdown menu (#1552) --- docs/.vuepress/config.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index db8621621bb..aaf668ffc97 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -47,6 +47,10 @@ module.exports = { "label": "v1.3.0", "key": "v1.3.0" }, + { + "label": "v1.5.0", + "key": "v1.5.0" + }, { "label": "v1.4.0", "key": "v1.4.0" @@ -63,9 +67,17 @@ module.exports = { "label": "v2.2.0", "key": "v2.2.0" }, + { + "label": "v2.3.0", + "key": "v2.3.0" + }, { "label": "v3.0.0", "key": "v3.0.0" + }, + { + "label": "v3.1.0", + "key": "v3.1.0" } ], topbar: { From 22a51ec35883343a97c7baf2319122ca3e06a9b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jun 2022 16:22:01 +0000 Subject: [PATCH 172/275] build(deps): bump github.com/stretchr/testify from 1.7.2 to 1.7.3 (#1559) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.2 to 1.7.3. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.7.2...v1.7.3) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 454eb5d7614..3ae20568bad 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.4.0 github.com/spf13/viper v1.12.0 - github.com/stretchr/testify v1.7.2 + github.com/stretchr/testify v1.7.3 github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd diff --git a/go.sum b/go.sum index 7da06990689..23afae791ad 100644 --- a/go.sum +++ b/go.sum @@ -960,8 +960,9 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -969,8 +970,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.7.3 h1:dAm0YRdRQlWojc3CrCRgPBzG5f941d0zvAKu7qY4e+I= +github.com/stretchr/testify v1.7.3/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= From 71d7480c923f4227453e8a80f51be01ae7ee845e Mon Sep 17 00:00:00 2001 From: Sean King Date: Wed, 22 Jun 2022 16:56:29 +0200 Subject: [PATCH 173/275] refactor: writing test case for module account incentivizing packet (#1397) * refactor: using SendCoins & writing test case for module account incentivizing packet * updating ModuleAccountAddrs helper fn and adding additional test for refunding to module acc * chore: changelog --- CHANGELOG.md | 1 + modules/apps/29-fee/keeper/escrow_test.go | 50 ++++++++++++++++--- modules/apps/29-fee/keeper/msg_server_test.go | 13 ++++- testing/simapp/app.go | 8 +++ 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e33c591d130..cb6e080f5f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees +* (testing/simapp) [\#1397](https://github.com/cosmos/ibc-go/pull/1397) Adding mock module to maccperms and adding check to ensure mock module is not a blocked account address. ### Features diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 7ccf87aa91b..0ab829877ea 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v3/testing/mock" "github.com/tendermint/tendermint/crypto/secp256k1" ) @@ -18,6 +19,7 @@ func (suite *KeeperTestSuite) TestDistributeFee() { refundAccBal sdk.Coin packetFee types.PacketFee packetFees []types.PacketFee + fee types.Fee ) testCases := []struct { @@ -27,7 +29,10 @@ func (suite *KeeperTestSuite) TestDistributeFee() { }{ { "success", - func() {}, + func() { + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + }, func() { // check if fees has been deleted packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) @@ -56,8 +61,30 @@ func (suite *KeeperTestSuite) TestDistributeFee() { suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(0)), balance) }, }, + { + "success: refund account is module account", + func() { + refundAcc = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(mock.ModuleName) + + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + + // fund mock account + err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), mock.ModuleName, packetFee.Fee.Total().Add(packetFee.Fee.Total()...)) + suite.Require().NoError(err) + }, + func() { + // check if the refund acc has been refunded the timeoutFee + expectedRefundAccBal := defaultTimeoutFee[0].Add(defaultTimeoutFee[0]) + balance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), refundAcc, sdk.DefaultBondDenom) + suite.Require().Equal(expectedRefundAccBal, balance) + }, + }, { "escrow account out of balance, fee module becomes locked - no distribution", func() { + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + // pass in an extra packet fee packetFees = append(packetFees, packetFee) }, @@ -76,6 +103,9 @@ func (suite *KeeperTestSuite) TestDistributeFee() { { "invalid forward address", func() { + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + forwardRelayer = "invalid address" }, func() { @@ -88,6 +118,9 @@ func (suite *KeeperTestSuite) TestDistributeFee() { { "invalid forward address: blocked address", func() { + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + forwardRelayer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() }, func() { @@ -100,6 +133,9 @@ func (suite *KeeperTestSuite) TestDistributeFee() { { "invalid receiver address: ack fee returned to sender", func() { + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + reverseRelayer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress() }, func() { @@ -112,6 +148,9 @@ func (suite *KeeperTestSuite) TestDistributeFee() { { "invalid refund address: no-op, timeout fee remains in escrow", func() { + packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) + packetFees = []types.PacketFee{packetFee, packetFee} + packetFees[0].RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() packetFees[1].RefundAddress = suite.chainA.GetSimApp().AccountKeeper.GetModuleAccount(suite.chainA.GetContext(), transfertypes.ModuleName).GetAddress().String() }, @@ -137,18 +176,15 @@ func (suite *KeeperTestSuite) TestDistributeFee() { refundAcc = suite.chainA.SenderAccount.GetAddress() packetID := channeltypes.NewPacketId(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, 1) - fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + fee = types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) - // escrow the packet fees & store the fees in state - packetFee = types.NewPacketFee(fee, refundAcc.String(), []string{}) - packetFees = []types.PacketFee{packetFee, packetFee} + tc.malleate() + // escrow the packet fees & store the fees in state suite.chainA.GetSimApp().IBCFeeKeeper.SetFeesInEscrow(suite.chainA.GetContext(), packetID, types.NewPacketFees(packetFees)) err := suite.chainA.GetSimApp().BankKeeper.SendCoinsFromAccountToModule(suite.chainA.GetContext(), refundAcc, types.ModuleName, packetFee.Fee.Total().Add(packetFee.Fee.Total()...)) suite.Require().NoError(err) - tc.malleate() - // fetch the account balances before fee distribution (forward, reverse, refund) forwardAccAddress, _ := sdk.AccAddressFromBech32(forwardRelayer) forwardRelayerBal = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), forwardAccAddress, sdk.DefaultBondDenom) diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 9a05f294c9d..cdcbe574d1c 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -3,6 +3,7 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" + disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -152,6 +153,7 @@ func (suite *KeeperTestSuite) TestPayPacketFee() { expEscrowBalance sdk.Coins expFeesInEscrow []types.PacketFee msg *types.MsgPayPacketFee + fee types.Fee ) testCases := []struct { @@ -182,6 +184,15 @@ func (suite *KeeperTestSuite) TestPayPacketFee() { }, true, }, + { + "refund account is module account", + func() { + msg.Signer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(disttypes.ModuleName).String() + expPacketFee := types.NewPacketFee(fee, msg.Signer, nil) + expFeesInEscrow = []types.PacketFee{expPacketFee} + }, + true, + }, { "fee module is locked", func() { @@ -241,7 +252,7 @@ func (suite *KeeperTestSuite) TestPayPacketFee() { suite.SetupTest() suite.coordinator.Setup(suite.path) // setup channel - fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) + fee = types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) msg = types.NewMsgPayPacketFee( fee, suite.path.EndpointA.ChannelConfig.PortID, diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 94d5640aa17..cb6c1cdccb3 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -43,6 +43,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/capability" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/ibc-go/v3/testing/mock" simappparams "github.com/cosmos/ibc-go/v3/testing/simapp/params" "github.com/cosmos/cosmos-sdk/x/crisis" @@ -164,6 +165,7 @@ var ( ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, ibcfeetypes.ModuleName: nil, icatypes.ModuleName: nil, + mock.ModuleName: nil, } ) @@ -654,6 +656,12 @@ func (app *SimApp) LoadHeight(height int64) error { func (app *SimApp) ModuleAccountAddrs() map[string]bool { modAccAddrs := make(map[string]bool) for acc := range maccPerms { + // do not add mock module to blocked addresses + // this is only used for testing + if acc == mock.ModuleName { + continue + } + modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true } From dbd0f774803fc08a545002da1e7474e357a63c86 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 23 Jun 2022 11:46:20 +0200 Subject: [PATCH 174/275] chore: ics29 fee payee event emission (#1568) * adding event emission for registered payees and counterparty payees in ics29 * updating naming of event emission funcs --- modules/apps/29-fee/keeper/events.go | 32 ++++++++++++++++++++++++ modules/apps/29-fee/keeper/msg_server.go | 4 +++ modules/apps/29-fee/types/events.go | 14 ++++++++--- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/modules/apps/29-fee/keeper/events.go b/modules/apps/29-fee/keeper/events.go index d60866e21d2..36207dbc5db 100644 --- a/modules/apps/29-fee/keeper/events.go +++ b/modules/apps/29-fee/keeper/events.go @@ -39,3 +39,35 @@ func EmitIncentivizedPacketEvent(ctx sdk.Context, packetID channeltypes.PacketId ), ) } + +// EmitRegisterPayeeEvent emits an event containing information of a registered payee for a relayer on a particular channel +func EmitRegisterPayeeEvent(ctx sdk.Context, relayer, payee, channelID string) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeRegisterPayee, + sdk.NewAttribute(types.AttributeKeyRelayer, relayer), + sdk.NewAttribute(types.AttributeKeyPayee, payee), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) +} + +// EmitRegisterCounterpartyPayeeEvent emits an event containing information of a registered counterparty payee for a relayer on a particular channel +func EmitRegisterCounterpartyPayeeEvent(ctx sdk.Context, relayer, counterpartyPayee, channelID string) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeRegisterCounterpartyPayee, + sdk.NewAttribute(types.AttributeKeyRelayer, relayer), + sdk.NewAttribute(types.AttributeKeyCounterpartyPayee, counterpartyPayee), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) +} diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index fe7af407d2f..1acb153594f 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -33,6 +33,8 @@ func (k Keeper) RegisterPayee(goCtx context.Context, msg *types.MsgRegisterPayee k.Logger(ctx).Info("registering payee address for relayer", "relayer", msg.Relayer, "payee", msg.Payee, "channel", msg.ChannelId) + EmitRegisterPayeeEvent(ctx, msg.Relayer, msg.Payee, msg.ChannelId) + return &types.MsgRegisterPayeeResponse{}, nil } @@ -57,6 +59,8 @@ func (k Keeper) RegisterCounterpartyPayee(goCtx context.Context, msg *types.MsgR k.Logger(ctx).Info("registering counterparty payee for relayer", "relayer", msg.Relayer, "counterparty payee", msg.CounterpartyPayee, "channel", msg.ChannelId) + EmitRegisterCounterpartyPayeeEvent(ctx, msg.Relayer, msg.CounterpartyPayee, msg.ChannelId) + return &types.MsgRegisterCounterpartyPayeeResponse{}, nil } diff --git a/modules/apps/29-fee/types/events.go b/modules/apps/29-fee/types/events.go index cac882d98d3..cffca5dabdd 100644 --- a/modules/apps/29-fee/types/events.go +++ b/modules/apps/29-fee/types/events.go @@ -2,9 +2,15 @@ package types // 29-fee events const ( - EventTypeIncentivizedPacket = "incentivized_ibc_packet" + EventTypeIncentivizedPacket = "incentivized_ibc_packet" + EventTypeRegisterPayee = "register_payee" + EventTypeRegisterCounterpartyPayee = "register_counterparty_payee" - AttributeKeyRecvFee = "recv_fee" - AttributeKeyAckFee = "ack_fee" - AttributeKeyTimeoutFee = "timeout_fee" + AttributeKeyRecvFee = "recv_fee" + AttributeKeyAckFee = "ack_fee" + AttributeKeyTimeoutFee = "timeout_fee" + AttributeKeyChannelID = "channel_id" + AttributeKeyRelayer = "relayer" + AttributeKeyPayee = "payee" + AttributeKeyCounterpartyPayee = "counterparty_payee" ) From 8ffa912d32ff6adbffc5c87aac2f1a26f54ea42b Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 23 Jun 2022 16:31:01 +0200 Subject: [PATCH 175/275] chore: allow ics27 to select and return default JSON encoded metadata (#1550) * adding distribution logic with new registered payees * updating ack test cases * removing commented out test * adding additional testcase to TestOnAcknowledgementPacket * cleaning up distribution logic and adapting tests * updating timeout test cases * updating timeout logic and adding application callback failure test cases * Apply suggestions from code review Co-authored-by: Charly * WIP handling empty version string for ics27 * updating testcases * adding test with auth module modifying channel version * adding inline comments re. ignored channel version from auth module * updating with deduplication suggestion Co-authored-by: Cian Hatton Co-authored-by: Charly --- .../controller/ibc_middleware.go | 3 +- .../controller/ibc_middleware_test.go | 26 ++++++++--------- .../controller/keeper/handshake.go | 29 ++++++++++++------- .../controller/keeper/handshake_test.go | 22 ++++++++++++-- .../27-interchain-accounts/types/metadata.go | 16 +++++++--- 5 files changed, 65 insertions(+), 31 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index b0b6bd6767c..b7c65874bfa 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -50,7 +50,8 @@ func (im IBCMiddleware) OnChanOpenInit( return "", types.ErrControllerSubModuleDisabled } - if err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version); err != nil { + version, err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) + if err != nil { return "", err } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 1c3660c54b5..7656c665333 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -130,6 +130,18 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { { "success", func() {}, true, }, + { + "ICA auth module modification of channel version is ignored", func() { + // NOTE: explicitly modify the channel version via the auth module callback, + // ensuring the expected JSON encoded metadata is not modified upon return + suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, + portID, channelID string, chanCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, version string, + ) (string, error) { + return "invalid-version", nil + } + }, true, + }, { "controller submodule disabled", func() { suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) @@ -200,19 +212,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { ) if tc.expPass { - expMetadata := icatypes.NewMetadata( - icatypes.Version, - path.EndpointA.ConnectionID, - path.EndpointB.ConnectionID, - "", - icatypes.EncodingProtobuf, - icatypes.TxTypeSDKMultiMsg, - ) - - expBytes, err := icatypes.ModuleCdc.MarshalJSON(&expMetadata) - suite.Require().NoError(err) - - suite.Require().Equal(version, string(expBytes)) + suite.Require().Equal(icatypes.NewDefaultMetadataString(path.EndpointA.ConnectionID, path.EndpointB.ConnectionID), version) suite.Require().NoError(err) } else { suite.Require().Error(err) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go index 6b84fb554ca..c9f72ae3380 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -28,26 +28,35 @@ func (k Keeper) OnChanOpenInit( chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { +) (string, error) { if order != channeltypes.ORDERED { - return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) + return "", sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order) } if !strings.HasPrefix(portID, icatypes.PortPrefix) { - return sdkerrors.Wrapf(icatypes.ErrInvalidControllerPort, "expected %s{owner-account-address}, got %s", icatypes.PortPrefix, portID) + return "", sdkerrors.Wrapf(icatypes.ErrInvalidControllerPort, "expected %s{owner-account-address}, got %s", icatypes.PortPrefix, portID) } if counterparty.PortId != icatypes.PortID { - return sdkerrors.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.PortID, counterparty.PortId) + return "", sdkerrors.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.PortID, counterparty.PortId) } var metadata icatypes.Metadata - if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(version), &metadata); err != nil { - return sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata") + if strings.TrimSpace(version) == "" { + connection, err := k.channelKeeper.GetConnection(ctx, connectionHops[0]) + if err != nil { + return "", err + } + + metadata = icatypes.NewDefaultMetadata(connectionHops[0], connection.GetCounterparty().GetConnectionID()) + } else { + if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(version), &metadata); err != nil { + return "", sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata") + } } if err := icatypes.ValidateControllerMetadata(ctx, k.channelKeeper, connectionHops, metadata); err != nil { - return err + return "", err } activeChannelID, found := k.GetActiveChannelID(ctx, connectionHops[0], portID) @@ -58,15 +67,15 @@ func (k Keeper) OnChanOpenInit( } if channel.State == channeltypes.OPEN { - return sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID) + return "", sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID) } if !icatypes.IsPreviousMetadataEqual(channel.Version, metadata) { - return sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version") + return "", sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version") } } - return nil + return string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)), nil } // OnChanOpenAck sets the active channel for the interchain account/owner pair diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go index f2104e2032d..b0cb9c3a125 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -30,7 +30,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { true, }, { - "success - previous active channel closed", + "success: previous active channel closed", func() { suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) @@ -47,6 +47,13 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { }, true, }, + { + "success: empty channel version returns default metadata JSON string", + func() { + channel.Version = "" + }, + true, + }, { "invalid metadata - previous metadata is different", func() { @@ -138,6 +145,14 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { }, false, }, + { + "connection not found with default empty channel version", + func() { + channel.ConnectionHops = []string{"connection-10"} + channel.Version = "" + }, + false, + }, { "invalid controller connection ID", func() { @@ -214,7 +229,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { path.EndpointA.ChannelConfig.PortID = portID // default values - metadata = icatypes.NewMetadata(icatypes.Version, ibctesting.FirstConnectionID, ibctesting.FirstConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg) + metadata = icatypes.NewMetadata(icatypes.Version, path.EndpointA.ConnectionID, path.EndpointB.ConnectionID, "", icatypes.EncodingProtobuf, icatypes.TxTypeSDKMultiMsg) versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata) suite.Require().NoError(err) @@ -232,12 +247,13 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { tc.malleate() // malleate mutates test data - err = suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), + version, err := suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version, ) if tc.expPass { suite.Require().NoError(err) + suite.Require().Equal(string(versionBytes), version) } else { suite.Require().Error(err) } diff --git a/modules/apps/27-interchain-accounts/types/metadata.go b/modules/apps/27-interchain-accounts/types/metadata.go index 15f27314d47..dd14c4788ec 100644 --- a/modules/apps/27-interchain-accounts/types/metadata.go +++ b/modules/apps/27-interchain-accounts/types/metadata.go @@ -27,17 +27,25 @@ func NewMetadata(version, controllerConnectionID, hostConnectionID, accAddress, } } -// NewDefaultMetadataString creates and returns a new JSON encoded version string containing the default ICS27 Metadata values +// NewDefaultMetadata creates and returns a new ICS27 Metadata instance containing the default ICS27 Metadata values // with the provided controller and host connection identifiers -func NewDefaultMetadataString(controllerConnectionID, hostConnectionID string) string { +func NewDefaultMetadata(connectionConnectionID, hostConnectionID string) Metadata { metadata := Metadata{ - Version: Version, - ControllerConnectionId: controllerConnectionID, + ControllerConnectionId: connectionConnectionID, HostConnectionId: hostConnectionID, Encoding: EncodingProtobuf, TxType: TxTypeSDKMultiMsg, + Version: Version, } + return metadata +} + +// NewDefaultMetadataString creates and returns a new JSON encoded version string containing the default ICS27 Metadata values +// with the provided controller and host connection identifiers +func NewDefaultMetadataString(controllerConnectionID, hostConnectionID string) string { + metadata := NewDefaultMetadata(controllerConnectionID, hostConnectionID) + return string(ModuleCdc.MustMarshalJSON(&metadata)) } From 5467300423eeadae68d0ac41db20c4b8c5315970 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 23 Jun 2022 16:34:00 +0200 Subject: [PATCH 176/275] docs: ics29 middleware usage for app devs (#1567) * adding integration doc for app wiring configuration * adjusting wording * updating grammar * updating vuepress config * adding explicit comment regarding intended audience of cosmos sdk devs * adding explicit reference to app.go in transfer and ica examples * fixing indentation in vuepress config.js * fixing more indentation --- docs/.vuepress/config.js | 25 ++++--- docs/middleware/ics29-fee/integration.md | 85 ++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 docs/middleware/ics29-fee/integration.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index aaf668ffc97..663a40a093b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -145,9 +145,9 @@ module.exports = { path: "/apps", children: [ { - title: "Overview", - directory: false, - path: "/apps/interchain-accounts/overview.html" + title: "Overview", + directory: false, + path: "/apps/interchain-accounts/overview.html" }, { title: "Authentication Modules", @@ -160,9 +160,9 @@ module.exports = { path: "/apps/interchain-accounts/active-channels.html" }, { - title: "Integration", - directory: false, - path: "/apps/interchain-accounts/integration.html" + title: "Integration", + directory: false, + path: "/apps/interchain-accounts/integration.html" }, { title: "Parameters", @@ -187,11 +187,16 @@ module.exports = { path: "/middleware", children: [ { - title: "Overview", - directory: false, - path: "/middleware/ics29-fee/overview.html" + title: "Overview", + directory: false, + path: "/middleware/ics29-fee/overview.html" }, - ] + { + title: "Integration", + directory: false, + path: "/middleware/ics29-fee/integration.html" + }, + ] }, ] }, diff --git a/docs/middleware/ics29-fee/integration.md b/docs/middleware/ics29-fee/integration.md new file mode 100644 index 00000000000..f1d0158e702 --- /dev/null +++ b/docs/middleware/ics29-fee/integration.md @@ -0,0 +1,85 @@ + + +# Integration + +Learn how to configure the Fee Middleware module with IBC applications. The following document is intended for developers building on top of the Cosmos SDK and only applies for Cosmos SDK chains. {synopsis} + +## Pre-requisite Readings + +* [IBC middleware development](../../ibc/middleware/develop.md) {prereq} +* [IBC middleware integration](../../ibc/middleware/integration.md) {prereq} + +The Fee Middleware module, as the name suggests, plays the role of an IBC middleware and as such must be configured by chain developers to route and handle IBC messages correctly. +For Cosmos SDK chains this setup is done via the `app/app.go` file, where modules are constructed and configured in order to bootstrap the blockchain application. + +## Configuring an application stack with Fee Middleware + +As mentioned in [IBC middleware development](../../ibc/middleware/develop.md) an application stack may be composed of many or no middlewares that nest a base application. +These layers form the complete set of application logic that enable developers to build composable and flexible IBC application stacks. +For example, an application stack may be just a single base application like `transfer`, however, the same application stack composed with `29-fee` will nest the `transfer` base application +by wrapping it with the Fee Middleware module. + + +### Transfer + +See below for an example of how to create an application stack using `transfer` and `29-fee`. +The following `transferStack` is configured in `app/app.go` and added to the IBC `Router`. +The in-line comments describe the execution flow of packets between the application stack and IBC core. + +```go +// Create Transfer Stack +// SendPacket, since it is originating from the application to core IBC: +// transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket + +// RecvPacket, message that originates from core IBC and goes down to app, the flow is the other way +// channel.RecvPacket -> fee.OnRecvPacket -> transfer.OnRecvPacket + +// transfer stack contains (from top to bottom): +// - IBC Fee Middleware +// - Transfer + +// create IBC module from bottom to top of stack +var transferStack porttypes.IBCModule +transferStack = transfer.NewIBCModule(app.TransferKeeper) +transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) + +// Add transfer stack to IBC Router +ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) +``` + +### Interchain Accounts + +See below for an example of how to create an application stack using `27-interchain-accounts` and `29-fee`. +The following `icaControllerStack` and `icaHostStack` are configured in `app/app.go` and added to the IBC `Router` with the associated authentication module. +The in-line comments describe the execution flow of packets between the application stack and IBC core. + +```go +// Create Interchain Accounts Stack +// SendPacket, since it is originating from the application to core IBC: +// icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket + +// initialize ICA module with mock module as the authentication module on the controller side +var icaControllerStack porttypes.IBCModule +icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewMockIBCApp("", scopedICAMockKeeper)) +app.ICAAuthModule = icaControllerStack.(ibcmock.IBCModule) +icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) +icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) + +// RecvPacket, message that originates from core IBC and goes down to app, the flow is: +// channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket + +var icaHostStack porttypes.IBCModule +icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) +icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) + +// Add authentication module, controller and host to IBC router +ibcRouter. + // the ICA Controller middleware needs to be explicitly added to the IBC Router because the + // ICA controller module owns the port capability for ICA. The ICA authentication module + // owns the channel capability. + AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) + AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). + AddRoute(icahosttypes.SubModuleName, icaHostStack). +``` \ No newline at end of file From 6ff53007a1f0caf1d9b1286b82c337f8926d15e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jun 2022 14:56:03 +0000 Subject: [PATCH 177/275] build(deps): bump technote-space/get-diff-action from 6.0.1 to 6.1.0 (#1560) Bumps [technote-space/get-diff-action](https://github.com/technote-space/get-diff-action) from 6.0.1 to 6.1.0. - [Release notes](https://github.com/technote-space/get-diff-action/releases) - [Changelog](https://github.com/technote-space/get-diff-action/blob/main/.releasegarc) - [Commits](https://github.com/technote-space/get-diff-action/compare/v6.0.1...v6.1.0) --- updated-dependencies: - dependency-name: technote-space/get-diff-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/test.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d6f09b1ef64..aaf7c7b8db3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6.1.0 with: PATTERNS: | **/**.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index be50bf0bdf1..d6e00030df0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,7 +41,7 @@ jobs: - uses: actions/setup-go@v3 with: go-version: 1.17 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6.1.0 id: git_diff with: PATTERNS: | @@ -96,7 +96,7 @@ jobs: - uses: actions/setup-go@v3 with: go-version: 1.17 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6.1.0 with: PATTERNS: | **/**.go @@ -120,7 +120,7 @@ jobs: needs: tests steps: - uses: actions/checkout@v3 - - uses: technote-space/get-diff-action@v6.0.1 + - uses: technote-space/get-diff-action@v6.1.0 with: PATTERNS: | **/**.go From c9cd8f9152a13a1e91720fea32f399cb7ece57ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jun 2022 15:10:04 +0000 Subject: [PATCH 178/275] build(deps): bump github.com/spf13/cobra from 1.4.0 to 1.5.0 (#1562) Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/spf13/cobra/releases) - [Commits](https://github.com/spf13/cobra/compare/v1.4.0...v1.5.0) --- updated-dependencies: - dependency-name: github.com/spf13/cobra dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Damian Nolan --- go.mod | 2 +- go.sum | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 3ae20568bad..14dfad3dfc5 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.3.1 github.com/spf13/cast v1.5.0 - github.com/spf13/cobra v1.4.0 + github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.12.0 github.com/stretchr/testify v1.7.3 github.com/tendermint/tendermint v0.34.19 diff --git a/go.sum b/go.sum index 23afae791ad..90807d0565b 100644 --- a/go.sum +++ b/go.sum @@ -247,6 +247,7 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= @@ -934,8 +935,9 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= From 9dc34921988eddb545731f7dcb7999eca3f9bf3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jun 2022 15:18:12 +0000 Subject: [PATCH 179/275] build(deps): bump github.com/stretchr/testify from 1.7.3 to 1.7.4 (#1561) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.3 to 1.7.4. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.7.3...v1.7.4) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 14dfad3dfc5..c2a37743dd3 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.12.0 - github.com/stretchr/testify v1.7.3 + github.com/stretchr/testify v1.7.4 github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd diff --git a/go.sum b/go.sum index 90807d0565b..94a11519f20 100644 --- a/go.sum +++ b/go.sum @@ -972,8 +972,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.3 h1:dAm0YRdRQlWojc3CrCRgPBzG5f941d0zvAKu7qY4e+I= -github.com/stretchr/testify v1.7.3/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM= +github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= From a7d609036c9810a973655089001681baae97061d Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 23 Jun 2022 21:27:45 +0200 Subject: [PATCH 180/275] docs: move ics20 docs from spec to top level docs (#1554) * move files from apps/transfer/spec to docs/apps/transfer * update transfer docs * docs: update content and rename transfer doc files * fix broken link * fix typo in link Co-authored-by: Carlos Rodriguez --- docs/.vuepress/config.js | 42 ++++++++++++++++ .../apps/transfer/events.md | 11 ++-- docs/apps/transfer/messages.md | 36 +++++++++++++ .../apps/transfer/metrics.md | 2 +- .../apps/transfer/overview.md | 50 +++++++++++-------- docs/apps/transfer/params.md | 24 +++++++++ .../apps/transfer/state-transitions.md | 18 +++---- .../apps/transfer/state.md | 2 +- modules/apps/transfer/spec/04_messages.md | 40 --------------- modules/apps/transfer/spec/07_params.md | 28 ----------- modules/apps/transfer/spec/README.md | 24 --------- 11 files changed, 147 insertions(+), 130 deletions(-) rename modules/apps/transfer/spec/05_events.md => docs/apps/transfer/events.md (84%) create mode 100644 docs/apps/transfer/messages.md rename modules/apps/transfer/spec/06_metrics.md => docs/apps/transfer/metrics.md (86%) rename modules/apps/transfer/spec/01_concepts.md => docs/apps/transfer/overview.md (72%) create mode 100644 docs/apps/transfer/params.md rename modules/apps/transfer/spec/03_state_transitions.md => docs/apps/transfer/state-transitions.md (78%) rename modules/apps/transfer/spec/02_state.md => docs/apps/transfer/state.md (57%) delete mode 100644 modules/apps/transfer/spec/04_messages.md delete mode 100644 modules/apps/transfer/spec/07_params.md delete mode 100644 modules/apps/transfer/spec/README.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 663a40a093b..5183df990c1 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -176,6 +176,48 @@ module.exports = { }, ] }, + { + title: "Transfer", + directory: true, + path: "/apps", + children: [ + { + title: "Overview", + directory: false, + path: "/apps/transfer/overview.html" + }, + { + title: "State", + directory: false, + path: "/apps/transfer/state.html" + }, + { + title: "State Transitions", + directory: false, + path: "/apps/transfer/state-transitions.html" + }, + { + title: "Messages", + directory: false, + path: "/apps/transfer/messages.html" + }, + { + title: "Events", + directory: false, + path: "/apps/transfer/events.html" + }, + { + title: "Metrics", + directory: false, + path: "/apps/transfer/metrics.html" + }, + { + title: "Params", + directory: false, + path: "/apps/transfer/params.html" + }, + ] + }, ] }, { diff --git a/modules/apps/transfer/spec/05_events.md b/docs/apps/transfer/events.md similarity index 84% rename from modules/apps/transfer/spec/05_events.md rename to docs/apps/transfer/events.md index 51b49da4602..a538d07d068 100644 --- a/modules/apps/transfer/spec/05_events.md +++ b/docs/apps/transfer/events.md @@ -4,7 +4,7 @@ order: 5 # Events -## MsgTransfer +## `MsgTransfer` | Type | Attribute Key | Attribute Value | |--------------|---------------|-----------------| @@ -13,28 +13,31 @@ order: 5 | message | action | transfer | | message | module | transfer | -## OnRecvPacket callback +## `OnRecvPacket` callback | Type | Attribute Key | Attribute Value | |-----------------------|---------------|-----------------| | fungible_token_packet | module | transfer | +| fungible_token_packet | sender | {sender} | | fungible_token_packet | receiver | {receiver} | | fungible_token_packet | denom | {denom} | | fungible_token_packet | amount | {amount} | | fungible_token_packet | success | {ackSuccess} | | denomination_trace | trace_hash | {hex_hash} | -## OnAcknowledgePacket callback +## `OnAcknowledgePacket` callback | Type | Attribute Key | Attribute Value | |-----------------------|-----------------|-------------------| | fungible_token_packet | module | transfer | +| fungible_token_packet | sender | {sender} | | fungible_token_packet | receiver | {receiver} | | fungible_token_packet | denom | {denom} | | fungible_token_packet | amount | {amount} | +| fungible_token_packet | acknowledgement | {ack.String()} | | fungible_token_packet | success | error | {ack.Response} | -## OnTimeoutPacket callback +## `OnTimeoutPacket` callback | Type | Attribute Key | Attribute Value | |-----------------------|-----------------|-----------------| diff --git a/docs/apps/transfer/messages.md b/docs/apps/transfer/messages.md new file mode 100644 index 00000000000..7cb61402e04 --- /dev/null +++ b/docs/apps/transfer/messages.md @@ -0,0 +1,36 @@ + + +# Messages + +## `MsgTransfer` + +A fungible token cross chain transfer is achieved by using the `MsgTransfer`: + +```go +type MsgTransfer struct { + SourcePort string + SourceChannel string + Token sdk.Coin + Sender string + Receiver string + TimeoutHeight ibcexported.Height + TimeoutTimestamp uint64 +} +``` + +This message is expected to fail if: + +- `SourcePort` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). +- `SourceChannel` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). +- `Token` is invalid (denom is invalid or amount is negative) + - `Token.Amount` is not positive. + - `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](../../../docs/architecture/adr-001-coin-source-tracing.md). +- `Sender` is empty. +- `Receiver` is empty. +- `TimeoutHeight` and `TimeoutTimestamp` are both zero. + +This message will send a fungible token to the counterparty chain represented by the counterparty Channel End connected to the Channel End with the identifiers `SourcePort` and `SourceChannel`. + +The denomination provided for transfer should correspond to the same denomination represented on this chain. The prefixes will be added as necessary upon by the receiving chain. diff --git a/modules/apps/transfer/spec/06_metrics.md b/docs/apps/transfer/metrics.md similarity index 86% rename from modules/apps/transfer/spec/06_metrics.md rename to docs/apps/transfer/metrics.md index 3d2ce5000e6..e9e3086ba1d 100644 --- a/modules/apps/transfer/spec/06_metrics.md +++ b/docs/apps/transfer/metrics.md @@ -4,7 +4,7 @@ order: 6 # Metrics -The transfer IBC application module exposes the following set of [metrics](https://github.com/cosmos/cosmos-sdk/blob/master/docs/core/telemetry.md). +The IBC transfer application module exposes the following set of [metrics](https://github.com/cosmos/cosmos-sdk/blob/main/docs/core/telemetry.md). | Metric | Description | Unit | Type | |:--------------------------------|:------------------------------------------------------------------------------------------|:----------------|:--------| diff --git a/modules/apps/transfer/spec/01_concepts.md b/docs/apps/transfer/overview.md similarity index 72% rename from modules/apps/transfer/spec/01_concepts.md rename to docs/apps/transfer/overview.md index e70185fcae5..8b83b2c789b 100644 --- a/modules/apps/transfer/spec/01_concepts.md +++ b/docs/apps/transfer/overview.md @@ -2,19 +2,27 @@ order: 1 --> -# Concepts +# Overview -## Acknowledgements +Learn about what the token Transfer module is {synopsis} + +## What is the Transfer module? + +Transfer is the Cosmos SDK implementation of the [ICS-20](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer) protocol, which enables cross-chain fungible token transfers. + +## Concepts + +### Acknowledgements ICS20 uses the recommended acknowledgement format as specified by [ICS 04](https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope). A successful receive of a transfer packet will result in a Result Acknowledgement being written -with the value `[]byte(byte(1))` in the `Response` field. +with the value `[]byte{byte(1)}` in the `Response` field. An unsuccessful receive of a transfer packet will result in an Error Acknowledgement being written with the error message in the `Response` field. -## Denomination Trace +### Denomination trace The denomination trace corresponds to the information that allows a token to be traced back to its origin chain. It contains a sequence of port and channel identifiers ordered from the most recent to @@ -31,14 +39,13 @@ acting as the "source zone". When the token is sent back to the chain it previou prefix is removed. This is a backwards movement in the token's timeline and the sender chain is acting as the "sink zone". -It is strongly recommended to read the full details of [ADR 001: Coin Source Tracing](https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-001-coin-source-tracing.md) to understand the implications and context of the IBC token representations. +It is strongly recommended to read the full details of [ADR 001: Coin Source Tracing](../../architecture/adr-001-coin-source-tracing.md) to understand the implications and context of the IBC token representations. -### UX suggestions for clients +## UX suggestions for clients -For clients (wallets, exchanges, applications, block explorers, etc) that want to display the source of the token, it is recommended to use the following -alternatives for each of the cases below: +For clients (wallets, exchanges, applications, block explorers, etc) that want to display the source of the token, it is recommended to use the following alternatives for each of the cases below: -#### Direct connection +### Direct connection If the denomination trace contains a single identifier prefix pair (as in the example above), then the easiest way to retrieve the chain and light client identifier is to map the trace information @@ -53,15 +60,15 @@ A general pseudo algorithm would look like the following: token. 3. Query the client state using the identifiers pair. Note that this query will return a `"Not Found"` response if the current chain is not connected to this channel. -4. Retrieve the the client identifier or chain identifier from the client state (eg: on +4. Retrieve the client identifier or chain identifier from the client state (eg: on Tendermint clients) and store it locally. -Using the gRPC gataway client service the steps above would be, with a given IBC token `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` stored on `chainB`: +Using the gRPC gateway client service the steps above would be, with a given IBC token `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` stored on `chainB`: -1. `GET /ibc_transfer/v1beta1/denom_traces/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` -> `{"path": "transfer/channelToA", "base_denom": "uatom"}` -2. `GET /ibc/channel/v1beta1/channels/channelToA/ports/transfer/client_state"` -> `{"client_id": "clientA", "chain-id": "chainA", ...}` -3. `GET /ibc/channel/v1beta1/channels/channelToA/ports/transfer"` -> `{"channel_id": "channelToA", port_id": "transfer", counterparty: {"channel_id": "channelToB", port_id": "transfer"}, ...}` -4. `GET /ibc/channel/v1beta1/channels/channelToB/ports/transfer/client_state" -> {"client_id": "clientB", "chain-id": "chainB", ...}` +1. `GET /ibc/apps/transfer/v1/denom_traces/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` -> `{"path": "transfer/channelToA", "base_denom": "uatom"}` +2. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer/client_state"` -> `{"client_id": "clientA", "chain-id": "chainA", ...}` +3. `GET /ibc/apps/transfer/v1/channels/channelToA/ports/transfer"` -> `{"channel_id": "channelToA", port_id": "transfer", counterparty: {"channel_id": "channelToB", port_id": "transfer"}, ...}` +4. `GET /ibc/apps/transfer/v1/channels/channelToB/ports/transfer/client_state" -> {"client_id": "clientB", "chain-id": "chainB", ...}` Then, the token transfer chain path for the `uatom` denomination would be: `chainA` -> `chainB`. @@ -69,9 +76,9 @@ Then, the token transfer chain path for the `uatom` denomination would be: `chai The multiple channel hops case applies when the token has passed through multiple chains between the original source and final destination chains. -The IBC protocol doesn't know the topology of the overall network (i.e connections between chains and identifier names between them). For this reason, in the the multiple hops case, a particular chain in the timeline of the individual transfers can't query the chain and client identifiers of the other chains. +The IBC protocol doesn't know the topology of the overall network (i.e connections between chains and identifier names between them). For this reason, in the multiple hops case, a particular chain in the timeline of the individual transfers can't query the chain and client identifiers of the other chains. -Take for example the following sequence of transfers `A -> B -> C` for an IBC token, with a final prefix path (trace info) of `transfer/channelChainC/transfer/channelChainB`. What the paragraph above means is that is that even in the case that chain `C` is directly connected to chain `A`, querying the port and channel identifiers that chain `B` uses to connect to chain `A` (eg: `transfer/channelChainA`) can be completely different from the one that chain `C` uses to connect to chain `A` (eg: `transfer/channelToChainA`). +Take for example the following sequence of transfers `A -> B -> C` for an IBC token, with a final prefix path (trace info) of `transfer/channelChainC/transfer/channelChainB`. What the paragraph above means is that even in the case that chain `C` is directly connected to chain `A`, querying the port and channel identifiers that chain `B` uses to connect to chain `A` (eg: `transfer/channelChainA`) can be completely different from the one that chain `C` uses to connect to chain `A` (eg: `transfer/channelToChainA`). Thus the proposed solution for clients that the IBC team recommends are the following: @@ -94,9 +101,9 @@ Thus the proposed solution for clients that the IBC team recommends are the foll The only viable alternative for clients (at the time of writing) to tokens with multiple connection hops, is to connect to all chains directly and perform relevant queries to each of them in the sequence. ::: -## Locked Funds +## Locked funds -In some [exceptional cases](https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-026-ibc-client-recovery-mechanisms.md#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred. +In some [exceptional cases](../../architecture/adr-026-ibc-client-recovery-mechanisms.md#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred. To mitigate this, a client update governance proposal can be submitted to update the frozen client with a new valid header. Once the proposal passes the client state will be unfrozen and the funds @@ -104,14 +111,13 @@ from the associated channels will then be unlocked. This mechanism only applies allow updates via governance, such as Tendermint clients. In addition to this, it's important to mention that a token must be sent back along the exact route -that it took originally un order to return it to its original form on the source chain (eg: the +that it took originally in order to return it to its original form on the source chain (eg: the Cosmos Hub for the `uatom`). Sending a token back to the same chain across a different channel will **not** move the token back across its timeline. If a channel in the chain history closes before the token can be sent back across that channel, then the token will not be returnable to its original form. - -## Security Considerations +## Security considerations For safety, no other module must be capable of minting tokens with the `ibc/` prefix. The IBC transfer module needs a subset of the denomination space that only it can create tokens in. diff --git a/docs/apps/transfer/params.md b/docs/apps/transfer/params.md new file mode 100644 index 00000000000..e2e74305311 --- /dev/null +++ b/docs/apps/transfer/params.md @@ -0,0 +1,24 @@ + + +# Parameters + +The IBC transfer application module contains the following parameters: + +| Key | Type | Default Value | +|------------------|------|---------------| +| `SendEnabled` | bool | `true` | +| `ReceiveEnabled` | bool | `true` | + +## `SendEnabled` + +The transfers enabled parameter controls send cross-chain transfer capabilities for all fungible tokens. + +To prevent a single token from being transferred from the chain, set the `SendEnabled` parameter to `true` and then set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/main/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. + +## `ReceiveEnabled` + +The transfers enabled parameter controls receive cross-chain transfer capabilities for all fungible tokens. + +To prevent a single token from being transferred to the chain, set the `ReceiveEnabled` parameter to `true` and then set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/main/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. diff --git a/modules/apps/transfer/spec/03_state_transitions.md b/docs/apps/transfer/state-transitions.md similarity index 78% rename from modules/apps/transfer/spec/03_state_transitions.md rename to docs/apps/transfer/state-transitions.md index 9090da54343..86f7deab2d1 100644 --- a/modules/apps/transfer/spec/03_state_transitions.md +++ b/docs/apps/transfer/state-transitions.md @@ -2,27 +2,25 @@ order: 3 --> -# State Transitions +# State transitions -## Send Fungible Tokens +## Send fungible tokens -A successful fungible token send has two state transitions depending if the -transfer is a movement forward or backwards in the token's timeline: +A successful fungible token send has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: 1. Sender chain is the source chain, *i.e* a transfer to any chain other than the one it was previously received from is a movement forwards in the token's timeline. This results in the following state transitions: -- The coins are transferred to an escrow address (i.e locked) on the sender chain +- The coins are transferred to an escrow address (i.e locked) on the sender chain. - The coins are transferred to the receiving chain through IBC TAO logic. 2. Sender chain is the sink chain, *i.e* the token is sent back to the chain it previously received from. This is a backwards movement in the token's timeline. This results in the following state transitions: -- The coins (vouchers) are burned on the sender chain -- The coins transferred to the receiving chain though IBC TAO logic. +- The coins (vouchers) are burned on the sender chain. +- The coins are transferred to the receiving chain through IBC TAO logic. -## Receive Fungible Tokens +## Receive fungible tokens -A successful fungible token receive has two state transitions depending if the -transfer is a movement forward or backwards in the token's timeline: +A successful fungible token receive has two state transitions depending if the transfer is a movement forward or backwards in the token's timeline: 1. Receiver chain is the source chain. This is a backwards movement in the token's timeline. This results in the following state transitions: diff --git a/modules/apps/transfer/spec/02_state.md b/docs/apps/transfer/state.md similarity index 57% rename from modules/apps/transfer/spec/02_state.md rename to docs/apps/transfer/state.md index a0b2f99a4c5..f436d4af8cc 100644 --- a/modules/apps/transfer/spec/02_state.md +++ b/docs/apps/transfer/state.md @@ -4,7 +4,7 @@ order: 2 # State -The transfer IBC application module keeps state of the port to which the module is binded and the denomination trace information as outlined in [ADR 01](./../../../../docs/architecture/adr-001-coin-source-tracing.md). +The IBC transfer application module keeps state of the port to which the module is binded and the denomination trace information as outlined in [ADR 001](../../architecture/adr-001-coin-source-tracing.md). - `Port`: `0x01 -> ProtocolBuffer(string)` - `DenomTrace`: `0x02 | []bytes(traceHash) -> ProtocolBuffer(DenomTrace)` diff --git a/modules/apps/transfer/spec/04_messages.md b/modules/apps/transfer/spec/04_messages.md deleted file mode 100644 index 611e2423da7..00000000000 --- a/modules/apps/transfer/spec/04_messages.md +++ /dev/null @@ -1,40 +0,0 @@ - - -# Messages - -## MsgTransfer - -A fungible token cross chain transfer is achieved by using the `MsgTransfer`: - -```go -type MsgTransfer struct { - SourcePort string - SourceChannel string - Token sdk.Coin - Sender string - Receiver string - TimeoutHeight ibcexported.Height - TimeoutTimestamp uint64 -} -``` - -This message is expected to fail if: - -- `SourcePort` is invalid (see 24-host naming requirements) -- `SourceChannel` is invalid (see 24-host naming requirements) -- `Token` is invalid (denom is invalid or amount is negative) -- `Token.Amount` is not positive -- `Sender` is empty -- `Receiver` is empty -- `TimeoutHeight` and `TimeoutTimestamp` are both zero -- `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](./../../../../docs/architecture/adr-001-coin-source-tracing.md). - -This message will send a fungible token to the counterparty chain represented -by the counterparty Channel End connected to the Channel End with the identifiers -`SourcePort` and `SourceChannel`. - -The denomination provided for transfer should correspond to the same denomination -represented on this chain. The prefixes will be added as necessary upon by the -receiving chain. diff --git a/modules/apps/transfer/spec/07_params.md b/modules/apps/transfer/spec/07_params.md deleted file mode 100644 index 142091a9433..00000000000 --- a/modules/apps/transfer/spec/07_params.md +++ /dev/null @@ -1,28 +0,0 @@ - - -# Parameters - -The ibc-transfer module contains the following parameters: - -| Key | Type | Default Value | -|------------------|------|---------------| -| `SendEnabled` | bool | `true` | -| `ReceiveEnabled` | bool | `true` | - -## SendEnabled - -The transfers enabled parameter controls send cross-chain transfer capabilities for all fungible -tokens. - -To prevent a single token from being transferred from the chain, set the `SendEnabled` parameter to `true` and -then set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/master/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. - -## ReceiveEnabled - -The transfers enabled parameter controls receive cross-chain transfer capabilities for all fungible -tokens. - -To prevent a single token from being transferred to the chain, set the `ReceiveEnabled` parameter to `true` and -then set the bank module's [`SendEnabled` parameter](https://github.com/cosmos/cosmos-sdk/blob/master/x/bank/spec/05_params.md#sendenabled) for the denomination to `false`. diff --git a/modules/apps/transfer/spec/README.md b/modules/apps/transfer/spec/README.md deleted file mode 100644 index 05d1cc156d0..00000000000 --- a/modules/apps/transfer/spec/README.md +++ /dev/null @@ -1,24 +0,0 @@ - - -# `ibc-transfer` - -## Abstract - -This paper defines the implementation of the ICS20 protocol on the Cosmos SDK. - -For the general specification please refer to the [ICS20 Specification](https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer). - -## Contents - -1. **[Concepts](01_concepts.md)** -2. **[State](02_state.md)** -3. **[State Transitions](03_state_transitions.md)** -4. **[Messages](04_messages.md)** -5. **[Events](05_events.md)** -6. **[Metrics](06_metrics.md)** -7. **[Parameters](07_params.md)** From d8130c34538850ef954b91a0b6a962677e9a07e4 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 23 Jun 2022 21:37:15 +0200 Subject: [PATCH 181/275] fix typo in parameter name of `NewDefaultMetadata` (#1573) ## Description closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- modules/apps/27-interchain-accounts/types/metadata.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/27-interchain-accounts/types/metadata.go b/modules/apps/27-interchain-accounts/types/metadata.go index dd14c4788ec..09185ea6edc 100644 --- a/modules/apps/27-interchain-accounts/types/metadata.go +++ b/modules/apps/27-interchain-accounts/types/metadata.go @@ -29,9 +29,9 @@ func NewMetadata(version, controllerConnectionID, hostConnectionID, accAddress, // NewDefaultMetadata creates and returns a new ICS27 Metadata instance containing the default ICS27 Metadata values // with the provided controller and host connection identifiers -func NewDefaultMetadata(connectionConnectionID, hostConnectionID string) Metadata { +func NewDefaultMetadata(controllerConnectionID, hostConnectionID string) Metadata { metadata := Metadata{ - ControllerConnectionId: connectionConnectionID, + ControllerConnectionId: controllerConnectionID, HostConnectionId: hostConnectionID, Encoding: EncodingProtobuf, TxType: TxTypeSDKMultiMsg, From 20ffa6f1aca8adddccdcd714488eead2256a420d Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 23 Jun 2022 22:24:05 +0200 Subject: [PATCH 182/275] adding team members to 02-client and light-clients code owners (#1563) * adding team members to 02-client and 07-tendermint code owners * review comment --- .github/CODEOWNERS | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bd59278e6a4..f6569b64ddd 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -16,10 +16,15 @@ /modules/core/ @colin-axner @fedekunze @AdityaSripal /proto/ibc/core/ @colin-axner @fedekunze @AdityaSripal +## CODEOWNERS for core/02-client + +/modules/core/02-client @seantking @damiannolan +/proto/ibc/core/client @seantking @damiannolan + # CODEOWNERS for the light-clients -/modules/light-clients/ @colin-axner @fedekunze @AdityaSripal -/proto/ibc/lightclients/ @colin-axner @fedekunze @AdityaSripal +/modules/light-clients/ @colin-axner @fedekunze @AdityaSripal @seantking @damiannolan +/proto/ibc/lightclients/ @colin-axner @fedekunze @AdityaSripal @seantking @damiannolan # CODEOWNERS for ICS 20 From e7d5bdae7247dcef8c31ef6adff88f8a49de799c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Jun 2022 14:36:09 +0200 Subject: [PATCH 183/275] build(deps): bump github.com/stretchr/testify from 1.7.4 to 1.7.5 (#1575) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.4 to 1.7.5. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.7.4...v1.7.5) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c2a37743dd3..7b9443ade4d 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.12.0 - github.com/stretchr/testify v1.7.4 + github.com/stretchr/testify v1.7.5 github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd diff --git a/go.sum b/go.sum index 94a11519f20..05c8bcbda2f 100644 --- a/go.sum +++ b/go.sum @@ -972,8 +972,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM= -github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= From 33afe107b77417bfb75c0fcb0fc4667f0d9bdcc6 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 26 Jun 2022 22:49:11 +0200 Subject: [PATCH 184/275] docs: document that version string can be empty as argument of RegisterInterchainAccount --- docs/apps/interchain-accounts/active-channels.md | 6 +++--- docs/apps/interchain-accounts/auth-modules.md | 8 ++++---- docs/migrations/v3-to-v4.md | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/apps/interchain-accounts/active-channels.md b/docs/apps/interchain-accounts/active-channels.md index c574ea87d85..d387bdea038 100644 --- a/docs/apps/interchain-accounts/active-channels.md +++ b/docs/apps/interchain-accounts/active-channels.md @@ -12,11 +12,11 @@ channel type that provides ordering of packets without the channel closing on ti When an Interchain Account is registered using the `RegisterInterchainAccount` API, a new channel is created on a particular port. During the `OnChanOpenAck` and `OnChanOpenConfirm` steps (controller & host chain) the `Active Channel` for this interchain account is stored in state. -It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `OnChanOpenInit` message like so: +It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `MsgChannelOpenInit` message like so: ```go - msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) - handler := k.msgRouter.Handler(msg) +msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) +handler := k.msgRouter.Handler(msg) ``` Alternatively, any relayer operator may initiate a new channel handshake for this interchain account once the previously set `Active Channel` is in a `CLOSED` state. This is done by initiating the channel handshake on the controller chain using the same portID associated with the interchain account in question. diff --git a/docs/apps/interchain-accounts/auth-modules.md b/docs/apps/interchain-accounts/auth-modules.md index fdff2385282..5d75409b3c4 100644 --- a/docs/apps/interchain-accounts/auth-modules.md +++ b/docs/apps/interchain-accounts/auth-modules.md @@ -38,15 +38,15 @@ func (im IBCModule) OnChanOpenInit( chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { +) (string, error) { // the authentication module *must* claim the channel capability on OnChanOpenInit if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err + return version, err } // perform custom logic - return nil + return version, nil } // OnChanOpenAck implements the IBCModule interface @@ -157,7 +157,7 @@ if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID return nil ``` -The `version` argument is used to support ICS29 fee middleware for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. +The `version` argument is used to support ICS29 fee middleware for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 49f311a844e..1cd08f5bd49 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -30,7 +30,7 @@ The return signature now includes the application version as detailed in the lat The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. -This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. +This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: From b2cd6e8b5534ade44d0891be5ae01d9230581714 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 26 Jun 2022 22:50:16 +0200 Subject: [PATCH 185/275] Revert "docs: document that version string can be empty as argument of RegisterInterchainAccount" This reverts commit 33afe107b77417bfb75c0fcb0fc4667f0d9bdcc6. --- docs/apps/interchain-accounts/active-channels.md | 6 +++--- docs/apps/interchain-accounts/auth-modules.md | 8 ++++---- docs/migrations/v3-to-v4.md | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/apps/interchain-accounts/active-channels.md b/docs/apps/interchain-accounts/active-channels.md index d387bdea038..c574ea87d85 100644 --- a/docs/apps/interchain-accounts/active-channels.md +++ b/docs/apps/interchain-accounts/active-channels.md @@ -12,11 +12,11 @@ channel type that provides ordering of packets without the channel closing on ti When an Interchain Account is registered using the `RegisterInterchainAccount` API, a new channel is created on a particular port. During the `OnChanOpenAck` and `OnChanOpenConfirm` steps (controller & host chain) the `Active Channel` for this interchain account is stored in state. -It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `MsgChannelOpenInit` message like so: +It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `OnChanOpenInit` message like so: ```go -msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) -handler := k.msgRouter.Handler(msg) + msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) + handler := k.msgRouter.Handler(msg) ``` Alternatively, any relayer operator may initiate a new channel handshake for this interchain account once the previously set `Active Channel` is in a `CLOSED` state. This is done by initiating the channel handshake on the controller chain using the same portID associated with the interchain account in question. diff --git a/docs/apps/interchain-accounts/auth-modules.md b/docs/apps/interchain-accounts/auth-modules.md index 5d75409b3c4..fdff2385282 100644 --- a/docs/apps/interchain-accounts/auth-modules.md +++ b/docs/apps/interchain-accounts/auth-modules.md @@ -38,15 +38,15 @@ func (im IBCModule) OnChanOpenInit( chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) (string, error) { +) error { // the authentication module *must* claim the channel capability on OnChanOpenInit if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return version, err + return err } // perform custom logic - return version, nil + return nil } // OnChanOpenAck implements the IBCModule interface @@ -157,7 +157,7 @@ if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID return nil ``` -The `version` argument is used to support ICS29 fee middleware for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. +The `version` argument is used to support ICS29 fee middleware for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 1cd08f5bd49..49f311a844e 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -30,7 +30,7 @@ The return signature now includes the application version as detailed in the lat The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. -This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. +This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: From 8be6a10fa4a732dbe5e12d6d70899168c2c61a1e Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 27 Jun 2022 16:28:19 +0200 Subject: [PATCH 186/275] docs: payee registration and fee distribution for relayer operators (#1577) * adding fee distribution docs for relayer operators * adding validation information and basic cli examples * removing unnecessary whitespace * updating definitions * Apply suggestions from code review Co-authored-by: Carlos Rodriguez Co-authored-by: Sean King Co-authored-by: Carlos Rodriguez Co-authored-by: Sean King --- docs/.vuepress/config.js | 5 ++ docs/middleware/ics29-fee/fee-distribution.md | 90 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 docs/middleware/ics29-fee/fee-distribution.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 5183df990c1..e748d200226 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -238,6 +238,11 @@ module.exports = { directory: false, path: "/middleware/ics29-fee/integration.html" }, + { + title: "Fee Distribution", + directory: false, + path: "/middleware/ics29-fee/fee-distribution.html" + }, ] }, ] diff --git a/docs/middleware/ics29-fee/fee-distribution.md b/docs/middleware/ics29-fee/fee-distribution.md new file mode 100644 index 00000000000..b89a2c9cd78 --- /dev/null +++ b/docs/middleware/ics29-fee/fee-distribution.md @@ -0,0 +1,90 @@ + + +# Fee distribution + +Learn about payee registration for the distribution of packet fees. The following document is intended for relayer operators. {synopsis} + +## Pre-requisite readings + +* [Fee Middleware](overview.md) {prereq} + +Packet fees are divided into 3 distinct amounts in order to compensate relayer operators for packet relaying on fee enabled IBC channels. + +- `RecvFee`: The sum of all packet receive fees distributed to a payee for successful execution of `MsgRecvPacket`. +- `AckFee`: The sum of all packet acknowledgement fees distributed to a payee for successful execution of `MsgAcknowledgement`. +- `TimeoutFee`: The sum of all packet timeout fees distributed to a payee for successful execution of `MsgTimeout`. + +## Register a payee address for forward relaying + +As mentioned in [ICS29 Concepts](../ics29-fee/overview.md#concepts), the forward relayer describes the actor who performs the submission of `MsgRecvPacket` on the destination chain. +Fee distribution for incentivized packet relays takes place on the packet source chain. +Relayer operators are expected to register a counterparty payee address, in order to be compensated accordingly with `RecvFee`s upon completion of a packet lifecycle. +The counterparty payee address registered on the destination chain is encoded into the packet acknowledgement and communicated as such to the source chain for fee distribution. +If a counterparty payee is not registered for the forward relayer on the destination chain, the escrowed fees will be refunded upon fee distribution. + +A transaction must be submitted to the desintation chain including a `CounterpartyPayee` address of an account on the source chain. +The transaction must be signed by the `Relayer`. + +```go +type MsgRegisterCounterpartyPayee struct { + // unique port identifier + PortId string + // unique channel identifier + ChannelId string + // the relayer address + Relayer string + // the counterparty payee address + CounterpartyPayee string +} +``` + +This message is expected to fail if: + +- `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). +- `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). +- `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/basics/accounts.md#Addresses)). +- `CounterpartyPayee` is empty. + +See below for an example CLI command: + +``` +simd tx ibc-fee register-counterparty-payee transfer channel-0 cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh osmo1v5y0tz01llxzf4c2afml8s3awue0ymju22wxx2 --from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh +``` + +## Register a payee address for reverse and timeout relaying + +As mentioned in [ICS29 Concepts](../ics29-fee/overview.md#concepts), the reverse relayer describes the actor who performs the submission of `MsgAcknowledgement` on the source chain. +Similarly the timeout relayer describes the actor who performs the submission of `MsgTimeout` (or `MsgTimeoutOnClose`) on the source chain. +Relayer operators may choose to register an optional payee address, in order to be compensated accordingly with `AckFee`s and `TimeoutFee`s upon completion of a packet life cycle. +If a payee is not registered for the reverse or timeout relayer on the source chain, then fee distribution assumes the default behaviour, where fees are paid out to the relayer account which delivers `MsgAcknowledgement` or `MsgTimeout`/`MsgTimeoutOnClose`. + +A transaction must be submitted to the source chain including a `Payee` address of an account on the source chain. +The transaction must be signed by the `Relayer`. + +```go +type MsgRegisterPayee struct { + // unique port identifier + PortId string + // unique channel identifier + ChannelId string + // the relayer address + Relayer string + // the payee address + Payee string +} +``` + +This message is expected to fail if: + +- `PortId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators). +- `ChannelId` is invalid (see [24-host naming requirements](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators)). +- `Relayer` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/basics/accounts.md#Addresses)). +- `Payee` is an invalid address (see [Cosmos SDK Addresses](https://github.com/cosmos/cosmos-sdk/blob/main/docs/basics/accounts.md#Addresses)). + +See below for an example CLI command: + +``` +simd tx ibc-fee register-payee transfer channel-0 cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5 --from cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh +``` From 1d94aadfa8db1b0b45b48dd20c9a999efd572801 Mon Sep 17 00:00:00 2001 From: Charly Date: Mon, 27 Jun 2022 17:34:02 +0200 Subject: [PATCH 187/275] docs: msg types for fee middleware (#1572) * fix broken link * fix: rm AllowUpdateAfter... check (#1118) * update code & test * update proto and adr026 * update CHANGELOG * update cli docs * update broken milestone link * updated docs * update re: comments * nits: adding inline comments Co-authored-by: Sean King --- docs/.vuepress/config.js | 7 +++- docs/middleware/ics29-fee/msgs.md | 70 +++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 docs/middleware/ics29-fee/msgs.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index e748d200226..a6da1d7ad8c 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -224,7 +224,7 @@ module.exports = { title: "IBC Middleware Modules", children: [ { - title: "ICS29 Fee Middleware", + title: "Fee Middleware", directory: true, path: "/middleware", children: [ @@ -238,6 +238,11 @@ module.exports = { directory: false, path: "/middleware/ics29-fee/integration.html" }, + { + title: "Fee Messages", + directory: false, + path: "/middleware/ics29-fee/msgs.html" + }, { title: "Fee Distribution", directory: false, diff --git a/docs/middleware/ics29-fee/msgs.md b/docs/middleware/ics29-fee/msgs.md new file mode 100644 index 00000000000..91d67849236 --- /dev/null +++ b/docs/middleware/ics29-fee/msgs.md @@ -0,0 +1,70 @@ + + +# Escrowing fees + +The fee middleware module exposes two different ways to pay fees for relaying IBC packets: + +1. `MsgPayPacketFee`, which enables the escrowing of fees for a packet at the next sequence send and should be combined into one `MultiMsgTx` with the message that will be paid for. + + Note that the `Relayers` field has been set up to allow for an optional whitelist of relayers permitted to receive this fee, however, this feature has not yet been enabled at this time. + + ``` + type MsgPayPacketFee struct{ + // fee encapsulates the recv, ack and timeout fees associated with an IBC packet + Fee Fee + // the source port unique identifier + SourcePortId string + // the source channel unique identifer + SourceChannelId string + // account address to refund fee if necessary + Signer string + // optional list of relayers permitted to the receive packet fee + Relayers []string + } + ``` + + The `Fee` message contained in this synchronous fee payment method configures different fees which will be paid out for `MsgRecvPacket`, `MsgAcknowledgement`, and `MsgTimeout`/`MsgTimeoutOnClose`. + + ``` + type Fee struct { + RecvFee types.Coins + AckFee types.Coins + TimeoutFee types.Coin` + } + ``` + +2. `MsgPayPacketFeeAsync`, which enables the asynchronous escrowing of fees for a specified packet: + + ``` + type MsgPayPacketFeeAsync struct { + // unique packet identifier comprised of the channel ID, port ID and sequence + PacketId channeltypes.PacketId + // the packet fee associated with a particular IBC packet + PacketFee PacketFee + } + ``` + + where the `PacketFee` also specifies the `Fee` to be paid as well as the refund address for fees which are not paid out + ``` + type PacketFee struct { + Fee Fee + RefundAddress string + Relayers []]string + } + ``` + +Please see our [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers) for example flows on how to use these messages to incentivise a token transfer channel using a CLI. + +# Paying out the escrowed fees + +In the case of a successful transaction, `RecvFee` will be paid out to the designated counterparty payee address which has been registered on the receiver chain and sent back with the `MsgAcknowledgement`, `AckFee` will be paid out to the relayer address which has submitted the `MsgAcknowledgement` on the sending chain (or the registered payee in case one has been registered for the relayer address), and `TimeoutFee` will be reimbursed to the account which escrowed the fee. In cases of timeout transactions, `RecvFee` and `AckFee` will be reimbursed. + +Please note that fee payments are built on the assumption that sender chains are the source of incentives — the chain that sends the packets is the same chain where fee payments will occur -- please see the [relayer operator section](../ics29-fee/fee-distribution.md) to understand the flow for registering payee and counterparty payee (fee receiving) addresses. + +# A locked fee middleware module + +The fee middleware module can become locked if the situation arises that the escrow account for the fees does not have sufficient funds to pay out the fees which have been escrowed for each packet. This situation indicates a severe bug. In this case, the fee module will be locked until manual intervention fixes the issue. + +A locked fee module will simply skip fee logic and continue on to the underlying packet flow. A channel with a locked fee module will temporarily function as a fee disabled channel, and the locking of a fee module will not affect the continued flow of packets over the channel. From 3b5db68f0aa1f6706ad130aa21c0f4eda9e2dd4e Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 27 Jun 2022 17:43:27 +0200 Subject: [PATCH 188/275] chore: adding module name to incentivized packet events (#1580) --- modules/apps/29-fee/keeper/events.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/apps/29-fee/keeper/events.go b/modules/apps/29-fee/keeper/events.go index 36207dbc5db..f604a8c9704 100644 --- a/modules/apps/29-fee/keeper/events.go +++ b/modules/apps/29-fee/keeper/events.go @@ -27,7 +27,7 @@ func EmitIncentivizedPacketEvent(ctx sdk.Context, packetID channeltypes.PacketId } } - ctx.EventManager().EmitEvent( + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeIncentivizedPacket, sdk.NewAttribute(channeltypes.AttributeKeyPortID, packetID.PortId), @@ -37,7 +37,11 @@ func EmitIncentivizedPacketEvent(ctx sdk.Context, packetID channeltypes.PacketId sdk.NewAttribute(types.AttributeKeyAckFee, totalAckFees.String()), sdk.NewAttribute(types.AttributeKeyTimeoutFee, totalTimeoutFees.String()), ), - ) + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) } // EmitRegisterPayeeEvent emits an event containing information of a registered payee for a relayer on a particular channel From 36a3382bceabef7e54db5ba726be7c24f3874e2e Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 27 Jun 2022 17:50:54 +0200 Subject: [PATCH 189/275] docs: adding events to fee middleware docs (#1578) * adding fee distribution docs for relayer operators * adding validation information and basic cli examples * removing unnecessary whitespace * updating definitions * adding ics29 fee middleware events docs * cleanup Co-authored-by: Sean King --- docs/.vuepress/config.js | 5 +++++ docs/middleware/ics29-fee/events.md | 35 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 docs/middleware/ics29-fee/events.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index a6da1d7ad8c..15a6df397a0 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -248,6 +248,11 @@ module.exports = { directory: false, path: "/middleware/ics29-fee/fee-distribution.html" }, + { + title: "Events", + directory: false, + path: "/middleware/ics29-fee/events.html" + }, ] }, ] diff --git a/docs/middleware/ics29-fee/events.md b/docs/middleware/ics29-fee/events.md new file mode 100644 index 00000000000..04ab5b34cee --- /dev/null +++ b/docs/middleware/ics29-fee/events.md @@ -0,0 +1,35 @@ + + +# Events + +## `MsgPayPacketFee`, `MsgPayPacketFeeAsync` + +| Type | Attribute Key | Attribute Value | +|-------------------------|-----------------|-----------------| +| incentivized_ibc_packet | port_id | {portID} | +| incentivized_ibc_packet | channel_id | {channelID} | +| incentivized_ibc_packet | packet_sequence | {sequence} | +| incentivized_ibc_packet | recv_fee | {recvFee} | +| incentivized_ibc_packet | ack_fee | {ackFee} | +| incentivized_ibc_packet | timeout_fee | {timeoutFee} | +| message | module | fee-ibc | + +## `RegisterPayee` + +| Type | Attribute Key | Attribute Value | +|----------------|------------|--------------------| +| register_payee | relayer | {relayer} | +| register_payee | payee | {payee} | +| register_payee | channel_id | {channelID} | +| message | module | fee-ibc | + +## `RegisterCounterpartyPayee` + +| Type | Attribute Key | Attribute Value | +|-----------------------------|--------------------|---------------------| +| register_counterparty_payee | relayer | {relayer} | +| register_counterparty_payee | counterparty_payee | {counterpartyPayee} | +| register_counterparty_payee | channel_id | {channelID} | +| message | module | fee-ibc | From 83ca736968c18f9c82ae47e48760f3ddcb2f3588 Mon Sep 17 00:00:00 2001 From: Sean King Date: Mon, 27 Jun 2022 17:53:48 +0200 Subject: [PATCH 190/275] docs: adding End Users section to ics29 docs (#1579) * docs: adding End Users section to ics29 docs * Update docs/middleware/ics29-fee/end-users.md Co-authored-by: Carlos Rodriguez * Update docs/middleware/ics29-fee/end-users.md Co-authored-by: Carlos Rodriguez * Update docs/middleware/ics29-fee/end-users.md Co-authored-by: Carlos Rodriguez * Update docs/middleware/ics29-fee/end-users.md Co-authored-by: Carlos Rodriguez * Update docs/middleware/ics29-fee/end-users.md Co-authored-by: Carlos Rodriguez * Update docs/middleware/ics29-fee/end-users.md Co-authored-by: Carlos Rodriguez * Update docs/middleware/ics29-fee/end-users.md Co-authored-by: Carlos Rodriguez * Update docs/middleware/ics29-fee/end-users.md Co-authored-by: Carlos Rodriguez * Update docs/middleware/ics29-fee/end-users.md Co-authored-by: Damian Nolan * chore: add link Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan --- docs/.vuepress/config.js | 5 +++++ docs/middleware/ics29-fee/end-users.md | 31 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 docs/middleware/ics29-fee/end-users.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 15a6df397a0..a15407fd54a 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -238,6 +238,11 @@ module.exports = { directory: false, path: "/middleware/ics29-fee/integration.html" }, + { + title: "End Users", + directory: false, + path: "/middleware/ics29-fee/end-users.html" + }, { title: "Fee Messages", directory: false, diff --git a/docs/middleware/ics29-fee/end-users.md b/docs/middleware/ics29-fee/end-users.md new file mode 100644 index 00000000000..08857d21a37 --- /dev/null +++ b/docs/middleware/ics29-fee/end-users.md @@ -0,0 +1,31 @@ + + +# For end users + +Learn how to incentivize IBC packets using the ICS29 Fee Middleware module. {synopsis} + +## Pre-requisite readings + +* [Fee Middleware](overview.md) {prereq} + +## Summary + +Different types of end users: + +- CLI users who want to manually incentivize IBC packets +- Client developers + + +The Fee Middleware module allows end users to add a 'tip' to each IBC packet which will incentivize relayer operators to relay packets between chains. gRPC endpoints are exposed for client developers as well as a simple CLI for manually incentivizing IBC packets. + +## CLI Users + +For an in depth guide on how to use the ICS29 Fee Middleware module using the CLI please take a look at the [wiki](https://github.com/cosmos/ibc-go/wiki/Fee-enabled-fungible-token-transfers#asynchronous-incentivization-of-a-fungible-token-transfer) on the `ibc-go` repo. + +## Client developers + +Client developers can read more about the relevant ICS29 message types in the [Escrowing and paying out fees section](../ics29-fee/msgs.md). + +[CosmJS](https://github.com/cosmos/cosmjs) is a useful client library for signing and broadcasting Cosmos SDK messages. From 8422d0c4c35ef970539466c5bdec1cd27369bab3 Mon Sep 17 00:00:00 2001 From: Sean King Date: Mon, 27 Jun 2022 18:04:15 +0200 Subject: [PATCH 191/275] feat: emitting an event when handling a client upgrade proposal (#1570) * feat: emitting an event when handling a client upgrade proposal * refactor: only emit event if err is nil * refactor: idiotmatic go: --- CHANGELOG.md | 1 + modules/core/02-client/keeper/events.go | 13 +++++++++++++ modules/core/02-client/keeper/proposal.go | 9 ++++++++- modules/core/02-client/types/events.go | 23 +++++++++++++---------- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb6e080f5f4..281715f19ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees * (testing/simapp) [\#1397](https://github.com/cosmos/ibc-go/pull/1397) Adding mock module to maccperms and adding check to ensure mock module is not a blocked account address. +* (core/02-client) [\#1570](https://github.com/cosmos/ibc-go/pull/1570) Emitting an event when handling an upgrade client proposal. ### Features diff --git a/modules/core/02-client/keeper/events.go b/modules/core/02-client/keeper/events.go index ff8ae1c3acd..ad82292dc61 100644 --- a/modules/core/02-client/keeper/events.go +++ b/modules/core/02-client/keeper/events.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" @@ -68,6 +70,17 @@ func EmitUpdateClientProposalEvent(ctx sdk.Context, clientID string, clientState ) } +// EmitUpgradeClientProposalEvent emits an upgrade client proposal event +func EmitUpgradeClientProposalEvent(ctx sdk.Context, title string, height int64) { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeUpgradeClientProposal, + sdk.NewAttribute(types.AttributeKeyUpgradePlanTitle, title), + sdk.NewAttribute(types.AttributeKeyUpgradePlanHeight, fmt.Sprintf("%d", height)), + ), + ) +} + // EmitSubmitMisbehaviourEvent emits a client misbehaviour event func EmitSubmitMisbehaviourEvent(ctx sdk.Context, clientID string, clientState exported.ClientState) { ctx.EventManager().EmitEvent( diff --git a/modules/core/02-client/keeper/proposal.go b/modules/core/02-client/keeper/proposal.go index ef0bf043e50..5e483d8a110 100644 --- a/modules/core/02-client/keeper/proposal.go +++ b/modules/core/02-client/keeper/proposal.go @@ -98,5 +98,12 @@ func (k Keeper) HandleUpgradeProposal(ctx sdk.Context, p *types.UpgradeProposal) // sets the new upgraded client in last height committed on this chain is at plan.Height, // since the chain will panic at plan.Height and new chain will resume at plan.Height - return k.upgradeKeeper.SetUpgradedClient(ctx, p.Plan.Height, bz) + if err = k.upgradeKeeper.SetUpgradedClient(ctx, p.Plan.Height, bz); err != nil { + return err + } + + // emitting an event for handling client upgrade proposal + EmitUpgradeClientProposalEvent(ctx, p.Title, p.Plan.Height) + + return nil } diff --git a/modules/core/02-client/types/events.go b/modules/core/02-client/types/events.go index 391e1e37080..93aa27afa0b 100644 --- a/modules/core/02-client/types/events.go +++ b/modules/core/02-client/types/events.go @@ -8,20 +8,23 @@ import ( // IBC client events const ( - AttributeKeyClientID = "client_id" - AttributeKeySubjectClientID = "subject_client_id" - AttributeKeyClientType = "client_type" - AttributeKeyConsensusHeight = "consensus_height" - AttributeKeyHeader = "header" + AttributeKeyClientID = "client_id" + AttributeKeySubjectClientID = "subject_client_id" + AttributeKeyClientType = "client_type" + AttributeKeyConsensusHeight = "consensus_height" + AttributeKeyHeader = "header" + AttributeKeyUpgradePlanTitle = "title" + AttributeKeyUpgradePlanHeight = "height" ) // IBC client events vars var ( - EventTypeCreateClient = "create_client" - EventTypeUpdateClient = "update_client" - EventTypeUpgradeClient = "upgrade_client" - EventTypeSubmitMisbehaviour = "client_misbehaviour" - EventTypeUpdateClientProposal = "update_client_proposal" + EventTypeCreateClient = "create_client" + EventTypeUpdateClient = "update_client" + EventTypeUpgradeClient = "upgrade_client" + EventTypeSubmitMisbehaviour = "client_misbehaviour" + EventTypeUpdateClientProposal = "update_client_proposal" + EventTypeUpgradeClientProposal = "upgrade_client_proposal" AttributeValueCategory = fmt.Sprintf("%s_%s", host.ModuleName, SubModuleName) ) From 04791984b3d6c83f704c4f058e6ca0038d155d91 Mon Sep 17 00:00:00 2001 From: Sean King Date: Mon, 27 Jun 2022 18:58:51 +0200 Subject: [PATCH 192/275] docs: nits (#1595) --- docs/middleware/ics29-fee/fee-distribution.md | 2 +- docs/middleware/ics29-fee/msgs.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/middleware/ics29-fee/fee-distribution.md b/docs/middleware/ics29-fee/fee-distribution.md index b89a2c9cd78..0ca1bce921f 100644 --- a/docs/middleware/ics29-fee/fee-distribution.md +++ b/docs/middleware/ics29-fee/fee-distribution.md @@ -24,7 +24,7 @@ Relayer operators are expected to register a counterparty payee address, in orde The counterparty payee address registered on the destination chain is encoded into the packet acknowledgement and communicated as such to the source chain for fee distribution. If a counterparty payee is not registered for the forward relayer on the destination chain, the escrowed fees will be refunded upon fee distribution. -A transaction must be submitted to the desintation chain including a `CounterpartyPayee` address of an account on the source chain. +A transaction must be submitted to the destination chain including a `CounterpartyPayee` address of an account on the source chain. The transaction must be signed by the `Relayer`. ```go diff --git a/docs/middleware/ics29-fee/msgs.md b/docs/middleware/ics29-fee/msgs.md index 91d67849236..7ab81cd9552 100644 --- a/docs/middleware/ics29-fee/msgs.md +++ b/docs/middleware/ics29-fee/msgs.md @@ -6,7 +6,7 @@ order: 3 The fee middleware module exposes two different ways to pay fees for relaying IBC packets: -1. `MsgPayPacketFee`, which enables the escrowing of fees for a packet at the next sequence send and should be combined into one `MultiMsgTx` with the message that will be paid for. +1. `MsgPayPacketFee`, which enables the escrowing of fees for a packet at the next sequence send and should be combined into one `MultiMsgTx` with the message that will be paid for. Note that the `Relayers` field has been set up to allow for an optional whitelist of relayers permitted to receive this fee, however, this feature has not yet been enabled at this time. @@ -37,6 +37,8 @@ The fee middleware module exposes two different ways to pay fees for relaying IB 2. `MsgPayPacketFeeAsync`, which enables the asynchronous escrowing of fees for a specified packet: + Note that a packet can be 'topped up' multiple times with additional fees of any coin denomination by broadcasting multiple `MsgPayPacketFeeAsync` messages. + ``` type MsgPayPacketFeeAsync struct { // unique packet identifier comprised of the channel ID, port ID and sequence From 84792ba87a194e499e4e30dbb88fc5220bb0bc97 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 27 Jun 2022 22:18:08 +0200 Subject: [PATCH 193/275] docs: document that version string can be empty as argument of RegisterInterchainAccount (#1582) Co-authored-by: Carlos Rodriguez --- docs/apps/interchain-accounts/active-channels.md | 6 +++--- docs/apps/interchain-accounts/auth-modules.md | 8 ++++---- docs/migrations/v3-to-v4.md | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/apps/interchain-accounts/active-channels.md b/docs/apps/interchain-accounts/active-channels.md index c574ea87d85..d387bdea038 100644 --- a/docs/apps/interchain-accounts/active-channels.md +++ b/docs/apps/interchain-accounts/active-channels.md @@ -12,11 +12,11 @@ channel type that provides ordering of packets without the channel closing on ti When an Interchain Account is registered using the `RegisterInterchainAccount` API, a new channel is created on a particular port. During the `OnChanOpenAck` and `OnChanOpenConfirm` steps (controller & host chain) the `Active Channel` for this interchain account is stored in state. -It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `OnChanOpenInit` message like so: +It is possible to create a new channel using the same controller chain portID if the previously set `Active Channel` is now in a `CLOSED` state. This channel creation can be initialized programatically by sending a new `MsgChannelOpenInit` message like so: ```go - msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) - handler := k.msgRouter.Handler(msg) +msg := channeltypes.NewMsgChannelOpenInit(portID, string(versionBytes), channeltypes.ORDERED, []string{connectionID}, icatypes.PortID, icatypes.ModuleName) +handler := k.msgRouter.Handler(msg) ``` Alternatively, any relayer operator may initiate a new channel handshake for this interchain account once the previously set `Active Channel` is in a `CLOSED` state. This is done by initiating the channel handshake on the controller chain using the same portID associated with the interchain account in question. diff --git a/docs/apps/interchain-accounts/auth-modules.md b/docs/apps/interchain-accounts/auth-modules.md index fdff2385282..5d75409b3c4 100644 --- a/docs/apps/interchain-accounts/auth-modules.md +++ b/docs/apps/interchain-accounts/auth-modules.md @@ -38,15 +38,15 @@ func (im IBCModule) OnChanOpenInit( chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { +) (string, error) { // the authentication module *must* claim the channel capability on OnChanOpenInit if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err + return version, err } // perform custom logic - return nil + return version, nil } // OnChanOpenAck implements the IBCModule interface @@ -157,7 +157,7 @@ if err := keeper.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID return nil ``` -The `version` argument is used to support ICS29 fee middleware for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. +The `version` argument is used to support ICS29 fee middleware for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are expected to build the appropriate JSON encoded version string themselves and pass it accordingly. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 49f311a844e..1cd08f5bd49 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -30,7 +30,7 @@ The return signature now includes the application version as detailed in the lat The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. Consumers of the `RegisterInterchainAccount` are now expected to build the appropriate JSON encoded version string themselves and pass it accordingly. -This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. +This should be constructed within the interchain accounts authentication module which leverages the APIs exposed via the interchain accounts `controllerKeeper`. If an empty string is passed in the `version` argument, then the version will be initialized to a default value in the `OnChanOpenInit` callback of the controller's handler, so that channel handshake can proceed. The following code snippet illustrates how to construct an appropriate interchain accounts `Metadata` and encode it as a JSON bytestring: From 41282c772bd8494f9b48d9ebdb40be7d5f7abd18 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 28 Jun 2022 11:30:46 +0200 Subject: [PATCH 194/275] docs: add upgrade client proposal event (#1596) --- docs/ibc/events.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/ibc/events.md b/docs/ibc/events.md index b7b28351cab..2c584302566 100644 --- a/docs/ibc/events.md +++ b/docs/ibc/events.md @@ -58,7 +58,12 @@ callbacks to IBC applications. | update_client_proposal | client_type | {clientType} | | update_client_proposal | consensus_height | {consensusHeight} | +### UpgradeProposal +| Type | Attribute Key | Attribute Value | +|-------------------------|-----------------|-------------------| +| upgrade_client_proposal | title | {title} | +| upgrade_client_proposal | height | {height} | ## ICS 03 - Connection From b40dbc646c7191aaee12d3a70243f9b6f3f80919 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 28 Jun 2022 14:57:57 +0100 Subject: [PATCH 195/275] Consolidate usage of NewErrorAcknowledgement (#1565) --- CHANGELOG.md | 3 + docs/migrations/v3-to-v4.md | 4 + .../controller/ibc_middleware.go | 5 +- .../controller/keeper/events.go | 31 +++++++ .../27-interchain-accounts/host/ibc_module.go | 4 +- .../host/ibc_module_test.go | 2 +- .../host/keeper/events.go | 14 +-- .../27-interchain-accounts/host/types/ack.go | 27 ------ .../host/types/ack_test.go | 19 ----- .../27-interchain-accounts/types/events.go | 7 +- modules/apps/transfer/ibc_module.go | 27 ++++-- .../apps/transfer/keeper/mbt_relay_test.go | 2 +- modules/apps/transfer/keeper/relay_test.go | 2 +- modules/apps/transfer/types/ack.go | 27 ------ modules/apps/transfer/types/ack_test.go | 71 ---------------- .../core/04-channel/types/acknowledgement.go | 15 +++- .../04-channel/types/acknowledgement_test.go | 85 +++++++++++++++++-- testing/mock/mock.go | 3 +- 18 files changed, 173 insertions(+), 175 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/controller/keeper/events.go delete mode 100644 modules/apps/27-interchain-accounts/host/types/ack.go delete mode 100644 modules/apps/transfer/types/ack.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 281715f19ca..900ef224f5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/29-fee)[\#1338](https://github.com/cosmos/ibc-go/pull/1338) Renaming `Result` field in `IncentivizedAcknowledgement` to `AppAcknowledgement`. * (modules/29-fee)[\#1343](https://github.com/cosmos/ibc-go/pull/1343) Renaming `KeyForwardRelayerAddress` to `KeyRelayerAddressForAsyncAck`, and `ParseKeyForwardRelayerAddress` to `ParseKeyRelayerAddressForAsyncAck`. * (apps/27-interchain-accounts)[\#1432](https://github.com/cosmos/ibc-go/pull/1432) Updating `RegisterInterchainAccount` to include an additional `version` argument, supporting ICS29 fee middleware functionality in ICS27 interchain accounts. +* (apps/27-interchain-accounts)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Removing `NewErrorAcknowledgement` in favour of `channeltypes.NewErrorAcknowledgement`. +* (transfer)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Removing `NewErrorAcknowledgement` in favour of `channeltypes.NewErrorAcknowledgement`. +* (channel)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Updating `NewErrorAcknowledgement` to accept an error instead of a string and removing the possibility of non-deterministic writes to application state. ### State Machine Breaking diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 1cd08f5bd49..903c027ce4b 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -26,6 +26,10 @@ This is an API breaking change and as such IBC application developers will have The `OnChanOpenInit` application callback has been modified. The return signature now includes the application version as detailed in the latest IBC [spec changes](https://github.com/cosmos/ibc/pull/629). +The `NewErrorAcknowledgement` method signature has changed. +It now accepts an `error` rather than a `string`. This was done in order to prevent accidental state changes. +All error acknowledgements now contain a deterministic ABCI code and error message. It is the responsibility of the application developer to emit error details in events. + ### ICS27 - Interchain Accounts The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index b7c65874bfa..cbcafbd248c 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -138,7 +138,10 @@ func (im IBCMiddleware) OnRecvPacket( packet channeltypes.Packet, _ sdk.AccAddress, ) ibcexported.Acknowledgement { - return channeltypes.NewErrorAcknowledgement("cannot receive packet on controller chain") + err := sdkerrors.Wrapf(icatypes.ErrInvalidChannelFlow, "cannot receive packet on controller chain") + ack := channeltypes.NewErrorAcknowledgement(err) + keeper.EmitAcknowledgementEvent(ctx, packet, ack, err) + return ack } // OnAcknowledgementPacket implements the IBCMiddleware interface diff --git a/modules/apps/27-interchain-accounts/controller/keeper/events.go b/modules/apps/27-interchain-accounts/controller/keeper/events.go new file mode 100644 index 00000000000..3c820c74cb0 --- /dev/null +++ b/modules/apps/27-interchain-accounts/controller/keeper/events.go @@ -0,0 +1,31 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v3/modules/core/exported" +) + +// EmitAcknowledgementEvent emits an event signalling a successful or failed acknowledgement and including the error +// details if any. +func EmitAcknowledgementEvent(ctx sdk.Context, packet exported.PacketI, ack exported.Acknowledgement, err error) { + attributes := []sdk.Attribute{ + sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), + sdk.NewAttribute(icatypes.AttributeKeyControllerChannelID, packet.GetDestChannel()), + sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), + } + + if err != nil { + attributes = append(attributes, sdk.NewAttribute(icatypes.AttributeKeyAckError, err.Error())) + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + icatypes.EventTypePacket, + attributes..., + ), + ) +} diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 2e1ba8e0805..6e77c464afe 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -106,13 +106,13 @@ func (im IBCModule) OnRecvPacket( _ sdk.AccAddress, ) ibcexported.Acknowledgement { if !im.keeper.IsHostEnabled(ctx) { - return types.NewErrorAcknowledgement(types.ErrHostSubModuleDisabled) + return channeltypes.NewErrorAcknowledgement(types.ErrHostSubModuleDisabled) } txResponse, err := im.keeper.OnRecvPacket(ctx, packet) ack := channeltypes.NewResultAcknowledgement(txResponse) if err != nil { - ack = types.NewErrorAcknowledgement(err) + ack = channeltypes.NewErrorAcknowledgement(err) } // Emit an event indicating a successful or failed acknowledgement. diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 78a21cfee01..ea602e89b4a 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -403,7 +403,7 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { suite.chainB.GetSimApp().ICAAuthModule.IBCApp.OnRecvPacket = func( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, ) exported.Acknowledgement { - return channeltypes.NewErrorAcknowledgement("failed OnRecvPacket mock callback") + return channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed OnRecvPacket mock callback")) } }, true, }, diff --git a/modules/apps/27-interchain-accounts/host/keeper/events.go b/modules/apps/27-interchain-accounts/host/keeper/events.go index 116fb1cc3f7..2429acf18a3 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/events.go +++ b/modules/apps/27-interchain-accounts/host/keeper/events.go @@ -10,18 +10,20 @@ import ( // EmitAcknowledgementEvent emits an event signalling a successful or failed acknowledgement and including the error // details if any. func EmitAcknowledgementEvent(ctx sdk.Context, packet exported.PacketI, ack exported.Acknowledgement, err error) { - var errorMsg string + attributes := []sdk.Attribute{ + sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), + sdk.NewAttribute(icatypes.AttributeKeyHostChannelID, packet.GetDestChannel()), + sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), + } + if err != nil { - errorMsg = err.Error() + attributes = append(attributes, sdk.NewAttribute(icatypes.AttributeKeyAckError, err.Error())) } ctx.EventManager().EmitEvent( sdk.NewEvent( icatypes.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), - sdk.NewAttribute(icatypes.AttributeKeyAckError, errorMsg), - sdk.NewAttribute(icatypes.AttributeKeyHostChannelID, packet.GetDestChannel()), - sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), + attributes..., ), ) } diff --git a/modules/apps/27-interchain-accounts/host/types/ack.go b/modules/apps/27-interchain-accounts/host/types/ack.go deleted file mode 100644 index 202404fff3a..00000000000 --- a/modules/apps/27-interchain-accounts/host/types/ack.go +++ /dev/null @@ -1,27 +0,0 @@ -package types - -import ( - "fmt" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" -) - -const ( - // ackErrorString defines a string constant included in error acknowledgements - // NOTE: Changing this const is state machine breaking as acknowledgements are written into state - ackErrorString = "error handling packet on host chain: see events for details" -) - -// NewErrorAcknowledgement returns a deterministic error string which may be used in -// the packet acknowledgement. -func NewErrorAcknowledgement(err error) channeltypes.Acknowledgement { - // the ABCI code is included in the abcitypes.ResponseDeliverTx hash - // constructed in Tendermint and is therefore determinstic - _, code, _ := sdkerrors.ABCIInfo(err, false) // discard non-deterministic codespace and log values - - errorString := fmt.Sprintf("ABCI code: %d: %s", code, ackErrorString) - - return channeltypes.NewErrorAcknowledgement(errorString) -} diff --git a/modules/apps/27-interchain-accounts/host/types/ack_test.go b/modules/apps/27-interchain-accounts/host/types/ack_test.go index 6d2e6d1a95a..06cab3e0cc0 100644 --- a/modules/apps/27-interchain-accounts/host/types/ack_test.go +++ b/modules/apps/27-interchain-accounts/host/types/ack_test.go @@ -9,7 +9,6 @@ import ( tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" tmstate "github.com/tendermint/tendermint/state" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" ) @@ -80,21 +79,3 @@ func (suite *TypesTestSuite) TestABCICodeDeterminism() { suite.Require().Equal(hash, hashSameABCICode) suite.Require().NotEqual(hash, hashDifferentABCICode) } - -// TestAcknowledgementError will verify that only a constant string and -// ABCI error code are used in constructing the acknowledgement error string -func (suite *TypesTestSuite) TestAcknowledgementError() { - // same ABCI error code used - err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1") - errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2") - - // different ABCI error code used - errDifferentABCICode := sdkerrors.ErrNotFound - - ack := types.NewErrorAcknowledgement(err) - ackSameABCICode := types.NewErrorAcknowledgement(errSameABCICode) - ackDifferentABCICode := types.NewErrorAcknowledgement(errDifferentABCICode) - - suite.Require().Equal(ack, ackSameABCICode) - suite.Require().NotEqual(ack, ackDifferentABCICode) -} diff --git a/modules/apps/27-interchain-accounts/types/events.go b/modules/apps/27-interchain-accounts/types/events.go index 9bfd1df3049..3ca4b783b55 100644 --- a/modules/apps/27-interchain-accounts/types/events.go +++ b/modules/apps/27-interchain-accounts/types/events.go @@ -4,7 +4,8 @@ package types const ( EventTypePacket = "ics27_packet" - AttributeKeyAckError = "error" - AttributeKeyHostChannelID = "host_channel_id" - AttributeKeyAckSuccess = "success" + AttributeKeyAckError = "error" + AttributeKeyHostChannelID = "host_channel_id" + AttributeKeyControllerChannelID = "controller_channel_id" + AttributeKeyAckSuccess = "success" ) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 07469622bfc..d79ec986aab 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -9,6 +9,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -178,8 +179,10 @@ func (im IBCModule) OnRecvPacket( ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) var data types.FungibleTokenPacketData + var ackErr error if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - ack = channeltypes.NewErrorAcknowledgement("cannot unmarshal ICS-20 transfer packet data") + ackErr = sdkerrors.Wrapf(icatypes.ErrInvalidChannelFlow, "cannot unmarshal ICS-20 transfer packet data") + ack = channeltypes.NewErrorAcknowledgement(ackErr) } // only attempt the application logic if the packet data @@ -187,19 +190,27 @@ func (im IBCModule) OnRecvPacket( if ack.Success() { err := im.keeper.OnRecvPacket(ctx, packet, data) if err != nil { - ack = types.NewErrorAcknowledgement(err) + ack = channeltypes.NewErrorAcknowledgement(err) + ackErr = err } } + eventAttributes := []sdk.Attribute{ + sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), + sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), + sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), + sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), + } + + if ackErr != nil { + eventAttributes = append(eventAttributes, sdk.NewAttribute(types.AttributeKeyAckError, ackErr.Error())) + } + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), - sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), - sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), - sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), + eventAttributes..., ), ) diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 59e4869e54e..4366101f932 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -360,7 +360,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { registerDenom() err = suite.chainB.GetSimApp().TransferKeeper.OnAcknowledgementPacket( suite.chainB.GetContext(), packet, tc.packet.Data, - channeltypes.NewErrorAcknowledgement("MBT Error Acknowledgement")) + channeltypes.NewErrorAcknowledgement(fmt.Errorf("MBT Error Acknowledgement"))) default: err = fmt.Errorf("Unknown handler: %s", tc.handler) } diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 3ad851b587e..d9d6f8a68c7 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -255,7 +255,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { var ( successAck = channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - failedAck = channeltypes.NewErrorAcknowledgement("failed packet transfer") + failedAck = channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed packet transfer")) trace types.DenomTrace amount sdk.Int path *ibctesting.Path diff --git a/modules/apps/transfer/types/ack.go b/modules/apps/transfer/types/ack.go deleted file mode 100644 index 6512f2e8371..00000000000 --- a/modules/apps/transfer/types/ack.go +++ /dev/null @@ -1,27 +0,0 @@ -package types - -import ( - "fmt" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" -) - -const ( - // ackErrorString defines a string constant included in error acknowledgements - // NOTE: Changing this const is state machine breaking as acknowledgements are written into state - ackErrorString = "error handling packet on destination chain: see events for details" -) - -// NewErrorAcknowledgement returns a deterministic error string which may be used in -// the packet acknowledgement. -func NewErrorAcknowledgement(err error) channeltypes.Acknowledgement { - // the ABCI code is included in the abcitypes.ResponseDeliverTx hash - // constructed in Tendermint and is therefore deterministic - _, code, _ := sdkerrors.ABCIInfo(err, false) // discard non-determinstic codespace and log values - - errorString := fmt.Sprintf("ABCI code: %d: %s", code, ackErrorString) - - return channeltypes.NewErrorAcknowledgement(errorString) -} diff --git a/modules/apps/transfer/types/ack_test.go b/modules/apps/transfer/types/ack_test.go index ffc09da981e..2fc13a3290e 100644 --- a/modules/apps/transfer/types/ack_test.go +++ b/modules/apps/transfer/types/ack_test.go @@ -3,21 +3,11 @@ package types_test import ( "testing" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/suite" - abcitypes "github.com/tendermint/tendermint/abci/types" - tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" - tmstate "github.com/tendermint/tendermint/state" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" ) -const ( - gasUsed = uint64(100) - gasWanted = uint64(100) -) - type TypesTestSuite struct { suite.Suite @@ -37,64 +27,3 @@ func (suite *TypesTestSuite) SetupTest() { func TestTypesTestSuite(t *testing.T) { suite.Run(t, new(TypesTestSuite)) } - -// The safety of including ABCI error codes in the acknowledgement rests -// on the inclusion of these ABCI error codes in the abcitypes.ResposneDeliverTx -// hash. If the ABCI codes get removed from consensus they must no longer be used -// in the packet acknowledgement. -// -// This test acts as an indicator that the ABCI error codes may no longer be deterministic. -func (suite *TypesTestSuite) TestABCICodeDeterminism() { - // same ABCI error code used - err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1") - errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2") - - // different ABCI error code used - errDifferentABCICode := sdkerrors.ErrNotFound - - deliverTx := sdkerrors.ResponseDeliverTx(err, gasUsed, gasWanted, false) - responses := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTx, - }, - } - - deliverTxSameABCICode := sdkerrors.ResponseDeliverTx(errSameABCICode, gasUsed, gasWanted, false) - responsesSameABCICode := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTxSameABCICode, - }, - } - - deliverTxDifferentABCICode := sdkerrors.ResponseDeliverTx(errDifferentABCICode, gasUsed, gasWanted, false) - responsesDifferentABCICode := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTxDifferentABCICode, - }, - } - - hash := tmstate.ABCIResponsesResultsHash(&responses) - hashSameABCICode := tmstate.ABCIResponsesResultsHash(&responsesSameABCICode) - hashDifferentABCICode := tmstate.ABCIResponsesResultsHash(&responsesDifferentABCICode) - - suite.Require().Equal(hash, hashSameABCICode) - suite.Require().NotEqual(hash, hashDifferentABCICode) -} - -// TestAcknowledgementError will verify that only a constant string and -// ABCI error code are used in constructing the acknowledgement error string -func (suite *TypesTestSuite) TestAcknowledgementError() { - // same ABCI error code used - err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1") - errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2") - - // different ABCI error code used - errDifferentABCICode := sdkerrors.ErrNotFound - - ack := types.NewErrorAcknowledgement(err) - ackSameABCICode := types.NewErrorAcknowledgement(errSameABCICode) - ackDifferentABCICode := types.NewErrorAcknowledgement(errDifferentABCICode) - - suite.Require().Equal(ack, ackSameABCICode) - suite.Require().NotEqual(ack, ackDifferentABCICode) -} diff --git a/modules/core/04-channel/types/acknowledgement.go b/modules/core/04-channel/types/acknowledgement.go index b46de2b981d..49c795d0d55 100644 --- a/modules/core/04-channel/types/acknowledgement.go +++ b/modules/core/04-channel/types/acknowledgement.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "reflect" "strings" @@ -8,6 +9,12 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +const ( + // ackErrorString defines a string constant included in error acknowledgements + // NOTE: Changing this const is state machine breaking as acknowledgements are written into state. + ackErrorString = "error handling packet: see events for details" +) + // NewResultAcknowledgement returns a new instance of Acknowledgement using an Acknowledgement_Result // type in the Response field. func NewResultAcknowledgement(result []byte) Acknowledgement { @@ -22,10 +29,14 @@ func NewResultAcknowledgement(result []byte) Acknowledgement { // type in the Response field. // NOTE: Acknowledgements are written into state and thus, changes made to error strings included in packet acknowledgements // risk an app hash divergence when nodes in a network are running different patch versions of software. -func NewErrorAcknowledgement(err string) Acknowledgement { +func NewErrorAcknowledgement(err error) Acknowledgement { + // the ABCI code is included in the abcitypes.ResponseDeliverTx hash + // constructed in Tendermint and is therefore deterministic + _, code, _ := sdkerrors.ABCIInfo(err, false) // discard non-determinstic codespace and log values + return Acknowledgement{ Response: &Acknowledgement_Error{ - Error: err, + Error: fmt.Sprintf("ABCI code: %d: %s", code, ackErrorString), }, } } diff --git a/modules/core/04-channel/types/acknowledgement_test.go b/modules/core/04-channel/types/acknowledgement_test.go index 658ff31a8b5..530d288bb32 100644 --- a/modules/core/04-channel/types/acknowledgement_test.go +++ b/modules/core/04-channel/types/acknowledgement_test.go @@ -1,6 +1,20 @@ package types_test -import "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" +import ( + "fmt" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + abcitypes "github.com/tendermint/tendermint/abci/types" + tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" + tmstate "github.com/tendermint/tendermint/state" + + "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" +) + +const ( + gasUsed = uint64(100) + gasWanted = uint64(100) +) // tests acknowledgement.ValidateBasic and acknowledgement.GetBytes func (suite TypesTestSuite) TestAcknowledgement() { @@ -18,7 +32,7 @@ func (suite TypesTestSuite) TestAcknowledgement() { }, { "valid failed ack", - types.NewErrorAcknowledgement("error"), + types.NewErrorAcknowledgement(fmt.Errorf("error")), false, true, }, @@ -29,10 +43,10 @@ func (suite TypesTestSuite) TestAcknowledgement() { false, }, { - "empty faied ack", - types.NewErrorAcknowledgement(" "), - false, + "empty failed ack", + types.NewErrorAcknowledgement(fmt.Errorf(" ")), false, + true, }, { "nil response", @@ -68,3 +82,64 @@ func (suite TypesTestSuite) TestAcknowledgement() { }) } } + +// The safety of including ABCI error codes in the acknowledgement rests +// on the inclusion of these ABCI error codes in the abcitypes.ResposneDeliverTx +// hash. If the ABCI codes get removed from consensus they must no longer be used +// in the packet acknowledgement. +// +// This test acts as an indicator that the ABCI error codes may no longer be deterministic. +func (suite *TypesTestSuite) TestABCICodeDeterminism() { + // same ABCI error code used + err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1") + errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2") + + // different ABCI error code used + errDifferentABCICode := sdkerrors.ErrNotFound + + deliverTx := sdkerrors.ResponseDeliverTx(err, gasUsed, gasWanted, false) + responses := tmprotostate.ABCIResponses{ + DeliverTxs: []*abcitypes.ResponseDeliverTx{ + &deliverTx, + }, + } + + deliverTxSameABCICode := sdkerrors.ResponseDeliverTx(errSameABCICode, gasUsed, gasWanted, false) + responsesSameABCICode := tmprotostate.ABCIResponses{ + DeliverTxs: []*abcitypes.ResponseDeliverTx{ + &deliverTxSameABCICode, + }, + } + + deliverTxDifferentABCICode := sdkerrors.ResponseDeliverTx(errDifferentABCICode, gasUsed, gasWanted, false) + responsesDifferentABCICode := tmprotostate.ABCIResponses{ + DeliverTxs: []*abcitypes.ResponseDeliverTx{ + &deliverTxDifferentABCICode, + }, + } + + hash := tmstate.ABCIResponsesResultsHash(&responses) + hashSameABCICode := tmstate.ABCIResponsesResultsHash(&responsesSameABCICode) + hashDifferentABCICode := tmstate.ABCIResponsesResultsHash(&responsesDifferentABCICode) + + suite.Require().Equal(hash, hashSameABCICode) + suite.Require().NotEqual(hash, hashDifferentABCICode) +} + +// TestAcknowledgementError will verify that only a constant string and +// ABCI error code are used in constructing the acknowledgement error string +func (suite *TypesTestSuite) TestAcknowledgementError() { + // same ABCI error code used + err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1") + errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2") + + // different ABCI error code used + errDifferentABCICode := sdkerrors.ErrNotFound + + ack := types.NewErrorAcknowledgement(err) + ackSameABCICode := types.NewErrorAcknowledgement(errSameABCICode) + ackDifferentABCICode := types.NewErrorAcknowledgement(errDifferentABCICode) + + suite.Require().Equal(ack, ackSameABCICode) + suite.Require().NotEqual(ack, ackDifferentABCICode) +} diff --git a/testing/mock/mock.go b/testing/mock/mock.go index b621a05e9f7..a4ac465353d 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -2,6 +2,7 @@ package mock import ( "encoding/json" + "fmt" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" @@ -28,7 +29,7 @@ const ( var ( MockAcknowledgement = channeltypes.NewResultAcknowledgement([]byte("mock acknowledgement")) - MockFailAcknowledgement = channeltypes.NewErrorAcknowledgement("mock failed acknowledgement") + MockFailAcknowledgement = channeltypes.NewErrorAcknowledgement(fmt.Errorf("mock failed acknowledgement")) MockPacketData = []byte("mock packet data") MockFailPacketData = []byte("mock failed packet data") MockAsyncPacketData = []byte("mock async packet data") From f283d1241a11967ab2fb86b3db83905c47fd6153 Mon Sep 17 00:00:00 2001 From: Sean King Date: Tue, 28 Jun 2022 22:04:41 +0200 Subject: [PATCH 196/275] docs: adding line about module accounts / invariants (#1597) * docs: adding line about module accounts / invariants * Update docs/middleware/ics29-fee/fee-distribution.md Co-authored-by: Damian Nolan * Update docs/middleware/ics29-fee/fee-distribution.md Co-authored-by: Damian Nolan Co-authored-by: Damian Nolan --- docs/middleware/ics29-fee/fee-distribution.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/middleware/ics29-fee/fee-distribution.md b/docs/middleware/ics29-fee/fee-distribution.md index 0ca1bce921f..9cf3a821a21 100644 --- a/docs/middleware/ics29-fee/fee-distribution.md +++ b/docs/middleware/ics29-fee/fee-distribution.md @@ -27,6 +27,8 @@ If a counterparty payee is not registered for the forward relayer on the destina A transaction must be submitted to the destination chain including a `CounterpartyPayee` address of an account on the source chain. The transaction must be signed by the `Relayer`. +Note: If a module account address is used as the `CounterpartyPayee` it is recommended to [turn off invariant checks](https://github.com/cosmos/ibc-go/blob/71d7480c923f4227453e8a80f51be01ae7ee845e/testing/simapp/app.go#L659) for that module. + ```go type MsgRegisterCounterpartyPayee struct { // unique port identifier @@ -63,6 +65,8 @@ If a payee is not registered for the reverse or timeout relayer on the source ch A transaction must be submitted to the source chain including a `Payee` address of an account on the source chain. The transaction must be signed by the `Relayer`. +Note: If a module account address is used as the `Payee` it is recommended to [turn off invariant checks](https://github.com/cosmos/ibc-go/blob/71d7480c923f4227453e8a80f51be01ae7ee845e/testing/simapp/app.go#L659) for that module. + ```go type MsgRegisterPayee struct { // unique port identifier From ecf354399280a1ad3c6160bce0ff20a903357d2e Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 29 Jun 2022 15:05:28 +0200 Subject: [PATCH 197/275] follow up nits to #1565 (#1598) * delete test files and add error to transfer types * review comments --- .../host/types/ack_test.go | 81 ------------------- modules/apps/transfer/ibc_module.go | 3 +- modules/apps/transfer/types/ack_test.go | 29 ------- 3 files changed, 1 insertion(+), 112 deletions(-) delete mode 100644 modules/apps/27-interchain-accounts/host/types/ack_test.go delete mode 100644 modules/apps/transfer/types/ack_test.go diff --git a/modules/apps/27-interchain-accounts/host/types/ack_test.go b/modules/apps/27-interchain-accounts/host/types/ack_test.go deleted file mode 100644 index 06cab3e0cc0..00000000000 --- a/modules/apps/27-interchain-accounts/host/types/ack_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package types_test - -import ( - "testing" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/stretchr/testify/suite" - abcitypes "github.com/tendermint/tendermint/abci/types" - tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" - tmstate "github.com/tendermint/tendermint/state" - - ibctesting "github.com/cosmos/ibc-go/v3/testing" -) - -const ( - gasUsed = uint64(100) - gasWanted = uint64(100) -) - -type TypesTestSuite struct { - suite.Suite - - coordinator *ibctesting.Coordinator - - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain -} - -func (suite *TypesTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) - - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) -} - -func TestTypesTestSuite(t *testing.T) { - suite.Run(t, new(TypesTestSuite)) -} - -// The safety of including ABCI error codes in the acknowledgement rests -// on the inclusion of these ABCI error codes in the abcitypes.ResposneDeliverTx -// hash. If the ABCI codes get removed from consensus they must no longer be used -// in the packet acknowledgement. -// -// This test acts as an indicator that the ABCI error codes may no longer be deterministic. -func (suite *TypesTestSuite) TestABCICodeDeterminism() { - // same ABCI error code used - err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1") - errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2") - - // different ABCI error code used - errDifferentABCICode := sdkerrors.ErrNotFound - - deliverTx := sdkerrors.ResponseDeliverTx(err, gasUsed, gasWanted, false) - responses := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTx, - }, - } - - deliverTxSameABCICode := sdkerrors.ResponseDeliverTx(errSameABCICode, gasUsed, gasWanted, false) - responsesSameABCICode := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTxSameABCICode, - }, - } - - deliverTxDifferentABCICode := sdkerrors.ResponseDeliverTx(errDifferentABCICode, gasUsed, gasWanted, false) - responsesDifferentABCICode := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTxDifferentABCICode, - }, - } - - hash := tmstate.ABCIResponsesResultsHash(&responses) - hashSameABCICode := tmstate.ABCIResponsesResultsHash(&responsesSameABCICode) - hashDifferentABCICode := tmstate.ABCIResponsesResultsHash(&responsesDifferentABCICode) - - suite.Require().Equal(hash, hashSameABCICode) - suite.Require().NotEqual(hash, hashDifferentABCICode) -} diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index d79ec986aab..1e5f56280ce 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -9,7 +9,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" @@ -181,7 +180,7 @@ func (im IBCModule) OnRecvPacket( var data types.FungibleTokenPacketData var ackErr error if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - ackErr = sdkerrors.Wrapf(icatypes.ErrInvalidChannelFlow, "cannot unmarshal ICS-20 transfer packet data") + ackErr = sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") ack = channeltypes.NewErrorAcknowledgement(ackErr) } diff --git a/modules/apps/transfer/types/ack_test.go b/modules/apps/transfer/types/ack_test.go deleted file mode 100644 index 2fc13a3290e..00000000000 --- a/modules/apps/transfer/types/ack_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/stretchr/testify/suite" - - ibctesting "github.com/cosmos/ibc-go/v3/testing" -) - -type TypesTestSuite struct { - suite.Suite - - coordinator *ibctesting.Coordinator - - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain -} - -func (suite *TypesTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) - - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) -} - -func TestTypesTestSuite(t *testing.T) { - suite.Run(t, new(TypesTestSuite)) -} From d170a41de0051e71dff3f27a097328f8b649345f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Jun 2022 21:34:30 +0200 Subject: [PATCH 198/275] build(deps): bump github.com/stretchr/testify from 1.7.5 to 1.8.0 (#1616) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.5 to 1.8.0. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.7.5...v1.8.0) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7b9443ade4d..29861465660 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.12.0 - github.com/stretchr/testify v1.7.5 + github.com/stretchr/testify v1.8.0 github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd diff --git a/go.sum b/go.sum index 05c8bcbda2f..f85c6414a09 100644 --- a/go.sum +++ b/go.sum @@ -972,8 +972,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q= -github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= From 48a6ae512b4ea42c29fdf6c6f5363f50645591a2 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 29 Jun 2022 22:39:27 +0200 Subject: [PATCH 199/275] chore: bump go package version to v4 (#1564) * chore: bump go package version to v4 * update go.mod * fix alignment * fix build * review comments * build fixes --- .../adr-002-go-module-versioning.md | 2 +- go.mod | 4 +- go.sum | 3 +- .../27-interchain-accounts/client/cli/cli.go | 4 +- .../controller/client/cli/query.go | 2 +- .../controller/ibc_middleware.go | 12 +- .../controller/ibc_middleware_test.go | 14 +- .../controller/keeper/account.go | 6 +- .../controller/keeper/account_test.go | 8 +- .../controller/keeper/events.go | 6 +- .../controller/keeper/genesis.go | 4 +- .../controller/keeper/genesis_test.go | 8 +- .../controller/keeper/grpc_query.go | 2 +- .../controller/keeper/grpc_query_test.go | 2 +- .../controller/keeper/handshake.go | 4 +- .../controller/keeper/handshake_test.go | 8 +- .../controller/keeper/keeper.go | 8 +- .../controller/keeper/keeper_test.go | 6 +- .../controller/keeper/params.go | 2 +- .../controller/keeper/params_test.go | 2 +- .../controller/keeper/relay.go | 6 +- .../controller/keeper/relay_test.go | 10 +- .../controller/types/controller.pb.go | 4 +- .../controller/types/params_test.go | 2 +- .../controller/types/query.pb.go | 14 +- .../host/client/cli/query.go | 8 +- .../27-interchain-accounts/host/ibc_module.go | 10 +- .../host/ibc_module_test.go | 14 +- .../host/keeper/account.go | 2 +- .../host/keeper/account_test.go | 4 +- .../host/keeper/events.go | 6 +- .../host/keeper/genesis.go | 4 +- .../host/keeper/genesis_test.go | 8 +- .../host/keeper/grpc_query.go | 2 +- .../host/keeper/grpc_query_test.go | 2 +- .../host/keeper/handshake.go | 6 +- .../host/keeper/handshake_test.go | 8 +- .../host/keeper/keeper.go | 8 +- .../host/keeper/keeper_test.go | 6 +- .../host/keeper/params.go | 2 +- .../host/keeper/params_test.go | 2 +- .../host/keeper/relay.go | 6 +- .../host/keeper/relay_test.go | 12 +- .../host/types/ack_test.go | 81 ++++++++ .../host/types/host.pb.go | 4 +- .../host/types/params_test.go | 2 +- .../host/types/query.pb.go | 42 ++-- modules/apps/27-interchain-accounts/module.go | 18 +- .../27-interchain-accounts/module_test.go | 12 +- .../types/account.pb.go | 6 +- .../types/account_test.go | 4 +- .../types/codec_test.go | 4 +- .../types/expected_keepers.go | 4 +- .../27-interchain-accounts/types/genesis.go | 6 +- .../types/genesis.pb.go | 88 ++++----- .../types/genesis_test.go | 8 +- .../27-interchain-accounts/types/keys_test.go | 2 +- .../27-interchain-accounts/types/metadata.go | 2 +- .../types/metadata.pb.go | 40 ++-- .../types/metadata_test.go | 4 +- .../27-interchain-accounts/types/packet.pb.go | 42 ++-- .../types/packet_test.go | 2 +- .../27-interchain-accounts/types/port_test.go | 4 +- modules/apps/29-fee/client/cli/query.go | 4 +- modules/apps/29-fee/client/cli/tx.go | 4 +- modules/apps/29-fee/fee_test.go | 10 +- modules/apps/29-fee/ibc_middleware.go | 10 +- modules/apps/29-fee/ibc_middleware_test.go | 16 +- modules/apps/29-fee/ica_test.go | 12 +- modules/apps/29-fee/keeper/escrow.go | 4 +- modules/apps/29-fee/keeper/escrow_test.go | 9 +- modules/apps/29-fee/keeper/events.go | 4 +- modules/apps/29-fee/keeper/events_test.go | 2 +- modules/apps/29-fee/keeper/genesis.go | 2 +- modules/apps/29-fee/keeper/genesis_test.go | 6 +- modules/apps/29-fee/keeper/grpc_query.go | 2 +- modules/apps/29-fee/keeper/grpc_query_test.go | 6 +- modules/apps/29-fee/keeper/keeper.go | 6 +- modules/apps/29-fee/keeper/keeper_test.go | 8 +- modules/apps/29-fee/keeper/msg_server.go | 4 +- modules/apps/29-fee/keeper/msg_server_test.go | 10 +- modules/apps/29-fee/keeper/relay.go | 6 +- modules/apps/29-fee/keeper/relay_test.go | 10 +- modules/apps/29-fee/module.go | 6 +- modules/apps/29-fee/transfer_test.go | 8 +- modules/apps/29-fee/types/ack.pb.go | 44 ++--- modules/apps/29-fee/types/expected_keepers.go | 4 +- modules/apps/29-fee/types/fee.go | 2 +- modules/apps/29-fee/types/fee.pb.go | 32 +-- modules/apps/29-fee/types/fee_test.go | 2 +- modules/apps/29-fee/types/genesis.go | 2 +- modules/apps/29-fee/types/genesis.pb.go | 86 ++++---- modules/apps/29-fee/types/genesis_test.go | 6 +- modules/apps/29-fee/types/keys.go | 2 +- modules/apps/29-fee/types/keys_test.go | 6 +- modules/apps/29-fee/types/metadata.pb.go | 4 +- modules/apps/29-fee/types/msgs.go | 4 +- modules/apps/29-fee/types/msgs_test.go | 6 +- modules/apps/29-fee/types/query.pb.go | 172 ++++++++-------- modules/apps/29-fee/types/tx.pb.go | 92 ++++----- modules/apps/transfer/client/cli/query.go | 2 +- modules/apps/transfer/client/cli/tx.go | 6 +- modules/apps/transfer/ibc_module.go | 12 +- modules/apps/transfer/ibc_module_test.go | 10 +- modules/apps/transfer/keeper/encoding.go | 2 +- modules/apps/transfer/keeper/genesis.go | 2 +- modules/apps/transfer/keeper/genesis_test.go | 2 +- modules/apps/transfer/keeper/grpc_query.go | 2 +- .../apps/transfer/keeper/grpc_query_test.go | 4 +- modules/apps/transfer/keeper/keeper.go | 4 +- modules/apps/transfer/keeper/keeper_test.go | 4 +- .../apps/transfer/keeper/mbt_relay_test.go | 8 +- modules/apps/transfer/keeper/msg_server.go | 2 +- modules/apps/transfer/keeper/params.go | 2 +- modules/apps/transfer/keeper/params_test.go | 2 +- modules/apps/transfer/keeper/relay.go | 10 +- modules/apps/transfer/keeper/relay_test.go | 12 +- modules/apps/transfer/module.go | 10 +- modules/apps/transfer/simulation/decoder.go | 2 +- .../apps/transfer/simulation/decoder_test.go | 6 +- modules/apps/transfer/simulation/genesis.go | 2 +- .../apps/transfer/simulation/genesis_test.go | 4 +- modules/apps/transfer/simulation/params.go | 2 +- .../apps/transfer/simulation/params_test.go | 2 +- modules/apps/transfer/transfer_test.go | 6 +- modules/apps/transfer/types/ack_test.go | 29 +++ .../apps/transfer/types/expected_keepers.go | 6 +- modules/apps/transfer/types/genesis.go | 2 +- modules/apps/transfer/types/genesis.pb.go | 36 ++-- modules/apps/transfer/types/genesis_test.go | 2 +- modules/apps/transfer/types/keys_test.go | 2 +- modules/apps/transfer/types/msgs.go | 4 +- modules/apps/transfer/types/msgs_test.go | 2 +- modules/apps/transfer/types/packet.pb.go | 28 +-- modules/apps/transfer/types/query.pb.go | 4 +- modules/apps/transfer/types/trace.go | 2 +- modules/apps/transfer/types/transfer.pb.go | 34 ++-- modules/apps/transfer/types/tx.pb.go | 60 +++--- modules/core/02-client/abci.go | 6 +- modules/core/02-client/abci_test.go | 12 +- modules/core/02-client/client/cli/cli.go | 2 +- modules/core/02-client/client/cli/query.go | 6 +- modules/core/02-client/client/cli/tx.go | 4 +- .../core/02-client/client/proposal_handler.go | 2 +- modules/core/02-client/client/utils/utils.go | 12 +- modules/core/02-client/genesis.go | 6 +- modules/core/02-client/keeper/client.go | 4 +- modules/core/02-client/keeper/client_test.go | 16 +- modules/core/02-client/keeper/encoding.go | 4 +- modules/core/02-client/keeper/events.go | 4 +- modules/core/02-client/keeper/grpc_query.go | 6 +- .../core/02-client/keeper/grpc_query_test.go | 8 +- modules/core/02-client/keeper/keeper.go | 10 +- modules/core/02-client/keeper/keeper_test.go | 18 +- modules/core/02-client/keeper/migrations.go | 2 +- modules/core/02-client/keeper/params.go | 2 +- modules/core/02-client/keeper/params_test.go | 2 +- modules/core/02-client/keeper/proposal.go | 4 +- .../core/02-client/keeper/proposal_test.go | 8 +- modules/core/02-client/legacy/v100/genesis.go | 8 +- .../02-client/legacy/v100/genesis_test.go | 16 +- .../core/02-client/legacy/v100/solomachine.go | 2 +- .../02-client/legacy/v100/solomachine.pb.go | 172 ++++++++-------- modules/core/02-client/legacy/v100/store.go | 12 +- .../core/02-client/legacy/v100/store_test.go | 12 +- modules/core/02-client/module.go | 4 +- modules/core/02-client/proposal_handler.go | 4 +- .../core/02-client/proposal_handler_test.go | 8 +- modules/core/02-client/simulation/decoder.go | 6 +- .../core/02-client/simulation/decoder_test.go | 10 +- modules/core/02-client/simulation/genesis.go | 2 +- modules/core/02-client/types/client.go | 4 +- modules/core/02-client/types/client.pb.go | 84 ++++---- modules/core/02-client/types/client_test.go | 4 +- modules/core/02-client/types/codec.go | 2 +- modules/core/02-client/types/codec_test.go | 12 +- modules/core/02-client/types/encoding.go | 2 +- modules/core/02-client/types/encoding_test.go | 4 +- modules/core/02-client/types/events.go | 2 +- modules/core/02-client/types/genesis.go | 4 +- modules/core/02-client/types/genesis.pb.go | 64 +++--- modules/core/02-client/types/genesis_test.go | 16 +- modules/core/02-client/types/height.go | 2 +- modules/core/02-client/types/height_test.go | 2 +- modules/core/02-client/types/keys.go | 2 +- modules/core/02-client/types/keys_test.go | 2 +- modules/core/02-client/types/msgs.go | 4 +- modules/core/02-client/types/msgs_test.go | 12 +- modules/core/02-client/types/params.go | 2 +- modules/core/02-client/types/params_test.go | 2 +- modules/core/02-client/types/proposal.go | 2 +- modules/core/02-client/types/proposal_test.go | 6 +- modules/core/02-client/types/query.go | 2 +- modules/core/02-client/types/query.pb.go | 130 ++++++------ modules/core/02-client/types/tx.pb.go | 74 +++---- modules/core/03-connection/client/cli/cli.go | 2 +- .../core/03-connection/client/cli/query.go | 6 +- .../core/03-connection/client/utils/utils.go | 14 +- modules/core/03-connection/genesis.go | 4 +- modules/core/03-connection/keeper/events.go | 2 +- .../core/03-connection/keeper/grpc_query.go | 6 +- .../03-connection/keeper/grpc_query_test.go | 8 +- .../core/03-connection/keeper/handshake.go | 8 +- .../03-connection/keeper/handshake_test.go | 12 +- modules/core/03-connection/keeper/keeper.go | 10 +- .../core/03-connection/keeper/keeper_test.go | 4 +- modules/core/03-connection/keeper/params.go | 2 +- .../core/03-connection/keeper/params_test.go | 2 +- modules/core/03-connection/keeper/verify.go | 4 +- .../core/03-connection/keeper/verify_test.go | 16 +- modules/core/03-connection/module.go | 4 +- .../core/03-connection/simulation/decoder.go | 4 +- .../03-connection/simulation/decoder_test.go | 8 +- .../core/03-connection/simulation/genesis.go | 2 +- modules/core/03-connection/types/codec.go | 2 +- .../core/03-connection/types/connection.go | 6 +- .../core/03-connection/types/connection.pb.go | 95 ++++----- .../03-connection/types/connection_test.go | 8 +- modules/core/03-connection/types/events.go | 2 +- .../03-connection/types/expected_keepers.go | 2 +- modules/core/03-connection/types/genesis.go | 2 +- .../core/03-connection/types/genesis.pb.go | 48 ++--- .../core/03-connection/types/genesis_test.go | 6 +- modules/core/03-connection/types/keys.go | 2 +- modules/core/03-connection/types/keys_test.go | 2 +- modules/core/03-connection/types/msgs.go | 8 +- modules/core/03-connection/types/msgs_test.go | 12 +- .../core/03-connection/types/params_test.go | 2 +- modules/core/03-connection/types/query.go | 4 +- modules/core/03-connection/types/query.pb.go | 106 +++++----- modules/core/03-connection/types/tx.pb.go | 58 +++--- modules/core/03-connection/types/version.go | 2 +- .../core/03-connection/types/version_test.go | 6 +- modules/core/04-channel/client/cli/cli.go | 2 +- modules/core/04-channel/client/cli/query.go | 6 +- modules/core/04-channel/client/utils/utils.go | 12 +- modules/core/04-channel/genesis.go | 4 +- modules/core/04-channel/keeper/events.go | 4 +- modules/core/04-channel/keeper/grpc_query.go | 8 +- .../core/04-channel/keeper/grpc_query_test.go | 10 +- modules/core/04-channel/keeper/handshake.go | 10 +- .../core/04-channel/keeper/handshake_test.go | 12 +- modules/core/04-channel/keeper/keeper.go | 12 +- modules/core/04-channel/keeper/keeper_test.go | 6 +- modules/core/04-channel/keeper/packet.go | 10 +- modules/core/04-channel/keeper/packet_test.go | 16 +- modules/core/04-channel/keeper/timeout.go | 8 +- .../core/04-channel/keeper/timeout_test.go | 12 +- modules/core/04-channel/module.go | 4 +- modules/core/04-channel/simulation/decoder.go | 4 +- .../04-channel/simulation/decoder_test.go | 8 +- modules/core/04-channel/simulation/genesis.go | 2 +- .../04-channel/types/acknowledgement_test.go | 2 +- modules/core/04-channel/types/channel.go | 4 +- modules/core/04-channel/types/channel.pb.go | 114 +++++------ modules/core/04-channel/types/channel_test.go | 2 +- modules/core/04-channel/types/codec.go | 2 +- modules/core/04-channel/types/events.go | 2 +- .../core/04-channel/types/expected_keepers.go | 4 +- modules/core/04-channel/types/genesis.go | 2 +- modules/core/04-channel/types/genesis.pb.go | 62 +++--- modules/core/04-channel/types/genesis_test.go | 2 +- modules/core/04-channel/types/keys.go | 2 +- modules/core/04-channel/types/keys_test.go | 2 +- modules/core/04-channel/types/msgs.go | 6 +- modules/core/04-channel/types/msgs_test.go | 10 +- modules/core/04-channel/types/packet.go | 6 +- modules/core/04-channel/types/packet_test.go | 4 +- modules/core/04-channel/types/query.go | 4 +- modules/core/04-channel/types/query.pb.go | 186 +++++++++--------- modules/core/04-channel/types/tx.pb.go | 118 +++++------ modules/core/04-channel/types/version_test.go | 2 +- modules/core/05-port/keeper/keeper.go | 4 +- modules/core/05-port/keeper/keeper_test.go | 4 +- modules/core/05-port/module.go | 4 +- modules/core/05-port/types/module.go | 4 +- modules/core/05-port/types/query.pb.go | 2 +- modules/core/23-commitment/types/codec.go | 2 +- .../core/23-commitment/types/commitment.pb.go | 44 ++--- modules/core/23-commitment/types/merkle.go | 2 +- .../core/23-commitment/types/merkle_test.go | 2 +- .../core/23-commitment/types/utils_test.go | 2 +- modules/core/24-host/keys.go | 2 +- modules/core/24-host/parse_test.go | 4 +- modules/core/ante/ante.go | 6 +- modules/core/ante/ante_test.go | 12 +- modules/core/client/cli/cli.go | 8 +- modules/core/client/query.go | 6 +- modules/core/genesis.go | 10 +- modules/core/genesis_test.go | 22 +-- modules/core/keeper/grpc_query.go | 6 +- modules/core/keeper/keeper.go | 16 +- modules/core/keeper/keeper_test.go | 8 +- modules/core/keeper/migrations.go | 2 +- modules/core/keeper/msg_server.go | 10 +- modules/core/keeper/msg_server_test.go | 18 +- modules/core/legacy/v100/genesis.go | 10 +- modules/core/legacy/v100/genesis_test.go | 18 +- modules/core/module.go | 20 +- modules/core/simulation/decoder.go | 10 +- modules/core/simulation/decoder_test.go | 14 +- modules/core/simulation/genesis.go | 16 +- modules/core/simulation/genesis_test.go | 6 +- modules/core/types/codec.go | 14 +- modules/core/types/genesis.go | 6 +- modules/core/types/genesis.pb.go | 46 ++--- modules/core/types/query.go | 12 +- .../light-clients/06-solomachine/module.go | 2 +- .../06-solomachine/types/client_state.go | 8 +- .../06-solomachine/types/client_state_test.go | 16 +- .../06-solomachine/types/codec.go | 4 +- .../06-solomachine/types/codec_test.go | 10 +- .../06-solomachine/types/consensus_state.go | 4 +- .../types/consensus_state_test.go | 6 +- .../06-solomachine/types/header.go | 4 +- .../06-solomachine/types/header_test.go | 6 +- .../06-solomachine/types/misbehaviour.go | 6 +- .../types/misbehaviour_handle.go | 4 +- .../types/misbehaviour_handle_test.go | 8 +- .../06-solomachine/types/misbehaviour_test.go | 6 +- .../06-solomachine/types/proof.go | 10 +- .../06-solomachine/types/proof_test.go | 6 +- .../06-solomachine/types/proposal_handle.go | 4 +- .../types/proposal_handle_test.go | 8 +- .../06-solomachine/types/solomachine.go | 2 +- .../06-solomachine/types/solomachine.pb.go | 172 ++++++++-------- .../06-solomachine/types/solomachine_test.go | 8 +- .../06-solomachine/types/update.go | 4 +- .../06-solomachine/types/update_test.go | 8 +- modules/light-clients/07-tendermint/module.go | 2 +- .../07-tendermint/types/client_state.go | 12 +- .../07-tendermint/types/client_state_test.go | 16 +- .../07-tendermint/types/codec.go | 2 +- .../07-tendermint/types/consensus_state.go | 6 +- .../types/consensus_state_test.go | 6 +- .../07-tendermint/types/genesis.go | 4 +- .../07-tendermint/types/genesis_test.go | 6 +- .../07-tendermint/types/header.go | 6 +- .../07-tendermint/types/header_test.go | 6 +- .../07-tendermint/types/misbehaviour.go | 6 +- .../types/misbehaviour_handle.go | 4 +- .../types/misbehaviour_handle_test.go | 10 +- .../07-tendermint/types/misbehaviour_test.go | 10 +- .../07-tendermint/types/proposal_handle.go | 4 +- .../types/proposal_handle_test.go | 56 +++--- .../07-tendermint/types/store.go | 6 +- .../07-tendermint/types/store_test.go | 14 +- .../07-tendermint/types/tendermint.pb.go | 142 ++++++------- .../07-tendermint/types/tendermint_test.go | 10 +- .../07-tendermint/types/update.go | 6 +- .../07-tendermint/types/update_test.go | 12 +- .../07-tendermint/types/upgrade.go | 6 +- .../07-tendermint/types/upgrade_test.go | 10 +- modules/light-clients/09-localhost/module.go | 2 +- .../09-localhost/types/client_state.go | 10 +- .../09-localhost/types/client_state_test.go | 16 +- .../light-clients/09-localhost/types/codec.go | 2 +- .../09-localhost/types/localhost.pb.go | 6 +- .../09-localhost/types/localhost_test.go | 6 +- proto/ibc/applications/fee/v1/ack.proto | 2 +- proto/ibc/applications/fee/v1/fee.proto | 2 +- proto/ibc/applications/fee/v1/genesis.proto | 2 +- proto/ibc/applications/fee/v1/metadata.proto | 2 +- proto/ibc/applications/fee/v1/query.proto | 2 +- proto/ibc/applications/fee/v1/tx.proto | 2 +- .../controller/v1/controller.proto | 2 +- .../controller/v1/query.proto | 2 +- .../interchain_accounts/host/v1/host.proto | 2 +- .../interchain_accounts/host/v1/query.proto | 2 +- .../interchain_accounts/v1/account.proto | 2 +- .../interchain_accounts/v1/genesis.proto | 2 +- .../interchain_accounts/v1/metadata.proto | 2 +- .../interchain_accounts/v1/packet.proto | 2 +- .../applications/transfer/v1/genesis.proto | 2 +- .../ibc/applications/transfer/v1/query.proto | 2 +- .../applications/transfer/v1/transfer.proto | 2 +- proto/ibc/applications/transfer/v1/tx.proto | 2 +- .../ibc/applications/transfer/v2/packet.proto | 2 +- proto/ibc/core/channel/v1/channel.proto | 2 +- proto/ibc/core/channel/v1/genesis.proto | 2 +- proto/ibc/core/channel/v1/query.proto | 2 +- proto/ibc/core/channel/v1/tx.proto | 2 +- proto/ibc/core/client/v1/client.proto | 2 +- proto/ibc/core/client/v1/genesis.proto | 2 +- proto/ibc/core/client/v1/query.proto | 2 +- proto/ibc/core/client/v1/tx.proto | 2 +- proto/ibc/core/commitment/v1/commitment.proto | 2 +- proto/ibc/core/connection/v1/connection.proto | 2 +- proto/ibc/core/connection/v1/genesis.proto | 2 +- proto/ibc/core/connection/v1/query.proto | 2 +- proto/ibc/core/connection/v1/tx.proto | 2 +- proto/ibc/core/types/v1/genesis.proto | 2 +- .../lightclients/localhost/v1/localhost.proto | 2 +- .../solomachine/v1/solomachine.proto | 2 +- .../solomachine/v2/solomachine.proto | 2 +- .../tendermint/v1/tendermint.proto | 2 +- testing/README.md | 4 +- testing/app.go | 4 +- testing/chain.go | 16 +- testing/chain_test.go | 2 +- testing/config.go | 10 +- testing/endpoint.go | 14 +- testing/events.go | 6 +- testing/mock/ibc_app.go | 4 +- testing/mock/ibc_module.go | 6 +- testing/mock/ibc_module_test.go | 6 +- testing/mock/mock.go | 6 +- testing/mock/privval_test.go | 2 +- testing/path.go | 2 +- testing/sdk_test.go | 6 +- testing/simapp/ante_handler.go | 4 +- testing/simapp/app.go | 51 +++-- testing/simapp/encoding.go | 2 +- testing/simapp/genesis_account_test.go | 2 +- testing/simapp/sim_bench_test.go | 2 +- testing/simapp/sim_test.go | 6 +- testing/simapp/simd/cmd/cmd_test.go | 4 +- testing/simapp/simd/cmd/genaccounts_test.go | 4 +- testing/simapp/simd/cmd/root.go | 4 +- testing/simapp/simd/main.go | 4 +- testing/simapp/state.go | 2 +- testing/simapp/test_helpers.go | 2 +- testing/simapp/utils.go | 2 +- testing/solomachine.go | 10 +- testing/values.go | 12 +- 425 files changed, 2525 insertions(+), 2413 deletions(-) create mode 100644 modules/apps/27-interchain-accounts/host/types/ack_test.go create mode 100644 modules/apps/transfer/types/ack_test.go diff --git a/docs/architecture/adr-002-go-module-versioning.md b/docs/architecture/adr-002-go-module-versioning.md index 28207d5474d..a046792b142 100644 --- a/docs/architecture/adr-002-go-module-versioning.md +++ b/docs/architecture/adr-002-go-module-versioning.md @@ -72,7 +72,7 @@ This prevents the Go module version from being incremented with breaking changes It also requires all extended functions to live in the same Go module, disrupting the existing code structure. The version that implements this change will still be incompatible with previous versions, but future versions could be imported together without namespace collisions. -For example, lets say this solution is implmented in v3. Then +For example, lets say this solution is implemented in v3. Then `github.com/cosmos/ibc-go/v2` cannot be imported with any other ibc-go version diff --git a/go.mod b/go.mod index 29861465660..6bae0c1635d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ go 1.17 -module github.com/cosmos/ibc-go/v3 +module github.com/cosmos/ibc-go/v4 replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 @@ -53,10 +53,10 @@ require ( github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/gin-gonic/gin v1.7.0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-playground/validator/v10 v10.4.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/gateway v1.1.0 // indirect github.com/golang/snappy v0.0.3 // indirect diff --git a/go.sum b/go.sum index f85c6414a09..508fcd0b421 100644 --- a/go.sum +++ b/go.sum @@ -338,9 +338,8 @@ github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= -github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= diff --git a/modules/apps/27-interchain-accounts/client/cli/cli.go b/modules/apps/27-interchain-accounts/client/cli/cli.go index 95b49f29e2a..92dbb031255 100644 --- a/modules/apps/27-interchain-accounts/client/cli/cli.go +++ b/modules/apps/27-interchain-accounts/client/cli/cli.go @@ -3,8 +3,8 @@ package cli import ( "github.com/spf13/cobra" - controllercli "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/client/cli" - hostcli "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/client/cli" + controllercli "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/client/cli" + hostcli "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/client/cli" ) // GetQueryCmd returns the query commands for the interchain-accounts submodule diff --git a/modules/apps/27-interchain-accounts/controller/client/cli/query.go b/modules/apps/27-interchain-accounts/controller/client/cli/query.go index 9a939906b90..b7636715c7d 100644 --- a/modules/apps/27-interchain-accounts/controller/client/cli/query.go +++ b/modules/apps/27-interchain-accounts/controller/client/cli/query.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" ) // GetCmdParams returns the command handler for the controller submodule parameter querying. diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index cbcafbd248c..53adf6a090e 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -5,12 +5,12 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/keeper" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/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" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ porttypes.Middleware = &IBCMiddleware{} diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 7656c665333..b326c0bb71f 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -9,13 +9,13 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - fee "github.com/cosmos/ibc-go/v3/modules/apps/29-fee" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + fee "github.com/cosmos/ibc-go/v4/modules/apps/29-fee" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var ( diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account.go b/modules/apps/27-interchain-accounts/controller/keeper/account.go index 2cb5e023e22..e16f2d0874d 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account.go @@ -4,9 +4,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // RegisterInterchainAccount is the entry point to registering an interchain account: diff --git a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go index 0f8c89c51a8..5d8854eea59 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/account_test.go @@ -1,10 +1,10 @@ package keeper_test import ( - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestRegisterInterchainAccount() { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/events.go b/modules/apps/27-interchain-accounts/controller/keeper/events.go index 3c820c74cb0..8381fe7bec7 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/events.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/events.go @@ -4,9 +4,9 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // EmitAcknowledgementEvent emits an event signalling a successful or failed acknowledgement and including the error diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go index eab7687236e..88ca396b93b 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // InitGenesis initializes the interchain accounts controller application state from a provided genesis state diff --git a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go index 1c34e2efbf1..348294fbc8a 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/genesis_test.go @@ -1,10 +1,10 @@ package keeper_test import ( - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/keeper" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestInitGenesis() { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query.go index dd1d04a96b3..e23edc5017e 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/grpc_query.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" ) var _ types.QueryServer = Keeper{} diff --git a/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go index e76cdac1fb4..ba54ce876bc 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/grpc_query_test.go @@ -3,7 +3,7 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" ) func (suite *KeeperTestSuite) TestQueryParams() { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go index c9f72ae3380..337610f4a3b 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -8,8 +8,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // OnChanOpenInit performs basic validation of channel initialization. diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go index b0cb9c3a125..87338812aba 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -3,10 +3,10 @@ package keeper_test import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestOnChanOpenInit() { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go index 5973d2abcd3..3ecdb169197 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper.go @@ -12,10 +12,10 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // Keeper defines the IBC interchain accounts controller keeper diff --git a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go index 76020e17c87..602cb69426f 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/keeper_test.go @@ -7,9 +7,9 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var ( diff --git a/modules/apps/27-interchain-accounts/controller/keeper/params.go b/modules/apps/27-interchain-accounts/controller/keeper/params.go index dce72c0c491..38e82a27c80 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/params.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/params.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" ) // IsControllerEnabled retrieves the controller enabled boolean from the paramstore. diff --git a/modules/apps/27-interchain-accounts/controller/keeper/params_test.go b/modules/apps/27-interchain-accounts/controller/keeper/params_test.go index ffd71f49268..4e4d8703e40 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/params_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/params_test.go @@ -1,6 +1,6 @@ package keeper_test -import "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" +import "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" func (suite *KeeperTestSuite) TestParams() { expParams := types.DefaultParams() diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay.go b/modules/apps/27-interchain-accounts/controller/keeper/relay.go index 4eaf26c52a6..6d197aadca2 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay.go @@ -5,9 +5,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // SendTx takes pre-built packet data containing messages to be executed on the host chain from an authentication module and attempts to send the packet. diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go index 2a1f9894087..a980d3f953d 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go @@ -5,11 +5,11 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestSendTx() { diff --git a/modules/apps/27-interchain-accounts/controller/types/controller.pb.go b/modules/apps/27-interchain-accounts/controller/types/controller.pb.go index dfa8bd31512..8aa795abab6 100644 --- a/modules/apps/27-interchain-accounts/controller/types/controller.pb.go +++ b/modules/apps/27-interchain-accounts/controller/types/controller.pb.go @@ -93,9 +93,9 @@ var fileDescriptor_177fd0fec5eb3400 = []byte{ 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x15, 0x90, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x9f, 0x9c, 0x5f, 0x9c, 0x9b, 0x5f, 0xac, 0x9f, 0x99, 0x94, 0xac, 0x9b, 0x9e, 0xaf, 0x5f, 0x66, - 0xac, 0x9f, 0x9b, 0x9f, 0x52, 0x9a, 0x93, 0x5a, 0x0c, 0x0a, 0xa0, 0x62, 0x7d, 0x23, 0x73, 0x5d, + 0xa2, 0x9f, 0x9b, 0x9f, 0x52, 0x9a, 0x93, 0x5a, 0x0c, 0x0a, 0xa0, 0x62, 0x7d, 0x23, 0x73, 0x5d, 0x84, 0xb7, 0x74, 0xb1, 0x85, 0x4d, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0xd8, 0x2b, 0xc6, - 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe4, 0x79, 0xfc, 0x19, 0x5b, 0x01, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x36, 0xd4, 0x5d, 0xad, 0x5b, 0x01, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/27-interchain-accounts/controller/types/params_test.go b/modules/apps/27-interchain-accounts/controller/types/params_test.go index 1b2b296c7d4..df3927e22d3 100644 --- a/modules/apps/27-interchain-accounts/controller/types/params_test.go +++ b/modules/apps/27-interchain-accounts/controller/types/params_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" ) func TestValidateParams(t *testing.T) { diff --git a/modules/apps/27-interchain-accounts/controller/types/query.pb.go b/modules/apps/27-interchain-accounts/controller/types/query.pb.go index dbbdfeec611..82a755409f4 100644 --- a/modules/apps/27-interchain-accounts/controller/types/query.pb.go +++ b/modules/apps/27-interchain-accounts/controller/types/query.pb.go @@ -124,7 +124,7 @@ var fileDescriptor_df0d8b259d72854e = []byte{ // 315 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x91, 0x31, 0x4b, 0x33, 0x31, 0x1c, 0xc6, 0x9b, 0x17, 0xde, 0x0e, 0x71, 0x8b, 0x0e, 0x52, 0x24, 0x48, 0x27, 0x97, 0x26, 0xf4, - 0x2a, 0x08, 0x1d, 0x1c, 0x14, 0x74, 0xad, 0x1d, 0x5d, 0x24, 0x17, 0xc3, 0x35, 0x72, 0x97, 0x7f, + 0x2c, 0x08, 0x1d, 0x1c, 0x14, 0x74, 0xad, 0x1d, 0x5d, 0x24, 0x17, 0xc3, 0x35, 0x72, 0x97, 0x7f, 0x9a, 0xe4, 0x0a, 0x5d, 0xfd, 0x04, 0x82, 0x5f, 0xca, 0xb1, 0x20, 0x82, 0x9b, 0x72, 0xe7, 0x07, 0x91, 0xde, 0x1d, 0xb4, 0x62, 0x07, 0xad, 0x6b, 0xfe, 0x3c, 0xbf, 0x5f, 0x1e, 0x1e, 0x7c, 0xaa, 0x63, 0xc9, 0x85, 0xb5, 0xa9, 0x96, 0x22, 0x68, 0x30, 0x9e, 0x6b, 0x13, 0x94, 0x93, 0x13, 0xa1, @@ -136,12 +136,12 @@ var fileDescriptor_df0d8b259d72854e = []byte{ 0xea, 0x2d, 0x18, 0xaf, 0xc8, 0x18, 0xb7, 0x6d, 0xf5, 0xb2, 0x8f, 0x0e, 0xd1, 0xd1, 0x4e, 0x34, 0x64, 0xbf, 0x2f, 0xc5, 0x1a, 0x66, 0x43, 0x8a, 0xde, 0x10, 0xfe, 0x5f, 0xb9, 0xc8, 0x0b, 0xc2, 0xed, 0xfa, 0x48, 0x2e, 0xb6, 0x01, 0x7f, 0xef, 0xd1, 0xb9, 0xfc, 0x33, 0xa7, 0x6e, 0xde, 0x1d, - 0xde, 0x3f, 0x7f, 0x3c, 0xfe, 0x3b, 0x26, 0x11, 0x6f, 0x26, 0xf9, 0xc9, 0x14, 0x75, 0xc3, 0xb3, - 0xbb, 0xa7, 0x82, 0xa2, 0x45, 0x41, 0xd1, 0x7b, 0x41, 0xd1, 0x43, 0x49, 0x5b, 0x8b, 0x92, 0xb6, - 0x5e, 0x4b, 0xda, 0xba, 0x1e, 0x25, 0x3a, 0x4c, 0xf2, 0x98, 0x49, 0xc8, 0xb8, 0x04, 0x9f, 0x81, - 0x5f, 0xe2, 0x7b, 0x09, 0xf0, 0xd9, 0x80, 0x67, 0x70, 0x9b, 0xa7, 0xca, 0xd7, 0xb2, 0xe8, 0xa4, - 0xb7, 0xf2, 0xf5, 0x36, 0xf9, 0xc2, 0xdc, 0x2a, 0x1f, 0xb7, 0xab, 0x55, 0x07, 0x9f, 0x01, 0x00, - 0x00, 0xff, 0xff, 0x49, 0xe2, 0x61, 0x29, 0xae, 0x02, 0x00, 0x00, + 0xde, 0x3f, 0x7f, 0x3c, 0xfe, 0x1b, 0x90, 0x88, 0x37, 0x93, 0xfc, 0x64, 0x8a, 0xba, 0xe1, 0xd9, + 0xdd, 0x53, 0x41, 0xd1, 0xa2, 0xa0, 0xe8, 0xbd, 0xa0, 0xe8, 0xa1, 0xa4, 0xad, 0x45, 0x49, 0x5b, + 0xaf, 0x25, 0x6d, 0x5d, 0x8f, 0x12, 0x1d, 0x26, 0x79, 0xcc, 0x24, 0x64, 0x5c, 0x82, 0xcf, 0xc0, + 0x2f, 0xf1, 0xbd, 0x04, 0xf8, 0x6c, 0xc0, 0x33, 0xb8, 0xcd, 0x53, 0xe5, 0x6b, 0x59, 0x74, 0xd2, + 0x5b, 0xf9, 0x7a, 0x9b, 0x7c, 0x61, 0x6e, 0x95, 0x8f, 0xdb, 0xd5, 0xaa, 0xc7, 0x9f, 0x01, 0x00, + 0x00, 0xff, 0xff, 0x9b, 0x4f, 0xc0, 0x9d, 0xae, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/apps/27-interchain-accounts/host/client/cli/query.go b/modules/apps/27-interchain-accounts/host/client/cli/query.go index c35e03baa16..a5a6637ce9a 100644 --- a/modules/apps/27-interchain-accounts/host/client/cli/query.go +++ b/modules/apps/27-interchain-accounts/host/client/cli/query.go @@ -12,10 +12,10 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // GetCmdParams returns the command handler for the host submodule parameter querying. diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 6e77c464afe..7cf0deca969 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -5,11 +5,11 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // IBCModule implements the ICS26 interface for interchain accounts host chains diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index ea602e89b4a..df563082f91 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -14,13 +14,13 @@ import ( tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" tmstate "github.com/tendermint/tendermint/state" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var ( diff --git a/modules/apps/27-interchain-accounts/host/keeper/account.go b/modules/apps/27-interchain-accounts/host/keeper/account.go index d37cc21f1c2..a4c8b511dda 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/account.go +++ b/modules/apps/27-interchain-accounts/host/keeper/account.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" ) // RegisterInterchainAccount attempts to create a new account using the provided address and diff --git a/modules/apps/27-interchain-accounts/host/keeper/account_test.go b/modules/apps/27-interchain-accounts/host/keeper/account_test.go index 5e64189058e..038ed003748 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/account_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/account_test.go @@ -3,8 +3,8 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestRegisterInterchainAccount() { diff --git a/modules/apps/27-interchain-accounts/host/keeper/events.go b/modules/apps/27-interchain-accounts/host/keeper/events.go index 2429acf18a3..ead5d783864 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/events.go +++ b/modules/apps/27-interchain-accounts/host/keeper/events.go @@ -2,9 +2,11 @@ package keeper import ( "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // EmitAcknowledgementEvent emits an event signalling a successful or failed acknowledgement and including the error diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis.go b/modules/apps/27-interchain-accounts/host/keeper/genesis.go index 2a9caa3948b..c3dff759f4d 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // InitGenesis initializes the interchain accounts host application state from a provided genesis state diff --git a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go index 138d713cf67..be6ae690385 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/genesis_test.go @@ -1,10 +1,10 @@ package keeper_test import ( - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestInitGenesis() { diff --git a/modules/apps/27-interchain-accounts/host/keeper/grpc_query.go b/modules/apps/27-interchain-accounts/host/keeper/grpc_query.go index c2727eab535..65afdece331 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/grpc_query.go +++ b/modules/apps/27-interchain-accounts/host/keeper/grpc_query.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" ) var _ types.QueryServer = Keeper{} diff --git a/modules/apps/27-interchain-accounts/host/keeper/grpc_query_test.go b/modules/apps/27-interchain-accounts/host/keeper/grpc_query_test.go index e0ca62e8c56..44aae4b4e1f 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/grpc_query_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/grpc_query_test.go @@ -3,7 +3,7 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" ) func (suite *KeeperTestSuite) TestQueryParams() { diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake.go b/modules/apps/27-interchain-accounts/host/keeper/handshake.go index 6d15bb0568c..15a18fcea77 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake.go @@ -8,9 +8,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // OnChanOpenTry performs basic validation of the ICA channel diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go index ee0ca72f14b..9784c0ba412 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go @@ -3,10 +3,10 @@ package keeper_test import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestOnChanOpenTry() { diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper.go b/modules/apps/27-interchain-accounts/host/keeper/keeper.go index 8f2f345da1b..7125bb52f20 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper.go @@ -12,10 +12,10 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // Keeper defines the IBC interchain accounts host keeper diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go index 98f9c06bf25..7953f0f5663 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go @@ -7,9 +7,9 @@ import ( "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var ( diff --git a/modules/apps/27-interchain-accounts/host/keeper/params.go b/modules/apps/27-interchain-accounts/host/keeper/params.go index 1ecbd5b05f8..e56e72342c8 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/params.go +++ b/modules/apps/27-interchain-accounts/host/keeper/params.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" ) // IsHostEnabled retrieves the host enabled boolean from the paramstore. diff --git a/modules/apps/27-interchain-accounts/host/keeper/params_test.go b/modules/apps/27-interchain-accounts/host/keeper/params_test.go index 529afecaecf..c769ade3fdb 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/params_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/params_test.go @@ -1,6 +1,6 @@ package keeper_test -import "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" +import "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" func (suite *KeeperTestSuite) TestParams() { expParams := types.DefaultParams() diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay.go b/modules/apps/27-interchain-accounts/host/keeper/relay.go index 8610a50f5e5..e658c5bd3f5 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay.go @@ -5,9 +5,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/gogo/protobuf/proto" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // OnRecvPacket handles a given interchain accounts packet on a destination host chain. diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index d92be7227aa..c7ebd9428f5 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -10,12 +10,12 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestOnRecvPacket() { diff --git a/modules/apps/27-interchain-accounts/host/types/ack_test.go b/modules/apps/27-interchain-accounts/host/types/ack_test.go new file mode 100644 index 00000000000..f0484efe695 --- /dev/null +++ b/modules/apps/27-interchain-accounts/host/types/ack_test.go @@ -0,0 +1,81 @@ +package types_test + +import ( + "testing" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/suite" + abcitypes "github.com/tendermint/tendermint/abci/types" + tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" + tmstate "github.com/tendermint/tendermint/state" + + ibctesting "github.com/cosmos/ibc-go/v4/testing" +) + +const ( + gasUsed = uint64(100) + gasWanted = uint64(100) +) + +type TypesTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain +} + +func (suite *TypesTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +} + +func TestTypesTestSuite(t *testing.T) { + suite.Run(t, new(TypesTestSuite)) +} + +// The safety of including ABCI error codes in the acknowledgement rests +// on the inclusion of these ABCI error codes in the abcitypes.ResposneDeliverTx +// hash. If the ABCI codes get removed from consensus they must no longer be used +// in the packet acknowledgement. +// +// This test acts as an indicator that the ABCI error codes may no longer be deterministic. +func (suite *TypesTestSuite) TestABCICodeDeterminism() { + // same ABCI error code used + err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1") + errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2") + + // different ABCI error code used + errDifferentABCICode := sdkerrors.ErrNotFound + + deliverTx := sdkerrors.ResponseDeliverTx(err, gasUsed, gasWanted, false) + responses := tmprotostate.ABCIResponses{ + DeliverTxs: []*abcitypes.ResponseDeliverTx{ + &deliverTx, + }, + } + + deliverTxSameABCICode := sdkerrors.ResponseDeliverTx(errSameABCICode, gasUsed, gasWanted, false) + responsesSameABCICode := tmprotostate.ABCIResponses{ + DeliverTxs: []*abcitypes.ResponseDeliverTx{ + &deliverTxSameABCICode, + }, + } + + deliverTxDifferentABCICode := sdkerrors.ResponseDeliverTx(errDifferentABCICode, gasUsed, gasWanted, false) + responsesDifferentABCICode := tmprotostate.ABCIResponses{ + DeliverTxs: []*abcitypes.ResponseDeliverTx{ + &deliverTxDifferentABCICode, + }, + } + + hash := tmstate.ABCIResponsesResultsHash(&responses) + hashSameABCICode := tmstate.ABCIResponsesResultsHash(&responsesSameABCICode) + hashDifferentABCICode := tmstate.ABCIResponsesResultsHash(&responsesDifferentABCICode) + + suite.Require().Equal(hash, hashSameABCICode) + suite.Require().NotEqual(hash, hashDifferentABCICode) +} diff --git a/modules/apps/27-interchain-accounts/host/types/host.pb.go b/modules/apps/27-interchain-accounts/host/types/host.pb.go index e944986eb4c..db7356b7e9a 100644 --- a/modules/apps/27-interchain-accounts/host/types/host.pb.go +++ b/modules/apps/27-interchain-accounts/host/types/host.pb.go @@ -104,9 +104,9 @@ var fileDescriptor_48e202774f13d08e = []byte{ 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xf2, 0x4a, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0xd6, 0xcf, 0x4c, 0x4a, 0xd6, 0x4d, - 0xcf, 0xd7, 0x2f, 0x33, 0xd6, 0xcf, 0xcd, 0x4f, 0x29, 0xcd, 0x49, 0x2d, 0x06, 0x85, 0x5f, 0xb1, + 0xcf, 0xd7, 0x2f, 0x33, 0xd1, 0xcf, 0xcd, 0x4f, 0x29, 0xcd, 0x49, 0x2d, 0x06, 0x85, 0x5f, 0xb1, 0xbe, 0x91, 0xb9, 0x2e, 0x22, 0x04, 0x74, 0x51, 0x83, 0xae, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, - 0x0d, 0xec, 0x6b, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0xc9, 0x05, 0x61, 0x74, 0x01, + 0x0d, 0xec, 0x6b, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd5, 0xb2, 0xee, 0x31, 0x74, 0x01, 0x00, 0x00, } diff --git a/modules/apps/27-interchain-accounts/host/types/params_test.go b/modules/apps/27-interchain-accounts/host/types/params_test.go index 2606f3fd2f5..39ed24251f7 100644 --- a/modules/apps/27-interchain-accounts/host/types/params_test.go +++ b/modules/apps/27-interchain-accounts/host/types/params_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" ) func TestValidateParams(t *testing.T) { diff --git a/modules/apps/27-interchain-accounts/host/types/query.pb.go b/modules/apps/27-interchain-accounts/host/types/query.pb.go index c468e841945..313d0f10b6f 100644 --- a/modules/apps/27-interchain-accounts/host/types/query.pb.go +++ b/modules/apps/27-interchain-accounts/host/types/query.pb.go @@ -121,27 +121,27 @@ func init() { } var fileDescriptor_e6b7e23fc90c353a = []byte{ - // 312 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x91, 0x3f, 0x4b, 0x3b, 0x31, - 0x18, 0xc7, 0x9b, 0x1f, 0xfc, 0x3a, 0xc4, 0x2d, 0x3a, 0x48, 0x91, 0x20, 0x9d, 0x1c, 0xda, 0x84, - 0xfe, 0x81, 0x3a, 0xaa, 0xa3, 0x38, 0xa8, 0xa3, 0x8b, 0xe4, 0xd2, 0x70, 0x0d, 0xf4, 0xf2, 0xa4, - 0x97, 0xdc, 0x41, 0x57, 0x5f, 0x81, 0xe0, 0x4b, 0x72, 0x71, 0x11, 0x0a, 0x2e, 0x8e, 0x72, 0xe7, - 0x0b, 0x91, 0xcb, 0x1d, 0x68, 0x51, 0x84, 0xc3, 0xf5, 0x09, 0x9f, 0xcf, 0xf7, 0xf9, 0x3e, 0xc1, - 0xc7, 0x3a, 0x92, 0x5c, 0x58, 0xbb, 0xd4, 0x52, 0x78, 0x0d, 0xc6, 0x71, 0x6d, 0xbc, 0x4a, 0xe5, - 0x42, 0x68, 0x73, 0x2b, 0xa4, 0x84, 0xcc, 0x78, 0xc7, 0x17, 0xe0, 0x3c, 0xcf, 0x47, 0x7c, 0x95, - 0xa9, 0x74, 0xcd, 0x6c, 0x0a, 0x1e, 0xc8, 0x40, 0x47, 0x92, 0x7d, 0x25, 0xd9, 0x0f, 0x24, 0xab, - 0x48, 0x96, 0x8f, 0x7a, 0x07, 0x31, 0x40, 0xbc, 0x54, 0x5c, 0x58, 0xcd, 0x85, 0x31, 0xe0, 0x1b, - 0x26, 0xb8, 0x7a, 0xb3, 0x56, 0x5b, 0x04, 0x67, 0x00, 0xfb, 0x7b, 0x98, 0x5c, 0x55, 0x3b, 0x5d, - 0x8a, 0x54, 0x24, 0xee, 0x5a, 0xad, 0x32, 0xe5, 0x7c, 0x5f, 0xe2, 0xdd, 0xad, 0xa9, 0xb3, 0x60, - 0x9c, 0x22, 0x17, 0xb8, 0x6b, 0xc3, 0x64, 0x1f, 0x1d, 0xa2, 0xa3, 0x9d, 0xf1, 0x94, 0xb5, 0xa9, - 0xc0, 0x1a, 0x5b, 0xe3, 0x18, 0x3f, 0x23, 0xfc, 0x3f, 0xa4, 0x90, 0x47, 0x84, 0xbb, 0xf5, 0x23, - 0x39, 0x69, 0xa7, 0xfc, 0xbe, 0x7b, 0xef, 0xf4, 0x0f, 0x86, 0xba, 0x67, 0x7f, 0x7a, 0xf7, 0xf2, - 0xfe, 0xf0, 0x8f, 0x91, 0x01, 0x6f, 0xce, 0xfa, 0xfb, 0x39, 0xeb, 0x3e, 0x67, 0xf3, 0xa7, 0x82, - 0xa2, 0x4d, 0x41, 0xd1, 0x5b, 0x41, 0xd1, 0x7d, 0x49, 0x3b, 0x9b, 0x92, 0x76, 0x5e, 0x4b, 0xda, - 0xb9, 0x39, 0x8f, 0xb5, 0x5f, 0x64, 0x11, 0x93, 0x90, 0x70, 0x09, 0x2e, 0x01, 0x57, 0x89, 0x87, - 0x31, 0xf0, 0x7c, 0xc2, 0x13, 0x98, 0x67, 0x4b, 0xe5, 0xea, 0x98, 0xf1, 0x6c, 0xf8, 0x99, 0x34, - 0xdc, 0x4e, 0xf2, 0x6b, 0xab, 0x5c, 0xd4, 0x0d, 0xff, 0x36, 0xf9, 0x08, 0x00, 0x00, 0xff, 0xff, - 0x7d, 0xf5, 0x90, 0xb6, 0x78, 0x02, 0x00, 0x00, + // 310 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x91, 0x31, 0x4b, 0x03, 0x31, + 0x14, 0xc7, 0x1b, 0xc1, 0x0e, 0x71, 0x8b, 0x0e, 0x52, 0x24, 0x48, 0x27, 0x87, 0x36, 0xa1, 0xb5, + 0x50, 0x47, 0x75, 0x14, 0x07, 0x75, 0x74, 0x91, 0x5c, 0x1a, 0xae, 0x81, 0x5e, 0x5e, 0x7a, 0xc9, + 0x1d, 0x74, 0xf5, 0x13, 0x08, 0x7e, 0x24, 0x17, 0x17, 0xa1, 0xe0, 0xe2, 0x28, 0x77, 0x7e, 0x10, + 0xb9, 0xdc, 0x81, 0x16, 0x45, 0x38, 0x5c, 0x5f, 0xf8, 0xfd, 0xfe, 0xef, 0xff, 0x82, 0x4f, 0x74, + 0x24, 0xb9, 0xb0, 0x76, 0xa1, 0xa5, 0xf0, 0x1a, 0x8c, 0xe3, 0xda, 0x78, 0x95, 0xca, 0xb9, 0xd0, + 0xe6, 0x4e, 0x48, 0x09, 0x99, 0xf1, 0x8e, 0xcf, 0xc1, 0x79, 0x9e, 0x8f, 0xf8, 0x32, 0x53, 0xe9, + 0x8a, 0xd9, 0x14, 0x3c, 0x90, 0x81, 0x8e, 0x24, 0xfb, 0x4e, 0xb2, 0x5f, 0x48, 0x56, 0x91, 0x2c, + 0x1f, 0xf5, 0x0e, 0x62, 0x80, 0x78, 0xa1, 0xb8, 0xb0, 0x9a, 0x0b, 0x63, 0xc0, 0x37, 0x4c, 0x70, + 0xf5, 0xa6, 0xad, 0xb6, 0x08, 0xce, 0x00, 0xf6, 0xf7, 0x30, 0xb9, 0xae, 0x76, 0xba, 0x12, 0xa9, + 0x48, 0xdc, 0x8d, 0x5a, 0x66, 0xca, 0xf9, 0xbe, 0xc4, 0xbb, 0x1b, 0x53, 0x67, 0xc1, 0x38, 0x45, + 0x2e, 0x71, 0xd7, 0x86, 0xc9, 0x3e, 0x3a, 0x44, 0x47, 0x3b, 0xe3, 0x09, 0x6b, 0x53, 0x81, 0x35, + 0xb6, 0xc6, 0x31, 0x7e, 0x41, 0x78, 0x3b, 0xa4, 0x90, 0x27, 0x84, 0xbb, 0xf5, 0x23, 0x39, 0x6d, + 0xa7, 0xfc, 0xb9, 0x7b, 0xef, 0xec, 0x1f, 0x86, 0xba, 0x67, 0x7f, 0x72, 0xff, 0xfa, 0xf1, 0xb8, + 0xc5, 0xc8, 0x80, 0x37, 0x67, 0xfd, 0xfb, 0x9c, 0x75, 0x9f, 0xf3, 0xd9, 0x73, 0x41, 0xd1, 0xba, + 0xa0, 0xe8, 0xbd, 0xa0, 0xe8, 0xa1, 0xa4, 0x9d, 0x75, 0x49, 0x3b, 0x6f, 0x25, 0xed, 0xdc, 0x5e, + 0xc4, 0xda, 0xcf, 0xb3, 0x88, 0x49, 0x48, 0xb8, 0x04, 0x97, 0x80, 0xab, 0xc4, 0xc3, 0x18, 0x78, + 0x3e, 0xe1, 0x09, 0xcc, 0xb2, 0x85, 0x72, 0x75, 0xcc, 0x78, 0x3a, 0xfc, 0x4a, 0x1a, 0x6e, 0x26, + 0xf9, 0x95, 0x55, 0x2e, 0xea, 0x86, 0x7f, 0x3b, 0xfe, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x58, 0x8e, + 0x7b, 0xe6, 0x78, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index c7a5651baa6..cfcf9804a66 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -15,15 +15,15 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/client/cli" - controllerkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/keeper" - controllertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host" - hostkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" - hosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/client/cli" + controllerkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/keeper" + controllertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host" + hostkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" + hosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) var ( diff --git a/modules/apps/27-interchain-accounts/module_test.go b/modules/apps/27-interchain-accounts/module_test.go index ff44eed4ff0..be51b9d71c7 100644 --- a/modules/apps/27-interchain-accounts/module_test.go +++ b/modules/apps/27-interchain-accounts/module_test.go @@ -8,12 +8,12 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" - ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" - controllertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - hosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - "github.com/cosmos/ibc-go/v3/testing/simapp" + ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" + controllertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + hosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) type InterchainAccountsTestSuite struct { diff --git a/modules/apps/27-interchain-accounts/types/account.pb.go b/modules/apps/27-interchain-accounts/types/account.pb.go index da0a705399c..4978a25f4a7 100644 --- a/modules/apps/27-interchain-accounts/types/account.pb.go +++ b/modules/apps/27-interchain-accounts/types/account.pb.go @@ -91,10 +91,10 @@ var fileDescriptor_5561bd92625bf7da = []byte{ 0x61, 0xb8, 0xdf, 0xd3, 0x29, 0xfe, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x5c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xa1, 0xe1, 0xa7, 0x9f, 0x99, - 0x94, 0xac, 0x9b, 0x9e, 0xaf, 0x5f, 0x66, 0xac, 0x9f, 0x9b, 0x9f, 0x52, 0x9a, 0x93, 0x5a, 0x0c, + 0x94, 0xac, 0x9b, 0x9e, 0xaf, 0x5f, 0x66, 0xa2, 0x9f, 0x9b, 0x9f, 0x52, 0x9a, 0x93, 0x5a, 0x0c, 0x8a, 0xc1, 0x62, 0x7d, 0x23, 0x73, 0x5d, 0x44, 0x2c, 0xe8, 0xc2, 0x23, 0xaf, 0xa4, 0xb2, 0x20, - 0xb5, 0x38, 0x89, 0x0d, 0x1c, 0x7c, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x74, 0x07, 0x08, - 0x0e, 0xf1, 0x01, 0x00, 0x00, + 0xb5, 0x38, 0x89, 0x0d, 0x1c, 0x7c, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4e, 0xd7, 0x23, + 0x15, 0xf1, 0x01, 0x00, 0x00, } func (m *InterchainAccount) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/27-interchain-accounts/types/account_test.go b/modules/apps/27-interchain-accounts/types/account_test.go index 13acc610152..19684cb8c80 100644 --- a/modules/apps/27-interchain-accounts/types/account_test.go +++ b/modules/apps/27-interchain-accounts/types/account_test.go @@ -10,8 +10,8 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var ( diff --git a/modules/apps/27-interchain-accounts/types/codec_test.go b/modules/apps/27-interchain-accounts/types/codec_test.go index b18b018332a..51fe1128fba 100644 --- a/modules/apps/27-interchain-accounts/types/codec_test.go +++ b/modules/apps/27-interchain-accounts/types/codec_test.go @@ -6,8 +6,8 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) // caseRawBytes defines a helper struct, used for testing codec operations diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index 8fb0b743cda..e4873c561fd 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -5,8 +5,8 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // AccountKeeper defines the expected account keeper diff --git a/modules/apps/27-interchain-accounts/types/genesis.go b/modules/apps/27-interchain-accounts/types/genesis.go index f4c5b15b6d2..67e8391ef66 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.go +++ b/modules/apps/27-interchain-accounts/types/genesis.go @@ -1,9 +1,9 @@ package types import ( - controllertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - hosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + controllertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + hosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // DefaultGenesis creates and returns the interchain accounts GenesisState diff --git a/modules/apps/27-interchain-accounts/types/genesis.pb.go b/modules/apps/27-interchain-accounts/types/genesis.pb.go index c73f5c395f0..5dc6b9e4112 100644 --- a/modules/apps/27-interchain-accounts/types/genesis.pb.go +++ b/modules/apps/27-interchain-accounts/types/genesis.pb.go @@ -5,8 +5,8 @@ package types import ( fmt "fmt" - types "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - types1 "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" + types "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + types1 "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -351,48 +351,48 @@ func init() { } var fileDescriptor_629b3ced0911516b = []byte{ - // 645 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x95, 0x3f, 0x6f, 0x13, 0x3f, - 0x18, 0xc7, 0xe3, 0xa4, 0xbf, 0xfe, 0x14, 0xf7, 0x0f, 0xc5, 0x94, 0xea, 0x08, 0xd2, 0x25, 0x78, - 0x69, 0x24, 0xd4, 0x3b, 0xf5, 0x0f, 0x54, 0x54, 0x42, 0xa8, 0x17, 0x10, 0x64, 0x43, 0x66, 0x41, - 0x2c, 0x27, 0xc7, 0x67, 0x25, 0x96, 0x92, 0x73, 0x74, 0x76, 0x23, 0x75, 0x62, 0x67, 0x62, 0x43, - 0xac, 0x48, 0xbc, 0x00, 0xde, 0x01, 0x63, 0x27, 0xd4, 0x91, 0x29, 0x42, 0xed, 0x3b, 0xc8, 0x2b, - 0x40, 0xf6, 0x9d, 0x92, 0xf4, 0x48, 0xab, 0x9b, 0x98, 0x98, 0x62, 0xdf, 0xe3, 0xef, 0xf7, 0xf9, - 0x3c, 0x7e, 0x1c, 0x1b, 0x3e, 0x12, 0x1d, 0xe6, 0xd3, 0xe1, 0xb0, 0x2f, 0x18, 0xd5, 0x42, 0xc6, - 0xca, 0x17, 0xb1, 0xe6, 0x09, 0xeb, 0x51, 0x11, 0x87, 0x94, 0x31, 0x79, 0x12, 0x6b, 0xe5, 0x8f, - 0x76, 0xfd, 0x2e, 0x8f, 0xb9, 0x12, 0xca, 0x1b, 0x26, 0x52, 0x4b, 0xb4, 0x2d, 0x3a, 0xcc, 0x9b, - 0x97, 0x79, 0x0b, 0x64, 0xde, 0x68, 0xb7, 0xb6, 0xd9, 0x95, 0x5d, 0x69, 0x35, 0xbe, 0x19, 0xa5, - 0xf2, 0x5a, 0xab, 0x50, 0x56, 0x26, 0x63, 0x9d, 0xc8, 0x7e, 0x9f, 0x27, 0x06, 0x60, 0x36, 0xcb, - 0x4c, 0x0e, 0x0b, 0x99, 0xf4, 0xa4, 0xd2, 0x46, 0x6e, 0x7e, 0x53, 0x21, 0xfe, 0x5e, 0x86, 0xab, - 0x2f, 0xd3, 0x72, 0xde, 0x68, 0xaa, 0x39, 0xfa, 0x02, 0xa0, 0x33, 0xb3, 0x0f, 0xb3, 0x52, 0x43, - 0x65, 0x82, 0x0e, 0x68, 0x80, 0xe6, 0xca, 0xde, 0x33, 0xaf, 0x60, 0xc5, 0x5e, 0x6b, 0x6a, 0x34, - 0x9f, 0x23, 0xd8, 0x3e, 0x1b, 0xd7, 0x4b, 0x93, 0x71, 0xbd, 0x7e, 0x4a, 0x07, 0xfd, 0x23, 0x7c, - 0x5d, 0x3a, 0x4c, 0xb6, 0xd8, 0x42, 0x03, 0xf4, 0x01, 0x40, 0x64, 0x8a, 0xc8, 0xe1, 0x95, 0x2d, - 0xde, 0x93, 0xc2, 0x78, 0xaf, 0xa4, 0xd2, 0x57, 0xc0, 0x1e, 0x64, 0x60, 0xf7, 0x52, 0xb0, 0x3f, - 0x53, 0x60, 0xb2, 0xd1, 0xcb, 0x89, 0xf0, 0xd7, 0x0a, 0xdc, 0x5a, 0x5c, 0x28, 0x7a, 0x0f, 0x6f, - 0x51, 0xa6, 0xc5, 0x88, 0x87, 0xac, 0x47, 0xe3, 0x98, 0xf7, 0x95, 0x03, 0x1a, 0x95, 0xe6, 0xca, - 0xde, 0xe3, 0xc2, 0x8c, 0xc7, 0x56, 0xdf, 0x4a, 0xe5, 0x81, 0x9b, 0x01, 0x6e, 0xa5, 0x80, 0x39, - 0x73, 0x4c, 0xd6, 0xe9, 0xfc, 0x72, 0x85, 0x3e, 0x03, 0x78, 0x67, 0x81, 0xb1, 0x53, 0xb6, 0x14, - 0xcf, 0x0b, 0x53, 0x10, 0xde, 0x15, 0x4a, 0xf3, 0x84, 0x47, 0xed, 0xe9, 0x82, 0xe3, 0x34, 0x1e, - 0xe0, 0x8c, 0xa9, 0x96, 0x32, 0x2d, 0x70, 0xc0, 0x04, 0x89, 0xbc, 0x4c, 0xa1, 0x4d, 0xf8, 0xdf, - 0x50, 0x26, 0x5a, 0x39, 0x95, 0x46, 0xa5, 0x59, 0x25, 0xe9, 0x04, 0xbd, 0x85, 0xcb, 0x43, 0x9a, - 0xd0, 0x81, 0x72, 0x96, 0x6c, 0x37, 0x8f, 0x8a, 0x31, 0xce, 0xfd, 0x23, 0x46, 0xbb, 0xde, 0x6b, - 0xeb, 0x10, 0x2c, 0x19, 0x32, 0x92, 0xf9, 0xe1, 0x4f, 0x15, 0xb8, 0x91, 0xef, 0xf8, 0xbf, 0x0e, - 0xdd, 0xd4, 0x21, 0x04, 0x97, 0x4c, 0x53, 0x9c, 0x4a, 0x03, 0x34, 0xab, 0xc4, 0x8e, 0x11, 0xc9, - 0xf5, 0xe7, 0xa0, 0x18, 0xa1, 0xbd, 0x72, 0xae, 0xeb, 0xcc, 0x37, 0x00, 0xd7, 0xae, 0xec, 0x22, - 0x7a, 0x0a, 0xd7, 0x98, 0x8c, 0x63, 0xce, 0x8c, 0x63, 0x28, 0x22, 0x7b, 0xf3, 0x54, 0x03, 0x67, - 0x32, 0xae, 0x6f, 0x4e, 0x2f, 0x8d, 0x59, 0x18, 0x93, 0xd5, 0xd9, 0xbc, 0x1d, 0xa1, 0x87, 0xf0, - 0x7f, 0x03, 0x6b, 0x84, 0x65, 0x2b, 0x44, 0x93, 0x71, 0x7d, 0x3d, 0x15, 0x66, 0x01, 0x4c, 0x96, - 0xcd, 0xa8, 0x1d, 0xa1, 0x03, 0x08, 0xb3, 0xf6, 0x98, 0xf5, 0xb6, 0xd6, 0xe0, 0xee, 0x64, 0x5c, - 0xbf, 0x9d, 0x25, 0x9a, 0xc6, 0x30, 0xa9, 0x66, 0x93, 0x76, 0x84, 0x7f, 0x00, 0x78, 0xff, 0x86, - 0x3d, 0xff, 0xab, 0x15, 0xb4, 0xcc, 0x21, 0xb6, 0x69, 0x43, 0x1a, 0x45, 0x09, 0x57, 0x2a, 0x2b, - 0xa3, 0x36, 0x7f, 0x10, 0xaf, 0x2c, 0xb0, 0x07, 0xd1, 0x7e, 0x39, 0x4e, 0x3f, 0x04, 0xe1, 0xd9, - 0x85, 0x0b, 0xce, 0x2f, 0x5c, 0xf0, 0xeb, 0xc2, 0x05, 0x1f, 0x2f, 0xdd, 0xd2, 0xf9, 0xa5, 0x5b, - 0xfa, 0x79, 0xe9, 0x96, 0xde, 0xbd, 0xe8, 0x0a, 0xdd, 0x3b, 0xe9, 0x78, 0x4c, 0x0e, 0x7c, 0x26, - 0xd5, 0x40, 0x2a, 0x5f, 0x74, 0xd8, 0x4e, 0x57, 0xfa, 0xa3, 0x7d, 0x7f, 0x20, 0xa3, 0x93, 0x3e, - 0x57, 0xe6, 0xf1, 0x51, 0xfe, 0xde, 0xe1, 0xce, 0xac, 0xf9, 0x3b, 0xd3, 0x77, 0x47, 0x9f, 0x0e, - 0xb9, 0xea, 0x2c, 0xdb, 0x17, 0x67, 0xff, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf5, 0x08, 0x8f, - 0x1f, 0x67, 0x07, 0x00, 0x00, + // 643 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x95, 0x3f, 0x6f, 0x13, 0x31, + 0x18, 0xc6, 0xe3, 0xa4, 0x14, 0xc5, 0xfd, 0x43, 0x31, 0xa5, 0x3a, 0x82, 0x74, 0x09, 0x5e, 0x1a, + 0x09, 0xf5, 0x4e, 0x2d, 0x85, 0x8a, 0x4a, 0x08, 0xf5, 0x02, 0x82, 0x6c, 0xc8, 0x2c, 0x88, 0xe5, + 0xe4, 0xf8, 0xac, 0xc4, 0x52, 0x72, 0x8e, 0xce, 0x6e, 0xa4, 0x4e, 0xec, 0x4c, 0x6c, 0x88, 0x15, + 0x89, 0x0f, 0xc0, 0x37, 0x60, 0xec, 0x84, 0x3a, 0x32, 0x45, 0xa8, 0xfd, 0x06, 0xf9, 0x04, 0xc8, + 0xbe, 0x53, 0x92, 0x1e, 0x69, 0x75, 0x13, 0x13, 0x53, 0xec, 0x7b, 0xfd, 0x3c, 0xef, 0xef, 0xf5, + 0xeb, 0xd8, 0xf0, 0xb1, 0xe8, 0x30, 0x9f, 0x0e, 0x87, 0x7d, 0xc1, 0xa8, 0x16, 0x32, 0x56, 0xbe, + 0x88, 0x35, 0x4f, 0x58, 0x8f, 0x8a, 0x38, 0xa4, 0x8c, 0xc9, 0xe3, 0x58, 0x2b, 0x7f, 0xb4, 0xeb, + 0x77, 0x79, 0xcc, 0x95, 0x50, 0xde, 0x30, 0x91, 0x5a, 0xa2, 0x6d, 0xd1, 0x61, 0xde, 0xbc, 0xcc, + 0x5b, 0x20, 0xf3, 0x46, 0xbb, 0xb5, 0xcd, 0xae, 0xec, 0x4a, 0xab, 0xf1, 0xcd, 0x28, 0x95, 0xd7, + 0x5a, 0x85, 0xb2, 0x32, 0x19, 0xeb, 0x44, 0xf6, 0xfb, 0x3c, 0x31, 0x00, 0xb3, 0x59, 0x66, 0x72, + 0x50, 0xc8, 0xa4, 0x27, 0x95, 0x36, 0x72, 0xf3, 0x9b, 0x0a, 0xf1, 0x8f, 0x32, 0x5c, 0x7d, 0x95, + 0x96, 0xf3, 0x56, 0x53, 0xcd, 0xd1, 0x57, 0x00, 0x9d, 0x99, 0x7d, 0x98, 0x95, 0x1a, 0x2a, 0x13, + 0x74, 0x40, 0x03, 0x34, 0x57, 0xf6, 0x9e, 0x7b, 0x05, 0x2b, 0xf6, 0x5a, 0x53, 0xa3, 0xf9, 0x1c, + 0xc1, 0xf6, 0xe9, 0xb8, 0x5e, 0x9a, 0x8c, 0xeb, 0xf5, 0x13, 0x3a, 0xe8, 0x1f, 0xe2, 0xab, 0xd2, + 0x61, 0xb2, 0xc5, 0x16, 0x1a, 0xa0, 0x8f, 0x00, 0x22, 0x53, 0x44, 0x0e, 0xaf, 0x6c, 0xf1, 0x9e, + 0x16, 0xc6, 0x7b, 0x2d, 0x95, 0xbe, 0x04, 0xf6, 0x20, 0x03, 0xbb, 0x97, 0x82, 0xfd, 0x9d, 0x02, + 0x93, 0x8d, 0x5e, 0x4e, 0x84, 0xbf, 0x55, 0xe0, 0xd6, 0xe2, 0x42, 0xd1, 0x07, 0x78, 0x8b, 0x32, + 0x2d, 0x46, 0x3c, 0x64, 0x3d, 0x1a, 0xc7, 0xbc, 0xaf, 0x1c, 0xd0, 0xa8, 0x34, 0x57, 0xf6, 0x9e, + 0x14, 0x66, 0x3c, 0xb2, 0xfa, 0x56, 0x2a, 0x0f, 0xdc, 0x0c, 0x70, 0x2b, 0x05, 0xcc, 0x99, 0x63, + 0xb2, 0x4e, 0xe7, 0x97, 0x2b, 0xf4, 0x05, 0xc0, 0x3b, 0x0b, 0x8c, 0x9d, 0xb2, 0xa5, 0x78, 0x51, + 0x98, 0x82, 0xf0, 0xae, 0x50, 0x9a, 0x27, 0x3c, 0x6a, 0x4f, 0x17, 0x1c, 0xa5, 0xf1, 0x00, 0x67, + 0x4c, 0xb5, 0x94, 0x69, 0x81, 0x03, 0x26, 0x48, 0xe4, 0x65, 0x0a, 0x6d, 0xc2, 0x1b, 0x43, 0x99, + 0x68, 0xe5, 0x54, 0x1a, 0x95, 0x66, 0x95, 0xa4, 0x13, 0xf4, 0x0e, 0x2e, 0x0f, 0x69, 0x42, 0x07, + 0xca, 0x59, 0xb2, 0xdd, 0x3c, 0x2c, 0xc6, 0x38, 0xf7, 0x8f, 0x18, 0xed, 0x7a, 0x6f, 0xac, 0x43, + 0xb0, 0x64, 0xc8, 0x48, 0xe6, 0x87, 0x3f, 0x57, 0xe0, 0x46, 0xbe, 0xe3, 0xff, 0x3b, 0x74, 0x5d, + 0x87, 0x10, 0x5c, 0x32, 0x4d, 0x71, 0x2a, 0x0d, 0xd0, 0xac, 0x12, 0x3b, 0x46, 0x24, 0xd7, 0x9f, + 0xfd, 0x62, 0x84, 0xf6, 0xca, 0xb9, 0xaa, 0x33, 0xdf, 0x01, 0x5c, 0xbb, 0xb4, 0x8b, 0xe8, 0x19, + 0x5c, 0x63, 0x32, 0x8e, 0x39, 0x33, 0x8e, 0xa1, 0x88, 0xec, 0xcd, 0x53, 0x0d, 0x9c, 0xc9, 0xb8, + 0xbe, 0x39, 0xbd, 0x34, 0x66, 0x61, 0x4c, 0x56, 0x67, 0xf3, 0x76, 0x84, 0x1e, 0xc2, 0x9b, 0x06, + 0xd6, 0x08, 0xcb, 0x56, 0x88, 0x26, 0xe3, 0xfa, 0x7a, 0x2a, 0xcc, 0x02, 0x98, 0x2c, 0x9b, 0x51, + 0x3b, 0x42, 0xfb, 0x10, 0x66, 0xed, 0x31, 0xeb, 0x6d, 0xad, 0xc1, 0xdd, 0xc9, 0xb8, 0x7e, 0x3b, + 0x4b, 0x34, 0x8d, 0x61, 0x52, 0xcd, 0x26, 0xed, 0x08, 0xff, 0x04, 0xf0, 0xfe, 0x35, 0x7b, 0xfe, + 0x4f, 0x2b, 0x68, 0x99, 0x43, 0x6c, 0xd3, 0x86, 0x34, 0x8a, 0x12, 0xae, 0x54, 0x56, 0x46, 0x6d, + 0xfe, 0x20, 0x5e, 0x5a, 0x60, 0x0f, 0xa2, 0xfd, 0x72, 0x94, 0x7e, 0x08, 0xc2, 0xd3, 0x73, 0x17, + 0x9c, 0x9d, 0xbb, 0xe0, 0xf7, 0xb9, 0x0b, 0x3e, 0x5d, 0xb8, 0xa5, 0xb3, 0x0b, 0xb7, 0xf4, 0xeb, + 0xc2, 0x2d, 0xbd, 0x7f, 0xd9, 0x15, 0xba, 0x77, 0xdc, 0xf1, 0x98, 0x1c, 0xf8, 0x4c, 0xaa, 0x81, + 0x54, 0xbe, 0xe8, 0xb0, 0x9d, 0xae, 0xf4, 0x47, 0xfb, 0xfe, 0x40, 0x46, 0xc7, 0x7d, 0xae, 0xcc, + 0xe3, 0xa3, 0xfc, 0xbd, 0x83, 0x9d, 0x59, 0xf3, 0x77, 0xa6, 0xef, 0x8e, 0x3e, 0x19, 0x72, 0xd5, + 0x59, 0xb6, 0x2f, 0xce, 0xa3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcf, 0xd8, 0xa4, 0x04, 0x67, + 0x07, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/27-interchain-accounts/types/genesis_test.go b/modules/apps/27-interchain-accounts/types/genesis_test.go index bbdbc8d14d5..be86e8595a4 100644 --- a/modules/apps/27-interchain-accounts/types/genesis_test.go +++ b/modules/apps/27-interchain-accounts/types/genesis_test.go @@ -1,10 +1,10 @@ package types_test import ( - controllertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - hosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + controllertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + hosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *TypesTestSuite) TestValidateGenesisState() { diff --git a/modules/apps/27-interchain-accounts/types/keys_test.go b/modules/apps/27-interchain-accounts/types/keys_test.go index 94c7a3bed0d..58b5b9c71b3 100644 --- a/modules/apps/27-interchain-accounts/types/keys_test.go +++ b/modules/apps/27-interchain-accounts/types/keys_test.go @@ -1,7 +1,7 @@ package types_test import ( - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" ) func (suite *TypesTestSuite) TestKeyActiveChannel() { diff --git a/modules/apps/27-interchain-accounts/types/metadata.go b/modules/apps/27-interchain-accounts/types/metadata.go index 09185ea6edc..148e5221f28 100644 --- a/modules/apps/27-interchain-accounts/types/metadata.go +++ b/modules/apps/27-interchain-accounts/types/metadata.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) const ( diff --git a/modules/apps/27-interchain-accounts/types/metadata.pb.go b/modules/apps/27-interchain-accounts/types/metadata.pb.go index 907e8c0c01d..f1924453d83 100644 --- a/modules/apps/27-interchain-accounts/types/metadata.pb.go +++ b/modules/apps/27-interchain-accounts/types/metadata.pb.go @@ -128,26 +128,26 @@ var fileDescriptor_c29c32e397d1f21e = []byte{ // 349 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xcf, 0x4a, 0xeb, 0x40, 0x18, 0xc5, 0x9b, 0xde, 0x6b, 0x5b, 0x67, 0x25, 0x83, 0xe8, 0x58, 0x30, 0x95, 0xb8, 0xd0, 0x4d, - 0x33, 0xd4, 0x82, 0x82, 0xcb, 0x8a, 0x0b, 0x11, 0x37, 0xc5, 0x95, 0x20, 0x61, 0x32, 0x33, 0xa4, - 0x03, 0xc9, 0x7c, 0x21, 0x33, 0x0d, 0xed, 0x5b, 0xf8, 0x06, 0xbe, 0x8e, 0xcb, 0x2e, 0x5d, 0x15, - 0x69, 0xdf, 0xa0, 0x4f, 0x20, 0x49, 0x6b, 0xeb, 0xdf, 0x5d, 0x4e, 0xce, 0x39, 0xbf, 0x8f, 0xe1, - 0xa0, 0x73, 0x15, 0x72, 0xca, 0xd2, 0x34, 0x56, 0x9c, 0x59, 0x05, 0xda, 0x50, 0xa5, 0xad, 0xcc, - 0xf8, 0x80, 0x29, 0x1d, 0x30, 0xce, 0x61, 0xa8, 0xad, 0xa1, 0x79, 0x87, 0x26, 0xd2, 0x32, 0xc1, - 0x2c, 0xf3, 0xd3, 0x0c, 0x2c, 0xe0, 0x13, 0x15, 0x72, 0xff, 0x73, 0xcf, 0xff, 0xa5, 0xe7, 0xe7, - 0x9d, 0xe6, 0x6e, 0x04, 0x11, 0x94, 0x1d, 0x5a, 0x7c, 0x2d, 0xeb, 0xde, 0x73, 0x15, 0x35, 0xee, - 0x56, 0x44, 0x4c, 0x50, 0x3d, 0x97, 0x99, 0x51, 0xa0, 0x89, 0x73, 0xe4, 0x9c, 0x6e, 0xf7, 0x3f, - 0x24, 0x7e, 0x44, 0x84, 0x83, 0xb6, 0x19, 0xc4, 0xb1, 0xcc, 0x02, 0x0e, 0x5a, 0x4b, 0x5e, 0x5c, - 0x0b, 0x94, 0x20, 0xd5, 0x22, 0xda, 0x3b, 0x5e, 0x4c, 0x5b, 0xad, 0x31, 0x4b, 0xe2, 0x4b, 0xef, - 0xaf, 0xa4, 0xd7, 0xdf, 0xdb, 0x58, 0x57, 0x6b, 0xe7, 0x46, 0xe0, 0x5b, 0x84, 0x07, 0x60, 0xec, - 0x37, 0xf0, 0xbf, 0x12, 0x7c, 0xb8, 0x98, 0xb6, 0x0e, 0x96, 0xe0, 0x9f, 0x19, 0xaf, 0xbf, 0x53, - 0xfc, 0xfc, 0x02, 0x23, 0xa8, 0xce, 0x84, 0xc8, 0xa4, 0x31, 0xe4, 0xff, 0xf2, 0x15, 0x2b, 0x89, - 0x9b, 0xa8, 0x21, 0x35, 0x07, 0xa1, 0x74, 0x44, 0xb6, 0x4a, 0x6b, 0xad, 0xf1, 0x3e, 0xaa, 0xdb, - 0x51, 0x60, 0xc7, 0xa9, 0x24, 0xb5, 0xd2, 0xaa, 0xd9, 0xd1, 0xfd, 0x38, 0x95, 0xbd, 0xe0, 0x65, - 0xe6, 0x3a, 0x93, 0x99, 0xeb, 0xbc, 0xcd, 0x5c, 0xe7, 0x69, 0xee, 0x56, 0x26, 0x73, 0xb7, 0xf2, - 0x3a, 0x77, 0x2b, 0x0f, 0xd7, 0x91, 0xb2, 0x83, 0x61, 0xe8, 0x73, 0x48, 0x28, 0x07, 0x93, 0x80, - 0xa1, 0x2a, 0xe4, 0xed, 0x08, 0x68, 0xde, 0xa5, 0x09, 0x88, 0x61, 0x2c, 0x4d, 0x31, 0xa9, 0xa1, - 0x67, 0x17, 0xed, 0xcd, 0x2a, 0xed, 0xf5, 0x9a, 0xc5, 0x35, 0x13, 0xd6, 0xca, 0x25, 0xba, 0xef, - 0x01, 0x00, 0x00, 0xff, 0xff, 0x6e, 0x74, 0x28, 0x89, 0x02, 0x02, 0x00, 0x00, + 0x33, 0x54, 0x45, 0xc1, 0x65, 0xc5, 0x85, 0x88, 0x9b, 0xe2, 0x4a, 0x90, 0x30, 0x99, 0x19, 0xd2, + 0x81, 0x64, 0xbe, 0x90, 0x99, 0x86, 0xf6, 0x2d, 0x7c, 0x03, 0x5f, 0xc7, 0x65, 0x97, 0xae, 0x8a, + 0xb4, 0x6f, 0xd0, 0x27, 0x90, 0xa4, 0xb5, 0xf5, 0xef, 0x2e, 0x27, 0xe7, 0x9c, 0xdf, 0xc7, 0x70, + 0xd0, 0xb9, 0x0a, 0x39, 0x65, 0x69, 0x1a, 0x2b, 0xce, 0xac, 0x02, 0x6d, 0xa8, 0xd2, 0x56, 0x66, + 0xbc, 0xcf, 0x94, 0x0e, 0x18, 0xe7, 0x30, 0xd0, 0xd6, 0xd0, 0xbc, 0x43, 0x13, 0x69, 0x99, 0x60, + 0x96, 0xf9, 0x69, 0x06, 0x16, 0xf0, 0x91, 0x0a, 0xb9, 0xff, 0xb9, 0xe7, 0xff, 0xd2, 0xf3, 0xf3, + 0x4e, 0x73, 0x3b, 0x82, 0x08, 0xca, 0x0e, 0x2d, 0xbe, 0x16, 0x75, 0xef, 0xb9, 0x8a, 0x1a, 0x77, + 0x4b, 0x22, 0x26, 0xa8, 0x9e, 0xcb, 0xcc, 0x28, 0xd0, 0xc4, 0x39, 0x70, 0x8e, 0x37, 0x7b, 0x1f, + 0x12, 0x3f, 0x22, 0xc2, 0x41, 0xdb, 0x0c, 0xe2, 0x58, 0x66, 0x01, 0x07, 0xad, 0x25, 0x2f, 0xae, + 0x05, 0x4a, 0x90, 0x6a, 0x11, 0xed, 0x1e, 0xce, 0x27, 0xad, 0xd6, 0x88, 0x25, 0xf1, 0xa5, 0xf7, + 0x57, 0xd2, 0xeb, 0xed, 0xac, 0xad, 0xab, 0x95, 0x73, 0x23, 0xf0, 0x2d, 0xc2, 0x7d, 0x30, 0xf6, + 0x1b, 0xf8, 0x5f, 0x09, 0xde, 0x9f, 0x4f, 0x5a, 0x7b, 0x0b, 0xf0, 0xcf, 0x8c, 0xd7, 0xdb, 0x2a, + 0x7e, 0x7e, 0x81, 0x11, 0x54, 0x67, 0x42, 0x64, 0xd2, 0x18, 0xf2, 0x7f, 0xf1, 0x8a, 0xa5, 0xc4, + 0x4d, 0xd4, 0x90, 0x9a, 0x83, 0x50, 0x3a, 0x22, 0x1b, 0xa5, 0xb5, 0xd2, 0x78, 0x17, 0xd5, 0xed, + 0x30, 0xb0, 0xa3, 0x54, 0x92, 0x5a, 0x69, 0xd5, 0xec, 0xf0, 0x7e, 0x94, 0xca, 0x6e, 0xf0, 0x32, + 0x75, 0x9d, 0xf1, 0xd4, 0x75, 0xde, 0xa6, 0xae, 0xf3, 0x34, 0x73, 0x2b, 0xe3, 0x99, 0x5b, 0x79, + 0x9d, 0xb9, 0x95, 0x87, 0xeb, 0x48, 0xd9, 0xfe, 0x20, 0xf4, 0x39, 0x24, 0x94, 0x83, 0x49, 0xc0, + 0x50, 0x15, 0xf2, 0x76, 0x04, 0x34, 0x3f, 0xa3, 0x09, 0x88, 0x41, 0x2c, 0x4d, 0x31, 0xa9, 0xa1, + 0x27, 0x17, 0xed, 0xf5, 0x2a, 0xed, 0xd5, 0x9a, 0xc5, 0x35, 0x13, 0xd6, 0xca, 0x25, 0x4e, 0xdf, + 0x03, 0x00, 0x00, 0xff, 0xff, 0x54, 0xa4, 0x03, 0x92, 0x02, 0x02, 0x00, 0x00, } func (m *Metadata) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/27-interchain-accounts/types/metadata_test.go b/modules/apps/27-interchain-accounts/types/metadata_test.go index 3bda2549c07..30b1e98f66a 100644 --- a/modules/apps/27-interchain-accounts/types/metadata_test.go +++ b/modules/apps/27-interchain-accounts/types/metadata_test.go @@ -1,8 +1,8 @@ package types_test import ( - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) // use TestVersion as metadata being compared against diff --git a/modules/apps/27-interchain-accounts/types/packet.pb.go b/modules/apps/27-interchain-accounts/types/packet.pb.go index 98bc3e99ab0..faf353695d5 100644 --- a/modules/apps/27-interchain-accounts/types/packet.pb.go +++ b/modules/apps/27-interchain-accounts/types/packet.pb.go @@ -173,29 +173,29 @@ var fileDescriptor_89a080d7401cd393 = []byte{ // 393 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x51, 0x41, 0x8b, 0xd3, 0x40, 0x18, 0xcd, 0xb8, 0x41, 0xd6, 0x59, 0xd9, 0x2d, 0x61, 0x0f, 0x31, 0x42, 0x08, 0x2b, 0x62, 0x10, - 0x32, 0xe3, 0xb6, 0x82, 0x17, 0x2f, 0xb5, 0x8d, 0xd0, 0x8b, 0x94, 0x98, 0x42, 0xf5, 0x12, 0x26, + 0x32, 0xe3, 0xd6, 0x82, 0x17, 0x2f, 0xb5, 0x8d, 0xd0, 0x8b, 0x94, 0x98, 0x42, 0xf5, 0x12, 0x26, 0xd3, 0x31, 0x1d, 0x6c, 0x32, 0xa1, 0x33, 0x29, 0xe6, 0x1f, 0x94, 0x9e, 0xfc, 0x03, 0x3d, 0xf9, 0x67, 0x3c, 0xf6, 0xe8, 0x51, 0xda, 0x3f, 0x22, 0x99, 0x60, 0xdb, 0x83, 0x07, 0x6f, 0x8f, 0xc7, - 0xf7, 0xde, 0xf7, 0xbd, 0xef, 0xc1, 0xd7, 0x3c, 0xa5, 0x98, 0x94, 0xe5, 0x82, 0x53, 0xa2, 0xb8, - 0x28, 0x24, 0xe6, 0x85, 0x62, 0x4b, 0x3a, 0x27, 0xbc, 0x48, 0x08, 0xa5, 0xa2, 0x2a, 0x94, 0xc4, - 0xab, 0x7b, 0x5c, 0x12, 0xfa, 0x95, 0x29, 0x54, 0x2e, 0x85, 0x12, 0xd6, 0x0b, 0x9e, 0x52, 0x74, - 0xae, 0x42, 0xff, 0x50, 0xa1, 0xd5, 0xbd, 0xf3, 0x24, 0x13, 0x22, 0x5b, 0x30, 0xac, 0x65, 0x69, - 0xf5, 0x05, 0x93, 0xa2, 0x6e, 0x3d, 0x9c, 0xdb, 0x4c, 0x64, 0x42, 0x43, 0xdc, 0xa0, 0x96, 0xbd, - 0x5b, 0x03, 0xf8, 0x74, 0x74, 0xf4, 0xea, 0xb7, 0x56, 0x63, 0xbd, 0x7b, 0x48, 0x14, 0xb1, 0xfa, - 0xd0, 0x54, 0x75, 0xc9, 0x6c, 0xe0, 0x01, 0xff, 0xba, 0x1b, 0xa0, 0xff, 0x3c, 0x04, 0xc5, 0x75, - 0xc9, 0x22, 0x2d, 0xb5, 0x2c, 0x68, 0xce, 0x88, 0x22, 0xf6, 0x03, 0x0f, 0xf8, 0x8f, 0x23, 0x8d, - 0x1b, 0x2e, 0x67, 0xb9, 0xb0, 0x2f, 0x3c, 0xe0, 0x3f, 0x8a, 0x34, 0xbe, 0x7b, 0x0b, 0x2f, 0x07, - 0x42, 0xe6, 0x42, 0xc6, 0xdf, 0xac, 0x57, 0xf0, 0x32, 0x67, 0x52, 0x92, 0x8c, 0x49, 0x1b, 0x78, - 0x17, 0xfe, 0x55, 0xf7, 0x16, 0xb5, 0xd1, 0xd0, 0xdf, 0x68, 0xa8, 0x5f, 0xd4, 0xd1, 0x71, 0xea, - 0xe5, 0x14, 0x9a, 0xcd, 0x4e, 0xeb, 0x39, 0xec, 0xc4, 0x9f, 0xc6, 0x61, 0x32, 0xf9, 0xf0, 0x71, - 0x1c, 0x0e, 0x46, 0xef, 0x47, 0xe1, 0xb0, 0x63, 0x38, 0x37, 0x9b, 0xad, 0x77, 0x75, 0x46, 0x59, - 0xcf, 0xe0, 0x8d, 0x1e, 0x0b, 0xa7, 0xe1, 0x60, 0x12, 0x87, 0x49, 0x3c, 0xed, 0x00, 0xe7, 0x7a, - 0xb3, 0xf5, 0xe0, 0x89, 0x71, 0xcc, 0xf5, 0x0f, 0xd7, 0x78, 0x97, 0xfc, 0xdc, 0xbb, 0x60, 0xb7, - 0x77, 0xc1, 0xef, 0xbd, 0x0b, 0xbe, 0x1f, 0x5c, 0x63, 0x77, 0x70, 0x8d, 0x5f, 0x07, 0xd7, 0xf8, - 0x1c, 0x66, 0x5c, 0xcd, 0xab, 0x14, 0x51, 0x91, 0x63, 0xaa, 0x4f, 0xc7, 0x3c, 0xa5, 0x41, 0x26, - 0xf0, 0xaa, 0x87, 0x73, 0x31, 0xab, 0x16, 0x4c, 0x36, 0x65, 0x4b, 0xdc, 0x7d, 0x13, 0x9c, 0x1e, - 0x15, 0x1c, 0x7b, 0x6e, 0xfe, 0x23, 0xd3, 0x87, 0x3a, 0x52, 0xef, 0x4f, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xdd, 0x25, 0x3e, 0xc6, 0x1c, 0x02, 0x00, 0x00, + 0xf7, 0xde, 0xf7, 0xbd, 0xef, 0xc1, 0x1e, 0x4f, 0x29, 0x26, 0x65, 0xb9, 0xe0, 0x94, 0x28, 0x2e, + 0x0a, 0x89, 0x79, 0xa1, 0xd8, 0x92, 0xce, 0x09, 0x2f, 0x12, 0x42, 0xa9, 0xa8, 0x0a, 0x25, 0xf1, + 0xea, 0x1e, 0x97, 0x84, 0x7e, 0x65, 0x0a, 0x95, 0x4b, 0xa1, 0x84, 0xf5, 0x82, 0xa7, 0x14, 0x9d, + 0xab, 0xd0, 0x3f, 0x54, 0x68, 0x75, 0xef, 0x3c, 0xc9, 0x84, 0xc8, 0x16, 0x0c, 0x6b, 0x59, 0x5a, + 0x7d, 0xc1, 0xa4, 0xa8, 0x5b, 0x0f, 0xe7, 0x36, 0x13, 0x99, 0xd0, 0x10, 0x37, 0xa8, 0x65, 0xef, + 0xd6, 0x00, 0x3e, 0x1d, 0x1d, 0xbd, 0xfa, 0xad, 0xd5, 0x58, 0xef, 0x1e, 0x12, 0x45, 0xac, 0x3e, + 0x34, 0x55, 0x5d, 0x32, 0x1b, 0x78, 0xc0, 0xbf, 0xee, 0x06, 0xe8, 0x3f, 0x0f, 0x41, 0x71, 0x5d, + 0xb2, 0x48, 0x4b, 0x2d, 0x0b, 0x9a, 0x33, 0xa2, 0x88, 0xfd, 0xc0, 0x03, 0xfe, 0xe3, 0x48, 0xe3, + 0x86, 0xcb, 0x59, 0x2e, 0xec, 0x0b, 0x0f, 0xf8, 0x8f, 0x22, 0x8d, 0xef, 0xde, 0xc2, 0xcb, 0x81, + 0x90, 0xb9, 0x90, 0xf1, 0x37, 0xeb, 0x15, 0xbc, 0xcc, 0x99, 0x94, 0x24, 0x63, 0xd2, 0x06, 0xde, + 0x85, 0x7f, 0xd5, 0xbd, 0x45, 0x6d, 0x34, 0xf4, 0x37, 0x1a, 0xea, 0x17, 0x75, 0x74, 0x9c, 0x7a, + 0x39, 0x85, 0x66, 0xb3, 0xd3, 0x7a, 0x0e, 0x3b, 0xf1, 0xa7, 0x71, 0x98, 0x4c, 0x3e, 0x7c, 0x1c, + 0x87, 0x83, 0xd1, 0xfb, 0x51, 0x38, 0xec, 0x18, 0xce, 0xcd, 0x66, 0xeb, 0x5d, 0x9d, 0x51, 0xd6, + 0x33, 0x78, 0xa3, 0xc7, 0xc2, 0x69, 0x38, 0x98, 0xc4, 0x61, 0x12, 0x4f, 0x3b, 0xc0, 0xb9, 0xde, + 0x6c, 0x3d, 0x78, 0x62, 0x1c, 0x73, 0xfd, 0xc3, 0x35, 0xde, 0x25, 0x3f, 0xf7, 0x2e, 0xd8, 0xed, + 0x5d, 0xf0, 0x7b, 0xef, 0x82, 0xef, 0x07, 0xd7, 0xd8, 0x1d, 0x5c, 0xe3, 0xd7, 0xc1, 0x35, 0x3e, + 0x87, 0x19, 0x57, 0xf3, 0x2a, 0x45, 0x54, 0xe4, 0x98, 0xea, 0xd3, 0x31, 0x4f, 0x69, 0x90, 0x09, + 0xbc, 0xea, 0xe1, 0x5c, 0xcc, 0xaa, 0x05, 0x93, 0x4d, 0xd9, 0x12, 0x77, 0xdf, 0x04, 0xa7, 0x47, + 0x05, 0xc7, 0x9e, 0x9b, 0xff, 0xc8, 0xf4, 0xa1, 0x8e, 0xf4, 0xfa, 0x4f, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xe7, 0xf5, 0x15, 0xdd, 0x1c, 0x02, 0x00, 0x00, } func (m *InterchainAccountPacketData) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/27-interchain-accounts/types/packet_test.go b/modules/apps/27-interchain-accounts/types/packet_test.go index 52e7797d987..bfbfa9d3802 100644 --- a/modules/apps/27-interchain-accounts/types/packet_test.go +++ b/modules/apps/27-interchain-accounts/types/packet_test.go @@ -1,7 +1,7 @@ package types_test import ( - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" ) var largeMemo = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum" diff --git a/modules/apps/27-interchain-accounts/types/port_test.go b/modules/apps/27-interchain-accounts/types/port_test.go index bdef740cd98..a5dc2532b60 100644 --- a/modules/apps/27-interchain-accounts/types/port_test.go +++ b/modules/apps/27-interchain-accounts/types/port_test.go @@ -3,8 +3,8 @@ package types_test import ( "fmt" - "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *TypesTestSuite) TestNewControllerPortID() { diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index 3714c576748..bb6ef67a5d8 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -8,8 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" "github.com/spf13/cobra" ) diff --git a/modules/apps/29-fee/client/cli/tx.go b/modules/apps/29-fee/client/cli/tx.go index ef038ac7fd5..c31779c22f6 100644 --- a/modules/apps/29-fee/client/cli/tx.go +++ b/modules/apps/29-fee/client/cli/tx.go @@ -12,8 +12,8 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) const ( diff --git a/modules/apps/29-fee/fee_test.go b/modules/apps/29-fee/fee_test.go index d2445adef22..33ac52a60b0 100644 --- a/modules/apps/29-fee/fee_test.go +++ b/modules/apps/29-fee/fee_test.go @@ -5,11 +5,11 @@ import ( "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" ) type FeeTestSuite struct { diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 6a0477f5508..315b5ded3d2 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -7,11 +7,11 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/keeper" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/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" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ porttypes.Middleware = &IBCMiddleware{} diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index b5478fb1c51..6f0de4b1971 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -6,14 +6,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - fee "github.com/cosmos/ibc-go/v3/modules/apps/29-fee" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + fee "github.com/cosmos/ibc-go/v4/modules/apps/29-fee" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" ) var ( diff --git a/modules/apps/29-fee/ica_test.go b/modules/apps/29-fee/ica_test.go index d8cd4e4ce05..bc10f4941dd 100644 --- a/modules/apps/29-fee/ica_test.go +++ b/modules/apps/29-fee/ica_test.go @@ -5,12 +5,12 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var ( diff --git a/modules/apps/29-fee/keeper/escrow.go b/modules/apps/29-fee/keeper/escrow.go index 9755fb45e8d..fed2398f142 100644 --- a/modules/apps/29-fee/keeper/escrow.go +++ b/modules/apps/29-fee/keeper/escrow.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // escrowPacketFee sends the packet fee to the 29-fee module account to hold in escrow diff --git a/modules/apps/29-fee/keeper/escrow_test.go b/modules/apps/29-fee/keeper/escrow_test.go index 0ab829877ea..b1891e4e4e4 100644 --- a/modules/apps/29-fee/keeper/escrow_test.go +++ b/modules/apps/29-fee/keeper/escrow_test.go @@ -2,11 +2,12 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/testing/mock" "github.com/tendermint/tendermint/crypto/secp256k1" + + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/testing/mock" ) func (suite *KeeperTestSuite) TestDistributeFee() { diff --git a/modules/apps/29-fee/keeper/events.go b/modules/apps/29-fee/keeper/events.go index f604a8c9704..162542f4e4d 100644 --- a/modules/apps/29-fee/keeper/events.go +++ b/modules/apps/29-fee/keeper/events.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // EmitIncentivizedPacketEvent emits an event containing information on the total amount of fees incentivizing diff --git a/modules/apps/29-fee/keeper/events_test.go b/modules/apps/29-fee/keeper/events_test.go index 8ab52295e73..2dc1f8c91c4 100644 --- a/modules/apps/29-fee/keeper/events_test.go +++ b/modules/apps/29-fee/keeper/events_test.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" abcitypes "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" ) func (suite *KeeperTestSuite) TestIncentivizePacketEvent() { diff --git a/modules/apps/29-fee/keeper/genesis.go b/modules/apps/29-fee/keeper/genesis.go index 24e5ddd1ece..150058a734e 100644 --- a/modules/apps/29-fee/keeper/genesis.go +++ b/modules/apps/29-fee/keeper/genesis.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" ) // InitGenesis initializes the fee middleware application state from a provided genesis state diff --git a/modules/apps/29-fee/keeper/genesis_test.go b/modules/apps/29-fee/keeper/genesis_test.go index f26a1b9116d..4aebd5121a9 100644 --- a/modules/apps/29-fee/keeper/genesis_test.go +++ b/modules/apps/29-fee/keeper/genesis_test.go @@ -1,9 +1,9 @@ package keeper_test import ( - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestInitGenesis() { diff --git a/modules/apps/29-fee/keeper/grpc_query.go b/modules/apps/29-fee/keeper/grpc_query.go index 4abe16cbe90..3f92686f51f 100644 --- a/modules/apps/29-fee/keeper/grpc_query.go +++ b/modules/apps/29-fee/keeper/grpc_query.go @@ -10,7 +10,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" ) var _ types.QueryServer = Keeper{} diff --git a/modules/apps/29-fee/keeper/grpc_query_test.go b/modules/apps/29-fee/keeper/grpc_query_test.go index 42a9091178a..1286f3c3350 100644 --- a/modules/apps/29-fee/keeper/grpc_query_test.go +++ b/modules/apps/29-fee/keeper/grpc_query_test.go @@ -7,9 +7,9 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestQueryIncentivizedPackets() { diff --git a/modules/apps/29-fee/keeper/keeper.go b/modules/apps/29-fee/keeper/keeper.go index c94f661c904..c60942debea 100644 --- a/modules/apps/29-fee/keeper/keeper.go +++ b/modules/apps/29-fee/keeper/keeper.go @@ -7,9 +7,9 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // Middleware must implement types.ChannelKeeper and types.PortKeeper expected interfaces diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index f72888599e8..e4a6a8ab0d8 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -8,10 +8,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" ) var ( diff --git a/modules/apps/29-fee/keeper/msg_server.go b/modules/apps/29-fee/keeper/msg_server.go index 1acb153594f..c2beea28da3 100644 --- a/modules/apps/29-fee/keeper/msg_server.go +++ b/modules/apps/29-fee/keeper/msg_server.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) var _ types.MsgServer = Keeper{} diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index cdcbe574d1c..73c7caadc9c 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -2,12 +2,12 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestRegisterPayee() { diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index 0c14726c9ed..8c2e90f89c7 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -7,9 +7,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // SendPacket wraps IBC ChannelKeeper's SendPacket function diff --git a/modules/apps/29-fee/keeper/relay_test.go b/modules/apps/29-fee/keeper/relay_test.go index 5dd0aa15815..ca58b1661af 100644 --- a/modules/apps/29-fee/keeper/relay_test.go +++ b/modules/apps/29-fee/keeper/relay_test.go @@ -1,11 +1,11 @@ package keeper_test import ( - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" ) func (suite *KeeperTestSuite) TestWriteAcknowledgementAsync() { diff --git a/modules/apps/29-fee/module.go b/modules/apps/29-fee/module.go index 895a475b512..a9bb1ca0d7c 100644 --- a/modules/apps/29-fee/module.go +++ b/modules/apps/29-fee/module.go @@ -17,9 +17,9 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/client/cli" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/keeper" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/client/cli" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" ) var ( diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index be91db917ed..12a7a556e66 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -3,10 +3,10 @@ package fee_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) // Integration test to ensure ics29 works with ics20 diff --git a/modules/apps/29-fee/types/ack.pb.go b/modules/apps/29-fee/types/ack.pb.go index 3a3e6eae58e..890ba0b76d0 100644 --- a/modules/apps/29-fee/types/ack.pb.go +++ b/modules/apps/29-fee/types/ack.pb.go @@ -94,28 +94,28 @@ func init() { func init() { proto.RegisterFile("ibc/applications/fee/v1/ack.proto", fileDescriptor_ab2834946fb65ea4) } var fileDescriptor_ab2834946fb65ea4 = []byte{ - // 329 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xb1, 0x4e, 0xc2, 0x40, - 0x1c, 0xc6, 0x29, 0x26, 0x46, 0x1b, 0xa7, 0x8a, 0x42, 0x30, 0x39, 0xb0, 0x13, 0x0b, 0xbd, 0x20, - 0x71, 0xd0, 0x0d, 0x36, 0x27, 0x92, 0xba, 0x18, 0x96, 0xe6, 0x7a, 0xfd, 0x53, 0x2f, 0x5c, 0xef, - 0x2e, 0x77, 0x6d, 0x49, 0x7d, 0x0a, 0x1f, 0xc2, 0x87, 0x71, 0x64, 0x74, 0x22, 0x06, 0xde, 0x80, - 0x27, 0x30, 0xa5, 0x26, 0xa2, 0xc1, 0xed, 0xf2, 0x7d, 0xbf, 0xfc, 0x72, 0xf9, 0x7f, 0xf6, 0x35, - 0x0b, 0x29, 0x26, 0x4a, 0x71, 0x46, 0x49, 0xca, 0xa4, 0x30, 0x78, 0x06, 0x80, 0xf3, 0x01, 0x26, - 0x74, 0xee, 0x29, 0x2d, 0x53, 0xe9, 0x34, 0x59, 0x48, 0xbd, 0x7d, 0xc4, 0x9b, 0x01, 0x78, 0xf9, - 0xa0, 0xdd, 0x88, 0x65, 0x2c, 0x77, 0x0c, 0x2e, 0x5f, 0x15, 0xee, 0xbe, 0xd5, 0xed, 0xab, 0x07, - 0x41, 0x41, 0xa4, 0x2c, 0x67, 0x2f, 0x10, 0x8d, 0xe8, 0x5c, 0xc8, 0x05, 0x87, 0x28, 0x86, 0x04, - 0x44, 0xea, 0x4c, 0xec, 0x73, 0xa2, 0x54, 0x40, 0x7e, 0xc7, 0x2d, 0xab, 0x6b, 0xf5, 0xce, 0xc6, - 0x68, 0xbb, 0xea, 0xb4, 0x0b, 0x92, 0xf0, 0x7b, 0xf7, 0x00, 0xe4, 0xfa, 0x0e, 0x51, 0xea, 0xaf, - 0x70, 0x6a, 0x37, 0x67, 0x52, 0x2f, 0x88, 0x8e, 0x02, 0x0d, 0x9c, 0x14, 0xa0, 0x03, 0x12, 0x45, - 0x1a, 0x8c, 0x69, 0xd5, 0xbb, 0x56, 0xef, 0x74, 0xec, 0x6e, 0x57, 0x1d, 0x54, 0x49, 0xff, 0x01, - 0x5d, 0xff, 0xe2, 0xbb, 0xf1, 0xab, 0x62, 0x54, 0xe5, 0xce, 0x93, 0x7d, 0x99, 0x89, 0x08, 0x34, - 0x2f, 0x98, 0x88, 0x83, 0xf2, 0x4b, 0x26, 0xa3, 0xb4, 0x54, 0x1f, 0x75, 0xad, 0xde, 0xc9, 0xbe, - 0xfa, 0x30, 0xc7, 0x5d, 0xbf, 0xf1, 0xd3, 0x8c, 0x94, 0x7a, 0xac, 0xf2, 0xf1, 0xe4, 0x7d, 0x8d, - 0xac, 0xe5, 0x1a, 0x59, 0x9f, 0x6b, 0x64, 0xbd, 0x6e, 0x50, 0x6d, 0xb9, 0x41, 0xb5, 0x8f, 0x0d, - 0xaa, 0x4d, 0x6f, 0x63, 0x96, 0x3e, 0x67, 0xa1, 0x47, 0x65, 0x82, 0xa9, 0x34, 0x89, 0x34, 0x98, - 0x85, 0xb4, 0x1f, 0x4b, 0x9c, 0x0f, 0x71, 0x22, 0xa3, 0x8c, 0x83, 0x29, 0x27, 0x33, 0xf8, 0xe6, - 0xae, 0x5f, 0xae, 0x95, 0x16, 0x0a, 0x4c, 0x78, 0xbc, 0x3b, 0xff, 0xf0, 0x2b, 0x00, 0x00, 0xff, - 0xff, 0x08, 0xe8, 0xda, 0xf9, 0xd2, 0x01, 0x00, 0x00, + // 330 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xbf, 0x4e, 0xc2, 0x40, + 0x1c, 0xc7, 0x29, 0x26, 0x46, 0x1b, 0xa7, 0x8a, 0x42, 0x30, 0x39, 0xb0, 0x13, 0x0b, 0xbd, 0xe0, + 0x9f, 0x41, 0x37, 0xd8, 0x9c, 0x48, 0xea, 0x62, 0x58, 0x9a, 0xeb, 0xf5, 0x47, 0xbd, 0x70, 0xbd, + 0xbb, 0xdc, 0xb5, 0x25, 0xf5, 0x29, 0x7c, 0x08, 0x1f, 0xc6, 0x91, 0xd1, 0x89, 0x18, 0x78, 0x03, + 0x9e, 0xc0, 0x94, 0x9a, 0x88, 0x06, 0xb7, 0xcb, 0xf7, 0xfb, 0xc9, 0x27, 0x97, 0xdf, 0xd7, 0xbe, + 0x64, 0x21, 0xc5, 0x44, 0x29, 0xce, 0x28, 0x49, 0x99, 0x14, 0x06, 0x4f, 0x01, 0x70, 0x3e, 0xc0, + 0x84, 0xce, 0x3c, 0xa5, 0x65, 0x2a, 0x9d, 0x26, 0x0b, 0xa9, 0xb7, 0x8b, 0x78, 0x53, 0x00, 0x2f, + 0x1f, 0xb4, 0x1b, 0xb1, 0x8c, 0xe5, 0x96, 0xc1, 0xe5, 0xab, 0xc2, 0xdd, 0xb7, 0xba, 0x7d, 0xf1, + 0x20, 0x28, 0x88, 0x94, 0xe5, 0xec, 0x05, 0xa2, 0x21, 0x9d, 0x09, 0x39, 0xe7, 0x10, 0xc5, 0x90, + 0x80, 0x48, 0x9d, 0xb1, 0x7d, 0x4a, 0x94, 0x0a, 0xc8, 0xef, 0xb8, 0x65, 0x75, 0xad, 0xde, 0xc9, + 0x08, 0x6d, 0x96, 0x9d, 0x76, 0x41, 0x12, 0x7e, 0xef, 0xee, 0x81, 0x5c, 0xdf, 0x21, 0x4a, 0xfd, + 0x15, 0x4e, 0xec, 0xe6, 0x54, 0xea, 0x39, 0xd1, 0x51, 0xa0, 0x81, 0x93, 0x02, 0x74, 0x40, 0xa2, + 0x48, 0x83, 0x31, 0xad, 0x7a, 0xd7, 0xea, 0x1d, 0x8f, 0xdc, 0xcd, 0xb2, 0x83, 0x2a, 0xe9, 0x3f, + 0xa0, 0xeb, 0x9f, 0x7d, 0x37, 0x7e, 0x55, 0x0c, 0xab, 0xdc, 0x79, 0xb2, 0xcf, 0x33, 0x11, 0x81, + 0xe6, 0x05, 0x13, 0x71, 0x50, 0x7e, 0xc9, 0x64, 0x94, 0x96, 0xea, 0x83, 0xae, 0xd5, 0x3b, 0xda, + 0x55, 0xef, 0xe7, 0xb8, 0xeb, 0x37, 0x7e, 0x9a, 0xa1, 0x52, 0x8f, 0x55, 0x3e, 0x1a, 0xbf, 0xaf, + 0x90, 0xb5, 0x58, 0x21, 0xeb, 0x73, 0x85, 0xac, 0xd7, 0x35, 0xaa, 0x2d, 0xd6, 0xa8, 0xf6, 0xb1, + 0x46, 0xb5, 0xc9, 0x6d, 0xcc, 0xd2, 0xe7, 0x2c, 0xf4, 0xa8, 0x4c, 0x30, 0x95, 0x26, 0x91, 0x06, + 0xb3, 0x90, 0xf6, 0x63, 0x89, 0xf3, 0x1b, 0x9c, 0xc8, 0x28, 0xe3, 0x60, 0xca, 0xc9, 0x0c, 0xbe, + 0xba, 0xeb, 0x97, 0x6b, 0xa5, 0x85, 0x02, 0x13, 0x1e, 0x6e, 0xcf, 0x7f, 0xfd, 0x15, 0x00, 0x00, + 0xff, 0xff, 0xb3, 0x85, 0x93, 0xfa, 0xd2, 0x01, 0x00, 0x00, } func (m *IncentivizedAcknowledgement) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/29-fee/types/expected_keepers.go b/modules/apps/29-fee/types/expected_keepers.go index f725ff764b3..7fb564f0d9d 100644 --- a/modules/apps/29-fee/types/expected_keepers.go +++ b/modules/apps/29-fee/types/expected_keepers.go @@ -4,8 +4,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // AccountKeeper defines the contract required for account APIs. diff --git a/modules/apps/29-fee/types/fee.go b/modules/apps/29-fee/types/fee.go index 1f979c732d8..774d8857e56 100644 --- a/modules/apps/29-fee/types/fee.go +++ b/modules/apps/29-fee/types/fee.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // NewPacketFee creates and returns a new PacketFee struct including the incentivization fees, refund addres and relayers diff --git a/modules/apps/29-fee/types/fee.pb.go b/modules/apps/29-fee/types/fee.pb.go index 1867eb351e5..d36f5e7cb18 100644 --- a/modules/apps/29-fee/types/fee.pb.go +++ b/modules/apps/29-fee/types/fee.pb.go @@ -7,7 +7,7 @@ import ( fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" - types1 "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + types1 "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -268,7 +268,7 @@ var fileDescriptor_cb3319f1af2a53e5 = []byte{ // 525 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x31, 0x6f, 0x13, 0x31, 0x14, 0xc7, 0x73, 0x09, 0x6a, 0x1b, 0x47, 0x14, 0x74, 0x2a, 0x22, 0x8d, 0xe0, 0x52, 0x3c, 0x65, - 0x89, 0xad, 0xa4, 0x30, 0xc0, 0x04, 0x57, 0x29, 0x52, 0x27, 0xd0, 0x89, 0x89, 0x25, 0xf2, 0xd9, + 0x89, 0xad, 0x84, 0x32, 0xc0, 0x04, 0x57, 0x29, 0x52, 0x27, 0xd0, 0x89, 0x89, 0x25, 0xf2, 0xd9, 0x2f, 0xa9, 0x95, 0xdc, 0xf9, 0x74, 0xbe, 0x44, 0xca, 0xca, 0x27, 0xe0, 0x1b, 0xb0, 0xf3, 0x49, 0xba, 0x20, 0x75, 0x64, 0x0a, 0x28, 0xf9, 0x06, 0xdd, 0x91, 0x90, 0x7d, 0x4e, 0x94, 0x82, 0xaa, 0xaa, 0x12, 0xd3, 0xf9, 0xd9, 0xef, 0xef, 0xdf, 0xb3, 0xdf, 0xff, 0x8c, 0x5e, 0xc8, 0x98, 0x53, @@ -285,20 +285,20 @@ var fileDescriptor_cb3319f1af2a53e5 = []byte{ 0x1d, 0xf9, 0xb0, 0x24, 0x3b, 0xdd, 0xfd, 0xc0, 0x7b, 0x8c, 0x4f, 0x0c, 0xf7, 0xb3, 0x87, 0x1a, 0x85, 0x4c, 0x40, 0xcd, 0x0a, 0x0b, 0xaf, 0xdd, 0x05, 0x1f, 0x38, 0xb8, 0x5f, 0xc2, 0x77, 0xb4, 0xf7, 0x2b, 0x00, 0x39, 0xe5, 0x00, 0x00, 0x7f, 0xf5, 0x50, 0xfd, 0x03, 0xe3, 0x13, 0x30, 0x91, - 0xff, 0x12, 0xd5, 0xca, 0x06, 0x78, 0x9d, 0x46, 0xff, 0x19, 0xb9, 0xc5, 0x0d, 0x64, 0x00, 0x10, - 0x3e, 0x30, 0xc5, 0x44, 0x26, 0xdd, 0x7f, 0x8b, 0x0e, 0x73, 0x18, 0xcd, 0x52, 0x31, 0x64, 0x42, - 0xe4, 0xa0, 0x75, 0xb3, 0x7a, 0xe2, 0x75, 0xea, 0xe1, 0xf1, 0xf5, 0xb2, 0xfd, 0x64, 0xd3, 0xa2, - 0xdd, 0x75, 0x1c, 0x3d, 0x2c, 0x27, 0xde, 0x95, 0xb1, 0xdf, 0x32, 0xdd, 0x9f, 0xb2, 0x05, 0xe4, - 0xda, 0x5e, 0x43, 0x3d, 0xda, 0xc6, 0x38, 0x41, 0x68, 0x5b, 0xa0, 0xf6, 0x87, 0xa8, 0x91, 0xd9, - 0xc8, 0x1c, 0x5b, 0x3b, 0xab, 0xe0, 0x5b, 0x2b, 0xdd, 0x2a, 0xc3, 0xd6, 0xcd, 0xcb, 0xdb, 0xd9, - 0x04, 0x47, 0x28, 0xdb, 0x02, 0xf0, 0x77, 0x0f, 0x1d, 0x9d, 0x0b, 0x48, 0x0b, 0x39, 0x92, 0x20, - 0x76, 0xc8, 0x1f, 0x51, 0xdd, 0x89, 0xa4, 0x70, 0x37, 0xf4, 0xdc, 0x72, 0x8d, 0xc1, 0xc9, 0xc6, - 0xd5, 0x5b, 0xe6, 0xb9, 0x08, 0x9b, 0x0e, 0xf9, 0xf8, 0x06, 0x52, 0x0a, 0x1c, 0x1d, 0x64, 0x2e, - 0xe7, 0xef, 0xf3, 0x54, 0xff, 0xf7, 0x79, 0xc2, 0xf7, 0x97, 0xab, 0xc0, 0xbb, 0x5a, 0x05, 0xde, - 0xaf, 0x55, 0xe0, 0x7d, 0x59, 0x07, 0x95, 0xab, 0x75, 0x50, 0xf9, 0xb1, 0x0e, 0x2a, 0x9f, 0x5e, - 0xfd, 0x6b, 0x18, 0x19, 0xf3, 0xee, 0x58, 0xd1, 0xf9, 0x29, 0x4d, 0x94, 0x98, 0x4d, 0x41, 0x9b, - 0xf7, 0x42, 0xd3, 0xfe, 0xeb, 0xae, 0x79, 0x2a, 0xac, 0x87, 0xe2, 0x3d, 0xfb, 0xe3, 0x9e, 0xfe, - 0x09, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x6c, 0xa2, 0x41, 0x4f, 0x04, 0x00, 0x00, + 0x7f, 0x8a, 0x6a, 0x65, 0x03, 0xbc, 0x4e, 0xa3, 0xff, 0x8c, 0xdc, 0xe2, 0x06, 0x32, 0x00, 0x08, + 0x1f, 0x98, 0x62, 0x22, 0x93, 0xee, 0xbf, 0x45, 0x87, 0x39, 0x8c, 0x66, 0xa9, 0x18, 0x32, 0x21, + 0x72, 0xd0, 0xba, 0x59, 0x3d, 0xf1, 0x3a, 0xf5, 0xf0, 0xf8, 0x7a, 0xd9, 0x7e, 0xb2, 0x69, 0xd1, + 0xee, 0x3a, 0x8e, 0x1e, 0x96, 0x13, 0xef, 0xca, 0xd8, 0x6f, 0x99, 0xee, 0x4f, 0xd9, 0x02, 0x72, + 0x6d, 0xaf, 0xa1, 0x1e, 0x6d, 0x63, 0x9c, 0x20, 0xb4, 0x2d, 0x50, 0xfb, 0x43, 0xd4, 0xc8, 0x6c, + 0x64, 0x8e, 0xad, 0x9d, 0x55, 0xf0, 0xad, 0x95, 0x6e, 0x95, 0x61, 0xeb, 0xe6, 0xe5, 0xed, 0x6c, + 0x82, 0x23, 0x94, 0x6d, 0x01, 0xf8, 0xbb, 0x87, 0x8e, 0xce, 0x05, 0xa4, 0x85, 0x1c, 0x49, 0x10, + 0x3b, 0xe4, 0x8f, 0xa8, 0xee, 0x44, 0x52, 0xb8, 0x1b, 0x7a, 0x6e, 0xb9, 0xc6, 0xe0, 0x64, 0xe3, + 0xea, 0x2d, 0xf3, 0x5c, 0x84, 0x4d, 0x87, 0x7c, 0x7c, 0x03, 0x29, 0x05, 0x8e, 0x0e, 0x32, 0x97, + 0xf3, 0xf7, 0x79, 0xaa, 0xff, 0xfb, 0x3c, 0xe1, 0xfb, 0xcb, 0x55, 0xe0, 0x5d, 0xad, 0x02, 0xef, + 0xd7, 0x2a, 0xf0, 0xbe, 0xac, 0x83, 0xca, 0xd5, 0x3a, 0xa8, 0xfc, 0x58, 0x07, 0x95, 0x4f, 0xaf, + 0xfe, 0x35, 0x8c, 0x8c, 0x79, 0x77, 0xac, 0xe8, 0xfc, 0x94, 0x26, 0x4a, 0xcc, 0xa6, 0xa0, 0xcd, + 0x7b, 0xa1, 0x69, 0xff, 0x75, 0xd7, 0x3c, 0x15, 0xd6, 0x43, 0xf1, 0x9e, 0xfd, 0x71, 0x5f, 0xfe, + 0x09, 0x00, 0x00, 0xff, 0xff, 0x7a, 0x01, 0xeb, 0x42, 0x4f, 0x04, 0x00, 0x00, } func (m *Fee) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/29-fee/types/fee_test.go b/modules/apps/29-fee/types/fee_test.go index 4be71154a6b..3abe0e382b3 100644 --- a/modules/apps/29-fee/types/fee_test.go +++ b/modules/apps/29-fee/types/fee_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" ) var ( diff --git a/modules/apps/29-fee/types/genesis.go b/modules/apps/29-fee/types/genesis.go index 5cd081c75cb..8c9281faa15 100644 --- a/modules/apps/29-fee/types/genesis.go +++ b/modules/apps/29-fee/types/genesis.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // NewGenesisState creates a 29-fee GenesisState instance. diff --git a/modules/apps/29-fee/types/genesis.pb.go b/modules/apps/29-fee/types/genesis.pb.go index 57e676e069f..4fc869a658c 100644 --- a/modules/apps/29-fee/types/genesis.pb.go +++ b/modules/apps/29-fee/types/genesis.pb.go @@ -5,7 +5,7 @@ package types import ( fmt "fmt" - types "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + types "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -358,48 +358,48 @@ func init() { } var fileDescriptor_7191992e856dff95 = []byte{ - // 648 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcd, 0x4e, 0xd4, 0x40, - 0x1c, 0xdf, 0x82, 0x80, 0x0c, 0x06, 0xd8, 0x09, 0x48, 0x05, 0xe9, 0xe2, 0x18, 0x12, 0xa2, 0xd9, - 0x36, 0x7c, 0x78, 0xd0, 0x9b, 0x25, 0x62, 0x36, 0x31, 0x91, 0x8c, 0x9e, 0xbc, 0x6c, 0xba, 0xed, - 0xbf, 0x4b, 0xe3, 0x6e, 0xa7, 0x99, 0x19, 0x96, 0xac, 0x37, 0x4f, 0x5e, 0x7d, 0x0d, 0xe3, 0x23, - 0xf8, 0x02, 0x1c, 0x39, 0x7a, 0xda, 0x18, 0x78, 0x83, 0x7d, 0x02, 0x33, 0x9d, 0x29, 0x2c, 0xfb, - 0x61, 0x38, 0x78, 0x9b, 0xe9, 0xfc, 0xbe, 0xa6, 0xbf, 0xc9, 0x1f, 0x6d, 0x27, 0x8d, 0xd0, 0x0b, - 0xb2, 0xac, 0x95, 0x84, 0x81, 0x4c, 0x58, 0x2a, 0xbc, 0x18, 0xc0, 0xeb, 0xec, 0x7a, 0x4d, 0x48, - 0x41, 0x24, 0xc2, 0xcd, 0x38, 0x93, 0x0c, 0xaf, 0x25, 0x8d, 0xd0, 0x1d, 0x84, 0xb9, 0x31, 0x80, - 0xdb, 0xd9, 0x5d, 0x5f, 0x69, 0xb2, 0x26, 0xcb, 0x31, 0x9e, 0x5a, 0x69, 0xf8, 0xfa, 0x93, 0x49, - 0xaa, 0x8a, 0x35, 0x00, 0x09, 0x19, 0x07, 0x2f, 0x3c, 0x09, 0xd2, 0x14, 0x5a, 0xea, 0xd8, 0x2c, - 0x35, 0x84, 0xfc, 0x9c, 0x41, 0x0f, 0xde, 0xea, 0x18, 0x1f, 0x64, 0x20, 0x01, 0x77, 0xd0, 0x52, - 0x12, 0x41, 0x2a, 0x93, 0x38, 0x81, 0xa8, 0x1e, 0x03, 0x08, 0xdb, 0xda, 0x9a, 0xde, 0x59, 0xd8, - 0xab, 0xba, 0x13, 0xf2, 0xb9, 0xb5, 0x6b, 0xfc, 0x71, 0x10, 0x7e, 0x06, 0x79, 0x04, 0x20, 0x7c, - 0xe7, 0xbc, 0x57, 0x29, 0xf5, 0x7b, 0x95, 0x87, 0xdd, 0xa0, 0xdd, 0x7a, 0x45, 0x86, 0x34, 0x09, - 0x5d, 0xbc, 0xf9, 0xa2, 0xf0, 0xf8, 0xab, 0x85, 0x56, 0x62, 0x80, 0x3a, 0xa4, 0x41, 0xa3, 0x05, - 0x51, 0xdd, 0xc4, 0x14, 0xf6, 0x54, 0xee, 0xfe, 0x6c, 0xa2, 0xfb, 0x11, 0xc0, 0x1b, 0xcd, 0x39, - 0xd4, 0x14, 0xff, 0xa9, 0xb1, 0xde, 0xd0, 0xd6, 0xe3, 0x54, 0x09, 0xc5, 0xf1, 0x30, 0x4f, 0xe0, - 0x33, 0x54, 0xe6, 0xd0, 0x4c, 0x84, 0x04, 0x0e, 0x51, 0x3d, 0x0b, 0xba, 0xea, 0xf6, 0xd3, 0xb9, - 0xff, 0xce, 0x44, 0x7f, 0x7a, 0xcd, 0x38, 0x56, 0x04, 0x7f, 0xcb, 0xb8, 0xdb, 0xda, 0x7d, 0x44, - 0x90, 0xd0, 0x65, 0x7e, 0x9b, 0x22, 0xf0, 0x0f, 0x0b, 0x39, 0x03, 0xc0, 0x90, 0x9d, 0xa6, 0x12, - 0x78, 0x16, 0x70, 0xd9, 0x2d, 0x62, 0xdc, 0xcb, 0x63, 0x1c, 0xdc, 0x21, 0xc6, 0xe1, 0x00, 0x5b, - 0x47, 0xaa, 0x9a, 0x48, 0xdb, 0x23, 0x91, 0xc6, 0x38, 0x11, 0xfa, 0x98, 0x4f, 0xd6, 0x12, 0xf8, - 0x0b, 0x5a, 0x8e, 0x19, 0x3f, 0x0b, 0x78, 0x54, 0xe7, 0xd0, 0x0a, 0xba, 0xc0, 0x85, 0x3d, 0x93, - 0x87, 0x73, 0x27, 0x77, 0xa4, 0x09, 0x54, 0xe3, 0x5f, 0x47, 0x11, 0x07, 0x21, 0xfc, 0x8a, 0x89, - 0xb5, 0x66, 0x7a, 0x1a, 0x52, 0x25, 0x74, 0x29, 0xbe, 0xc5, 0x13, 0xa4, 0x83, 0xca, 0x23, 0x75, - 0xe3, 0xe7, 0x68, 0x2e, 0x63, 0x5c, 0xd6, 0x93, 0xc8, 0xb6, 0xb6, 0xac, 0x9d, 0x79, 0x1f, 0xf7, - 0x7b, 0x95, 0x45, 0xad, 0x69, 0x0e, 0x08, 0x9d, 0x55, 0xab, 0x5a, 0x84, 0x0f, 0x10, 0x32, 0x6f, - 0x40, 0xe1, 0xa7, 0x72, 0xfc, 0x6a, 0xbf, 0x57, 0x29, 0x6b, 0xfc, 0xcd, 0x19, 0xa1, 0xf3, 0x66, - 0x53, 0x8b, 0xc8, 0x19, 0x5a, 0x1a, 0xaa, 0x79, 0x48, 0xc8, 0xba, 0x9b, 0x10, 0xb6, 0xd1, 0x9c, - 0xb9, 0x9e, 0xf6, 0xa6, 0xc5, 0x16, 0xaf, 0xa0, 0x99, 0xfc, 0xff, 0xdb, 0xd3, 0xf9, 0x77, 0xbd, - 0x21, 0xbf, 0x2c, 0xb4, 0xf1, 0x8f, 0x66, 0xff, 0x7b, 0x8a, 0x77, 0x08, 0x8f, 0x3e, 0x09, 0x1d, - 0xc9, 0xdf, 0xec, 0xf7, 0x2a, 0x8f, 0x8c, 0xee, 0x08, 0x86, 0xd0, 0x72, 0x38, 0x9c, 0x8e, 0x7c, - 0xb3, 0xd0, 0xea, 0xd8, 0xea, 0x55, 0x82, 0x40, 0x2f, 0x75, 0x68, 0x5a, 0x6c, 0xf1, 0x47, 0x34, - 0x9f, 0xe5, 0x53, 0xa4, 0xe8, 0x67, 0x61, 0x6f, 0x33, 0x7f, 0x57, 0x6a, 0x8e, 0xb9, 0xc5, 0xf0, - 0xea, 0xec, 0xba, 0x7a, 0xd6, 0xd4, 0x22, 0xdf, 0x36, 0xcf, 0x68, 0xd9, 0x54, 0x5e, 0xb0, 0x09, - 0xbd, 0x9f, 0x15, 0x98, 0xf7, 0xe7, 0x97, 0x8e, 0x75, 0x71, 0xe9, 0x58, 0x7f, 0x2e, 0x1d, 0xeb, - 0xfb, 0x95, 0x53, 0xba, 0xb8, 0x72, 0x4a, 0xbf, 0xaf, 0x9c, 0xd2, 0xa7, 0x17, 0xcd, 0x44, 0x9e, - 0x9c, 0x36, 0xdc, 0x90, 0xb5, 0xbd, 0x90, 0x89, 0x36, 0x13, 0x5e, 0xd2, 0x08, 0xab, 0x4d, 0xe6, - 0x75, 0xf6, 0xbd, 0x36, 0x8b, 0x4e, 0x5b, 0x20, 0xd4, 0x98, 0x15, 0xde, 0xde, 0xcb, 0xaa, 0x9a, - 0xb0, 0xb2, 0x9b, 0x81, 0x68, 0xcc, 0xe6, 0xe3, 0x73, 0xff, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x87, 0x75, 0xda, 0x18, 0xdc, 0x05, 0x00, 0x00, + // 649 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0xcf, 0x4e, 0xd4, 0x4e, + 0x1c, 0xdf, 0xc2, 0x0f, 0xf8, 0x31, 0x18, 0x60, 0x27, 0x20, 0x15, 0xa4, 0x8b, 0x63, 0x48, 0x88, + 0x66, 0xdb, 0x80, 0x78, 0xd0, 0x9b, 0x25, 0x62, 0x36, 0x31, 0x91, 0x8c, 0x9e, 0xbc, 0x6c, 0xba, + 0xed, 0xb7, 0x4b, 0xe3, 0x6e, 0xa7, 0x99, 0x19, 0x96, 0xac, 0x37, 0x4f, 0x5e, 0x7d, 0x0d, 0xe3, + 0x23, 0xf8, 0x02, 0x1c, 0x39, 0x7a, 0xda, 0x18, 0x78, 0x83, 0x7d, 0x02, 0x33, 0x9d, 0x29, 0x2c, + 0xbb, 0xd4, 0x70, 0xf0, 0x36, 0xd3, 0xf9, 0xfc, 0x9b, 0x7e, 0x26, 0x5f, 0xb4, 0x9d, 0xb4, 0x42, + 0x2f, 0xc8, 0xb2, 0x4e, 0x12, 0x06, 0x32, 0x61, 0xa9, 0xf0, 0x62, 0x00, 0xaf, 0xb7, 0xeb, 0xb5, + 0x21, 0x05, 0x91, 0x08, 0x37, 0xe3, 0x4c, 0x32, 0xbc, 0x96, 0xb4, 0x42, 0x77, 0x14, 0xe6, 0xc6, + 0x00, 0x6e, 0x6f, 0x77, 0x7d, 0xa5, 0xcd, 0xda, 0x2c, 0xc7, 0x78, 0x6a, 0xa5, 0xe1, 0xeb, 0x8f, + 0xca, 0x54, 0x15, 0x6b, 0x04, 0x12, 0x32, 0x0e, 0x5e, 0x78, 0x1c, 0xa4, 0x29, 0x74, 0xd4, 0xb1, + 0x59, 0x6a, 0x08, 0xf9, 0x31, 0x83, 0xee, 0xbd, 0xd1, 0x31, 0xde, 0xcb, 0x40, 0x02, 0xee, 0xa1, + 0xa5, 0x24, 0x82, 0x54, 0x26, 0x71, 0x02, 0x51, 0x33, 0x06, 0x10, 0xb6, 0xb5, 0x35, 0xbd, 0xb3, + 0xb0, 0x57, 0x77, 0x4b, 0xf2, 0xb9, 0x8d, 0x2b, 0xfc, 0x51, 0x10, 0x7e, 0x02, 0x79, 0x08, 0x20, + 0x7c, 0xe7, 0x6c, 0x50, 0xab, 0x0c, 0x07, 0xb5, 0xfb, 0xfd, 0xa0, 0xdb, 0x79, 0x49, 0xc6, 0x34, + 0x09, 0x5d, 0xbc, 0xfe, 0xa2, 0xf0, 0xf8, 0x8b, 0x85, 0x56, 0x62, 0x80, 0x26, 0xa4, 0x41, 0xab, + 0x03, 0x51, 0xd3, 0xc4, 0x14, 0xf6, 0x54, 0xee, 0xfe, 0xa4, 0xd4, 0xfd, 0x10, 0xe0, 0xb5, 0xe6, + 0x1c, 0x68, 0x8a, 0xff, 0xd8, 0x58, 0x6f, 0x68, 0xeb, 0xdb, 0x54, 0x09, 0xc5, 0xf1, 0x38, 0x4f, + 0xe0, 0x53, 0x54, 0xe5, 0xd0, 0x4e, 0x84, 0x04, 0x0e, 0x51, 0x33, 0x0b, 0xfa, 0xea, 0xf6, 0xd3, + 0xb9, 0xff, 0x4e, 0xa9, 0x3f, 0xbd, 0x62, 0x1c, 0x29, 0x82, 0xbf, 0x65, 0xdc, 0x6d, 0xed, 0x3e, + 0x21, 0x48, 0xe8, 0x32, 0xbf, 0x49, 0x11, 0xf8, 0xbb, 0x85, 0x9c, 0x11, 0x60, 0xc8, 0x4e, 0x52, + 0x09, 0x3c, 0x0b, 0xb8, 0xec, 0x17, 0x31, 0xfe, 0xcb, 0x63, 0xec, 0xdf, 0x21, 0xc6, 0xc1, 0x08, + 0x5b, 0x47, 0xaa, 0x9b, 0x48, 0xdb, 0x13, 0x91, 0x6e, 0x71, 0x22, 0xf4, 0x21, 0x2f, 0xd7, 0x12, + 0xf8, 0x33, 0x5a, 0x8e, 0x19, 0x3f, 0x0d, 0x78, 0xd4, 0xe4, 0xd0, 0x09, 0xfa, 0xc0, 0x85, 0x3d, + 0x93, 0x87, 0x73, 0xcb, 0x3b, 0xd2, 0x04, 0xaa, 0xf1, 0xaf, 0xa2, 0x88, 0x83, 0x10, 0x7e, 0xcd, + 0xc4, 0x5a, 0x33, 0x3d, 0x8d, 0xa9, 0x12, 0xba, 0x14, 0xdf, 0xe0, 0x09, 0xd2, 0x43, 0xd5, 0x89, + 0xba, 0xf1, 0x53, 0x34, 0x97, 0x31, 0x2e, 0x9b, 0x49, 0x64, 0x5b, 0x5b, 0xd6, 0xce, 0xbc, 0x8f, + 0x87, 0x83, 0xda, 0xa2, 0xd6, 0x34, 0x07, 0x84, 0xce, 0xaa, 0x55, 0x23, 0xc2, 0xfb, 0x08, 0x99, + 0x37, 0xa0, 0xf0, 0x53, 0x39, 0x7e, 0x75, 0x38, 0xa8, 0x55, 0x35, 0xfe, 0xfa, 0x8c, 0xd0, 0x79, + 0xb3, 0x69, 0x44, 0xe4, 0x14, 0x2d, 0x8d, 0xd5, 0x3c, 0x26, 0x64, 0xdd, 0x4d, 0x08, 0xdb, 0x68, + 0xce, 0x5c, 0x4f, 0x7b, 0xd3, 0x62, 0x8b, 0x57, 0xd0, 0x4c, 0xfe, 0xff, 0xed, 0xe9, 0xfc, 0xbb, + 0xde, 0x90, 0x9f, 0x16, 0xda, 0xf8, 0x4b, 0xb3, 0xff, 0x3c, 0xc5, 0x5b, 0x84, 0x27, 0x9f, 0x84, + 0x8e, 0xe4, 0x6f, 0x0e, 0x07, 0xb5, 0x07, 0x46, 0x77, 0x02, 0x43, 0x68, 0x35, 0x1c, 0x4f, 0x47, + 0xbe, 0x5a, 0x68, 0xf5, 0xd6, 0xea, 0x55, 0x82, 0x40, 0x2f, 0x75, 0x68, 0x5a, 0x6c, 0xf1, 0x07, + 0x34, 0x9f, 0xe5, 0x53, 0xa4, 0xe8, 0x67, 0x61, 0x6f, 0x33, 0x7f, 0x57, 0x6a, 0x8e, 0xb9, 0xc5, + 0xf0, 0xea, 0xed, 0xba, 0x7a, 0xd6, 0x34, 0x22, 0xdf, 0x36, 0xcf, 0x68, 0xd9, 0x54, 0x5e, 0xb0, + 0x09, 0xfd, 0x3f, 0x2b, 0x30, 0xef, 0xce, 0x2e, 0x1c, 0xeb, 0xfc, 0xc2, 0xb1, 0x7e, 0x5f, 0x38, + 0xd6, 0xb7, 0x4b, 0xa7, 0x72, 0x7e, 0xe9, 0x54, 0x7e, 0x5d, 0x3a, 0x95, 0x8f, 0xcf, 0xdb, 0x89, + 0x3c, 0x3e, 0x69, 0xb9, 0x21, 0xeb, 0x7a, 0x21, 0x13, 0x5d, 0x26, 0xbc, 0xa4, 0x15, 0xd6, 0xdb, + 0xcc, 0xeb, 0xed, 0x7b, 0x5d, 0x16, 0x9d, 0x74, 0x40, 0xa8, 0x31, 0x2b, 0xbc, 0xbd, 0x17, 0x75, + 0x35, 0x61, 0x65, 0x3f, 0x03, 0xd1, 0x9a, 0xcd, 0xc7, 0xe7, 0xb3, 0x3f, 0x01, 0x00, 0x00, 0xff, + 0xff, 0x3c, 0x18, 0x93, 0x1b, 0xdc, 0x05, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/29-fee/types/genesis_test.go b/modules/apps/29-fee/types/genesis_test.go index d0f6b7ab115..bbec115baf7 100644 --- a/modules/apps/29-fee/types/genesis_test.go +++ b/modules/apps/29-fee/types/genesis_test.go @@ -7,9 +7,9 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func TestValidateDefaultGenesis(t *testing.T) { diff --git a/modules/apps/29-fee/types/keys.go b/modules/apps/29-fee/types/keys.go index 7cbaffcd556..c547432400b 100644 --- a/modules/apps/29-fee/types/keys.go +++ b/modules/apps/29-fee/types/keys.go @@ -7,7 +7,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) const ( diff --git a/modules/apps/29-fee/types/keys_test.go b/modules/apps/29-fee/types/keys_test.go index 94f2c4602b2..26c9158fd7f 100644 --- a/modules/apps/29-fee/types/keys_test.go +++ b/modules/apps/29-fee/types/keys_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var validPacketID = channeltypes.NewPacketId(ibctesting.MockFeePort, ibctesting.FirstChannelID, 1) diff --git a/modules/apps/29-fee/types/metadata.pb.go b/modules/apps/29-fee/types/metadata.pb.go index 95bb9244946..5715cc7e676 100644 --- a/modules/apps/29-fee/types/metadata.pb.go +++ b/modules/apps/29-fee/types/metadata.pb.go @@ -101,10 +101,10 @@ var fileDescriptor_03d0f000eda681ce = []byte{ 0x95, 0x58, 0x50, 0x00, 0xd5, 0xe8, 0xe4, 0x7f, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0xa6, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xc9, 0xf9, - 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x99, 0x49, 0xc9, 0xba, 0xe9, 0xf9, 0xfa, 0x65, 0xc6, 0xfa, 0xb9, + 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0x99, 0x49, 0xc9, 0xba, 0xe9, 0xf9, 0xfa, 0x65, 0x26, 0xfa, 0xb9, 0xf9, 0x29, 0xa5, 0x39, 0xa9, 0xc5, 0xa0, 0xe0, 0x28, 0xd6, 0x37, 0xb2, 0xd4, 0x05, 0x85, 0x44, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0xd8, 0x57, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x04, 0x84, 0x58, 0xe0, 0x2e, 0x01, 0x00, 0x00, + 0xbf, 0xe9, 0x11, 0xe3, 0x2e, 0x01, 0x00, 0x00, } func (m *Metadata) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/29-fee/types/msgs.go b/modules/apps/29-fee/types/msgs.go index 81d22d50422..4b0fd331c9d 100644 --- a/modules/apps/29-fee/types/msgs.go +++ b/modules/apps/29-fee/types/msgs.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // msg types diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go index 5b6cbc8c033..bf12f95784b 100644 --- a/modules/apps/29-fee/types/msgs_test.go +++ b/modules/apps/29-fee/types/msgs_test.go @@ -4,9 +4,9 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/secp256k1" diff --git a/modules/apps/29-fee/types/query.pb.go b/modules/apps/29-fee/types/query.pb.go index 46e12a4e437..87a5f18f894 100644 --- a/modules/apps/29-fee/types/query.pb.go +++ b/modules/apps/29-fee/types/query.pb.go @@ -9,7 +9,7 @@ import ( github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types1 "github.com/cosmos/cosmos-sdk/types" query "github.com/cosmos/cosmos-sdk/types/query" - types "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + types "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -1069,91 +1069,91 @@ func init() { } var fileDescriptor_0638a8a78ca2503c = []byte{ - // 1338 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x5d, 0x6f, 0xdb, 0x54, - 0x18, 0xee, 0xe9, 0x3e, 0xda, 0x9e, 0x76, 0xb0, 0x9c, 0x16, 0x96, 0x86, 0x36, 0xe9, 0x3c, 0x06, - 0xa5, 0x53, 0x6d, 0x35, 0x65, 0x74, 0x43, 0x42, 0xd0, 0x74, 0x74, 0x14, 0x06, 0x94, 0xac, 0x37, - 0x20, 0x50, 0xe6, 0x38, 0x27, 0xa9, 0xd5, 0xd4, 0xc7, 0xb3, 0x9d, 0x88, 0xac, 0x2b, 0xb0, 0x89, - 0x0a, 0x04, 0x08, 0x90, 0x90, 0xb8, 0xe0, 0x1e, 0x21, 0x90, 0xf8, 0x01, 0xfc, 0x83, 0x5d, 0xa1, - 0x4a, 0xdc, 0x20, 0x2e, 0x02, 0x6a, 0x11, 0x3f, 0x20, 0x57, 0x5c, 0x80, 0x84, 0x7c, 0xce, 0xeb, - 0xc4, 0x99, 0xed, 0x36, 0x29, 0xa5, 0x5c, 0xd5, 0xf6, 0x79, 0x3f, 0x9e, 0xe7, 0x39, 0xaf, 0x7d, - 0x9e, 0x14, 0x9f, 0xd3, 0xf3, 0x9a, 0xa2, 0x9a, 0x66, 0x59, 0xd7, 0x54, 0x47, 0x67, 0x86, 0xad, - 0x14, 0x29, 0x55, 0xaa, 0x33, 0xca, 0xcd, 0x0a, 0xb5, 0x6a, 0xb2, 0x69, 0x31, 0x87, 0x91, 0x33, - 0x7a, 0x5e, 0x93, 0xfd, 0x41, 0x72, 0x91, 0x52, 0xb9, 0x3a, 0x93, 0x18, 0x29, 0xb1, 0x12, 0xe3, - 0x31, 0x8a, 0x7b, 0x25, 0xc2, 0x13, 0x63, 0x25, 0xc6, 0x4a, 0x65, 0xaa, 0xa8, 0xa6, 0xae, 0xa8, - 0x86, 0xc1, 0x1c, 0x48, 0x12, 0xab, 0x49, 0x8d, 0xd9, 0xeb, 0xcc, 0x56, 0xf2, 0xaa, 0xed, 0x36, - 0xca, 0x53, 0x47, 0x9d, 0x51, 0x34, 0xa6, 0x1b, 0xb0, 0x3e, 0xe5, 0x5f, 0xe7, 0x28, 0x9a, 0x51, - 0xa6, 0x5a, 0xd2, 0x0d, 0x5e, 0x0c, 0x62, 0xcf, 0x46, 0xa1, 0x77, 0xf1, 0x89, 0x90, 0xf3, 0x51, - 0x21, 0x25, 0x6a, 0x50, 0x5b, 0xb7, 0xfd, 0x95, 0x34, 0x66, 0x51, 0x45, 0x5b, 0x55, 0x0d, 0x83, - 0x96, 0xdd, 0x10, 0xb8, 0x14, 0x21, 0xd2, 0x27, 0x08, 0xa7, 0x5e, 0x73, 0xf1, 0x2c, 0x19, 0x1a, - 0x35, 0x1c, 0xbd, 0xaa, 0xdf, 0xa2, 0x85, 0x65, 0x55, 0x5b, 0xa3, 0x8e, 0x9d, 0xa5, 0x37, 0x2b, - 0xd4, 0x76, 0xc8, 0x22, 0xc6, 0x2d, 0x90, 0x71, 0x34, 0x81, 0x26, 0x07, 0xd3, 0x8f, 0xc9, 0x82, - 0x91, 0xec, 0x32, 0x92, 0x85, 0xae, 0xc0, 0x48, 0x5e, 0x56, 0x4b, 0x14, 0x72, 0xb3, 0xbe, 0x4c, - 0x72, 0x16, 0x0f, 0xf1, 0xc0, 0xdc, 0x2a, 0xd5, 0x4b, 0xab, 0x4e, 0xbc, 0x77, 0x02, 0x4d, 0x1e, - 0xcf, 0x0e, 0xf2, 0x67, 0x2f, 0xf0, 0x47, 0xd2, 0x47, 0x08, 0x4f, 0x44, 0xc3, 0xb1, 0x4d, 0x66, - 0xd8, 0x94, 0x14, 0xf1, 0x88, 0xee, 0x5b, 0xce, 0x99, 0x62, 0x3d, 0x8e, 0x26, 0x8e, 0x4d, 0x0e, - 0xa6, 0xa7, 0xe5, 0x88, 0x8d, 0x95, 0x97, 0x0a, 0x6e, 0x4e, 0x51, 0xf7, 0x2a, 0x2e, 0x52, 0x6a, - 0x67, 0x8e, 0xdf, 0xab, 0xa7, 0x7a, 0xb2, 0xc3, 0x7a, 0xb0, 0x9f, 0xb4, 0x85, 0x70, 0x32, 0x02, - 0x8c, 0x27, 0xcd, 0x73, 0x78, 0x40, 0x74, 0xcf, 0xe9, 0x05, 0x50, 0x66, 0x9c, 0xf7, 0x77, 0x55, - 0x97, 0x3d, 0xa9, 0xab, 0xae, 0x26, 0x6e, 0xd4, 0x52, 0x01, 0xfa, 0xf5, 0x9b, 0x70, 0xdf, 0x89, - 0x28, 0x1f, 0x44, 0xef, 0x51, 0x53, 0x93, 0x02, 0x1e, 0x0e, 0xd1, 0x04, 0x20, 0x1d, 0x48, 0x12, - 0x12, 0x94, 0x44, 0xfa, 0x11, 0xe1, 0x27, 0xa2, 0xb6, 0x67, 0x91, 0x59, 0x0b, 0x82, 0xef, 0x61, - 0xcf, 0xcd, 0x19, 0xdc, 0x67, 0x32, 0x8b, 0x4b, 0xec, 0xaa, 0x33, 0x90, 0x3d, 0xe9, 0xde, 0x2e, - 0x15, 0xc8, 0x38, 0xc6, 0x20, 0xb1, 0xbb, 0x76, 0x8c, 0xaf, 0x0d, 0xc0, 0x93, 0x10, 0x69, 0x8f, - 0x07, 0xa5, 0xfd, 0x14, 0xe1, 0xa9, 0x4e, 0x08, 0x81, 0xca, 0x37, 0x0e, 0x71, 0xf2, 0xc2, 0x67, - 0xee, 0x2d, 0x3c, 0xca, 0xf1, 0xac, 0x30, 0x47, 0x2d, 0x67, 0xa9, 0x56, 0xe5, 0xa1, 0x87, 0x35, - 0x6d, 0xd2, 0x57, 0x08, 0x27, 0xc2, 0xea, 0x03, 0xbf, 0xdb, 0x78, 0xc0, 0xa2, 0x5a, 0x35, 0x57, - 0xa4, 0xd4, 0x23, 0x35, 0xda, 0xb6, 0x61, 0xde, 0x56, 0x2d, 0x30, 0xdd, 0xc8, 0x5c, 0x71, 0x8b, - 0x37, 0xea, 0xa9, 0xd3, 0x35, 0x75, 0xbd, 0xfc, 0xb4, 0xd4, 0xcc, 0x94, 0xbe, 0xfb, 0x35, 0x35, - 0x59, 0xd2, 0x9d, 0xd5, 0x4a, 0x5e, 0xd6, 0xd8, 0xba, 0x02, 0xdf, 0x3e, 0xf1, 0x67, 0xda, 0x2e, - 0xac, 0x29, 0x4e, 0xcd, 0xa4, 0x36, 0x2f, 0x62, 0x67, 0xfb, 0x2d, 0x40, 0x21, 0xbd, 0x89, 0xe3, - 0x2d, 0x6c, 0xf3, 0xda, 0xda, 0xe1, 0x52, 0xff, 0x12, 0xf9, 0xa5, 0x6d, 0x96, 0x07, 0xe6, 0x35, - 0xdc, 0xaf, 0x6a, 0x6b, 0x1d, 0x12, 0x5f, 0x00, 0xe2, 0x0f, 0x0a, 0xe2, 0x5e, 0x62, 0x77, 0xbc, - 0xfb, 0x54, 0x01, 0x41, 0xba, 0x81, 0xc7, 0x5a, 0xb8, 0x56, 0xf4, 0x75, 0xca, 0x2a, 0xce, 0xe1, - 0x52, 0xff, 0x06, 0xe1, 0xf1, 0x88, 0x16, 0x40, 0x7f, 0x0b, 0xe1, 0x21, 0x47, 0x3c, 0xef, 0x50, - 0x83, 0xab, 0xa0, 0xc1, 0xb0, 0xd0, 0xc0, 0x9f, 0xdc, 0x9d, 0x0e, 0x83, 0x4e, 0x0b, 0x8f, 0xa4, - 0xe1, 0x18, 0x07, 0xba, 0xac, 0xd6, 0xa8, 0xf7, 0x2d, 0x20, 0x4f, 0xb6, 0xbd, 0xe6, 0xae, 0x02, - 0x03, 0x99, 0x87, 0x1a, 0xf5, 0x54, 0x4c, 0xb4, 0x6e, 0xad, 0x49, 0xfe, 0xb7, 0x3f, 0x8e, 0xfb, - 0x2c, 0x5a, 0x56, 0x6b, 0xd4, 0x82, 0xaf, 0x86, 0x77, 0x2b, 0x5d, 0xc7, 0xc4, 0xdf, 0x04, 0x24, - 0x78, 0x06, 0x9f, 0x32, 0xdd, 0x07, 0x39, 0xb5, 0x50, 0xb0, 0xa8, 0x6d, 0x43, 0xa3, 0x78, 0xa3, - 0x9e, 0x1a, 0x11, 0x8d, 0xda, 0x96, 0xa5, 0xec, 0x10, 0xbf, 0x9f, 0x87, 0x5b, 0x06, 0x12, 0x2f, - 0xb0, 0x8a, 0xe1, 0x50, 0xcb, 0x54, 0x2d, 0xe7, 0xbf, 0x65, 0x61, 0xc0, 0xe1, 0x14, 0xd2, 0x10, - 0x18, 0x5d, 0xc3, 0x44, 0xf3, 0x2d, 0xe6, 0x38, 0x5e, 0xe8, 0x3c, 0xde, 0xa8, 0xa7, 0x46, 0xa1, - 0x73, 0x20, 0x46, 0xca, 0xc6, 0xb4, 0xfb, 0xab, 0x4a, 0x1f, 0x7b, 0xa7, 0xe1, 0x22, 0xa5, 0xcf, - 0x1b, 0x6a, 0xbe, 0x4c, 0x0b, 0xf0, 0x79, 0xfc, 0x3f, 0x8c, 0xc2, 0xd7, 0xde, 0x99, 0x18, 0x86, - 0x06, 0xf8, 0xdf, 0x41, 0x78, 0xa4, 0x48, 0x69, 0x8e, 0x8a, 0xf5, 0x1c, 0xa8, 0xea, 0x0d, 0xf7, - 0x54, 0xe4, 0xe7, 0x3a, 0x50, 0x33, 0x73, 0x0e, 0xa6, 0xfd, 0x11, 0x21, 0x59, 0x58, 0x55, 0x29, - 0x4b, 0x8a, 0x01, 0x2c, 0xd2, 0x5d, 0xef, 0xd5, 0x0b, 0xd4, 0xf4, 0x44, 0xbb, 0xd0, 0x3a, 0xdd, - 0xc4, 0xd6, 0x90, 0x46, 0x3d, 0xf5, 0x00, 0x4c, 0x9c, 0x58, 0x90, 0x9a, 0x27, 0x5e, 0xfb, 0x10, - 0xf5, 0x76, 0x36, 0x44, 0xd2, 0xeb, 0x51, 0x3b, 0xd7, 0x94, 0x6a, 0x0e, 0x0f, 0xfa, 0x38, 0x71, - 0x20, 0xfd, 0x99, 0x87, 0x1b, 0xf5, 0x14, 0x09, 0x10, 0x96, 0xb2, 0xb8, 0xc5, 0x33, 0xfd, 0x47, - 0x0c, 0x9f, 0xe0, 0xb5, 0xc9, 0x0f, 0x08, 0x0f, 0x87, 0x9c, 0xa2, 0xe4, 0x52, 0xa4, 0xcc, 0xfb, - 0xf8, 0xce, 0xc4, 0xe5, 0x03, 0x64, 0x0a, 0x3e, 0xd2, 0xf4, 0xdd, 0x9f, 0x7e, 0xff, 0xa2, 0xf7, - 0x71, 0x72, 0x5e, 0x01, 0xa7, 0xdc, 0x74, 0xc8, 0x61, 0xe7, 0x37, 0xf9, 0xac, 0x17, 0x93, 0x60, - 0x39, 0x32, 0xd7, 0x2d, 0x00, 0x0f, 0xf9, 0xa5, 0xee, 0x13, 0x01, 0xf8, 0x16, 0xe2, 0xc8, 0xdf, - 0x25, 0x9b, 0x01, 0xe4, 0xde, 0xa0, 0x29, 0x1b, 0xcd, 0xe3, 0x40, 0x6e, 0x6d, 0xf8, 0xa6, 0xe2, - 0x8e, 0x48, 0xdb, 0x22, 0x4c, 0xcf, 0xa6, 0x62, 0xbb, 0xb0, 0x0c, 0x8d, 0xb6, 0xad, 0x7a, 0x0f, - 0x37, 0xc3, 0x24, 0x21, 0x7f, 0x23, 0x3c, 0xbe, 0xa7, 0x27, 0x22, 0x99, 0xae, 0x77, 0x27, 0xe0, - 0x10, 0x13, 0x0b, 0xff, 0xaa, 0x06, 0x48, 0x76, 0x9d, 0x2b, 0xf6, 0x32, 0x79, 0x69, 0x0f, 0xc5, - 0xc2, 0x74, 0xf2, 0xd4, 0x09, 0x9d, 0x88, 0xbf, 0x10, 0x3e, 0xd5, 0xe6, 0x91, 0x48, 0x7a, 0x6f, - 0xac, 0x61, 0x86, 0x2d, 0x31, 0xdb, 0x55, 0x0e, 0xf0, 0xb9, 0x23, 0x46, 0x60, 0x83, 0xd4, 0x8e, - 0x6e, 0x04, 0x1c, 0x17, 0x49, 0xae, 0xe9, 0xe0, 0xc8, 0x9f, 0x08, 0x0f, 0xf9, 0x7d, 0x12, 0x99, - 0xe9, 0x80, 0x49, 0xbb, 0x65, 0x4b, 0xa4, 0xbb, 0x49, 0x01, 0xee, 0xef, 0x09, 0xee, 0xb7, 0xc8, - 0xdb, 0x47, 0xcd, 0xdd, 0x33, 0x71, 0xe4, 0xc3, 0x5e, 0x7c, 0xfa, 0x7e, 0x9f, 0x44, 0x2e, 0x76, - 0xc0, 0x25, 0x68, 0xdd, 0x12, 0x4f, 0x75, 0x9b, 0x06, 0x32, 0xbc, 0x2f, 0x64, 0x78, 0x87, 0xdc, - 0x3e, 0x6a, 0x19, 0xfc, 0x3e, 0x8e, 0x7c, 0x8b, 0xf0, 0x09, 0x7e, 0xf8, 0x93, 0xa9, 0xbd, 0x89, - 0xf8, 0x8d, 0x4e, 0xe2, 0x42, 0x47, 0xb1, 0xc0, 0xf4, 0x2a, 0x27, 0x3a, 0x4f, 0x9e, 0xed, 0xf0, - 0xe5, 0x05, 0xf7, 0x63, 0x2b, 0x1b, 0x70, 0xb5, 0xa9, 0x70, 0xcb, 0x42, 0x7e, 0x41, 0x38, 0x16, - 0xb0, 0x42, 0x64, 0x9f, 0x0d, 0x88, 0x32, 0x6b, 0x89, 0xb9, 0xae, 0xf3, 0x80, 0xcf, 0x0a, 0xe7, - 0xf3, 0x0a, 0xb9, 0x76, 0x70, 0x3e, 0x41, 0x3f, 0x46, 0xbe, 0x47, 0x98, 0x04, 0x8d, 0xce, 0x7e, - 0xe7, 0x53, 0xa4, 0x51, 0xdb, 0xef, 0x7c, 0x8a, 0xf6, 0x54, 0xd2, 0xa3, 0x9c, 0x5f, 0x92, 0x8c, - 0x05, 0xf8, 0xf9, 0x2c, 0x02, 0xd9, 0x46, 0x38, 0x16, 0x28, 0xb2, 0xdf, 0x66, 0x44, 0x39, 0xa4, - 0xc4, 0x5c, 0xd7, 0x79, 0x00, 0xf6, 0x45, 0x0e, 0xf6, 0x0a, 0xc9, 0x1c, 0xf0, 0x64, 0xf0, 0x51, - 0xca, 0xbc, 0x7a, 0x6f, 0x27, 0x89, 0xb6, 0x77, 0x92, 0xe8, 0xb7, 0x9d, 0x24, 0xfa, 0x7c, 0x37, - 0xd9, 0xb3, 0xbd, 0x9b, 0xec, 0xf9, 0x79, 0x37, 0xd9, 0xf3, 0xc6, 0xc5, 0xe0, 0x4f, 0x1d, 0x3d, - 0xaf, 0x4d, 0x97, 0x98, 0x52, 0x9d, 0x55, 0xd6, 0x59, 0xa1, 0x52, 0xa6, 0xb6, 0x68, 0x9e, 0xbe, - 0x3c, 0xed, 0xf6, 0xe7, 0xbf, 0x7e, 0xf2, 0x27, 0xf9, 0x3f, 0xe0, 0x66, 0xff, 0x09, 0x00, 0x00, - 0xff, 0xff, 0x15, 0xfb, 0x28, 0xf6, 0xad, 0x14, 0x00, 0x00, + // 1340 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x5f, 0x6f, 0xdb, 0xd4, + 0x1b, 0xee, 0xe9, 0xba, 0xb5, 0x3d, 0xed, 0x7e, 0xbf, 0xe5, 0xb4, 0xb0, 0x34, 0xb4, 0x49, 0xe7, + 0x31, 0x28, 0x9d, 0x6a, 0xab, 0xd9, 0x46, 0x37, 0x24, 0x04, 0x4d, 0x47, 0x47, 0x61, 0x40, 0xc9, + 0x7a, 0x03, 0x02, 0x65, 0x8e, 0x73, 0x92, 0x5a, 0x4d, 0x7d, 0x3c, 0xdb, 0x89, 0xc8, 0xba, 0x02, + 0x9b, 0xa8, 0x40, 0x80, 0x00, 0x09, 0x89, 0x0b, 0xee, 0x11, 0x02, 0x89, 0x0f, 0xc0, 0x37, 0xd8, + 0x15, 0xaa, 0xc4, 0x0d, 0xe2, 0x22, 0xa0, 0x16, 0xf1, 0x01, 0x72, 0xc5, 0x05, 0x48, 0xc8, 0xe7, + 0xbc, 0x4e, 0x9c, 0xd9, 0x6e, 0x93, 0x52, 0xca, 0x55, 0x6d, 0x9f, 0xf7, 0xcf, 0xf3, 0x3c, 0xe7, + 0xb5, 0xcf, 0x93, 0xe2, 0xb3, 0x7a, 0x5e, 0x53, 0x54, 0xd3, 0x2c, 0xeb, 0x9a, 0xea, 0xe8, 0xcc, + 0xb0, 0x95, 0x22, 0xa5, 0x4a, 0x75, 0x56, 0xb9, 0x55, 0xa1, 0x56, 0x4d, 0x36, 0x2d, 0xe6, 0x30, + 0x72, 0x5a, 0xcf, 0x6b, 0xb2, 0x3f, 0x48, 0x2e, 0x52, 0x2a, 0x57, 0x67, 0x13, 0xa3, 0x25, 0x56, + 0x62, 0x3c, 0x46, 0x71, 0xaf, 0x44, 0x78, 0x62, 0xbc, 0xc4, 0x58, 0xa9, 0x4c, 0x15, 0xd5, 0xd4, + 0x15, 0xd5, 0x30, 0x98, 0x03, 0x49, 0x62, 0x35, 0xa9, 0x31, 0x7b, 0x9d, 0xd9, 0x4a, 0x5e, 0xb5, + 0xdd, 0x46, 0x79, 0xea, 0xa8, 0xb3, 0x8a, 0xc6, 0x74, 0x03, 0xd6, 0xa7, 0xfd, 0xeb, 0x1c, 0x45, + 0x33, 0xca, 0x54, 0x4b, 0xba, 0xc1, 0x8b, 0x41, 0xec, 0x99, 0x28, 0xf4, 0x2e, 0x3e, 0x11, 0x72, + 0x2e, 0x2a, 0xa4, 0x44, 0x0d, 0x6a, 0xeb, 0xb6, 0xbf, 0x92, 0xc6, 0x2c, 0xaa, 0x68, 0xab, 0xaa, + 0x61, 0xd0, 0xb2, 0x1b, 0x02, 0x97, 0x22, 0x44, 0xfa, 0x18, 0xe1, 0xd4, 0xab, 0x2e, 0x9e, 0x25, + 0x43, 0xa3, 0x86, 0xa3, 0x57, 0xf5, 0xdb, 0xb4, 0xb0, 0xac, 0x6a, 0x6b, 0xd4, 0xb1, 0xb3, 0xf4, + 0x56, 0x85, 0xda, 0x0e, 0x59, 0xc4, 0xb8, 0x05, 0x32, 0x8e, 0x26, 0xd1, 0xd4, 0x50, 0xfa, 0x31, + 0x59, 0x30, 0x92, 0x5d, 0x46, 0xb2, 0xd0, 0x15, 0x18, 0xc9, 0xcb, 0x6a, 0x89, 0x42, 0x6e, 0xd6, + 0x97, 0x49, 0xce, 0xe0, 0x61, 0x1e, 0x98, 0x5b, 0xa5, 0x7a, 0x69, 0xd5, 0x89, 0xf7, 0x4e, 0xa2, + 0xa9, 0xbe, 0xec, 0x10, 0x7f, 0xf6, 0x3c, 0x7f, 0x24, 0x7d, 0x88, 0xf0, 0x64, 0x34, 0x1c, 0xdb, + 0x64, 0x86, 0x4d, 0x49, 0x11, 0x8f, 0xea, 0xbe, 0xe5, 0x9c, 0x29, 0xd6, 0xe3, 0x68, 0xf2, 0xd8, + 0xd4, 0x50, 0x7a, 0x46, 0x8e, 0xd8, 0x58, 0x79, 0xa9, 0xe0, 0xe6, 0x14, 0x75, 0xaf, 0xe2, 0x22, + 0xa5, 0x76, 0xa6, 0xef, 0x7e, 0x3d, 0xd5, 0x93, 0x1d, 0xd1, 0x83, 0xfd, 0xa4, 0x2d, 0x84, 0x93, + 0x11, 0x60, 0x3c, 0x69, 0x9e, 0xc5, 0x83, 0xa2, 0x7b, 0x4e, 0x2f, 0x80, 0x32, 0x13, 0xbc, 0xbf, + 0xab, 0xba, 0xec, 0x49, 0x5d, 0x75, 0x35, 0x71, 0xa3, 0x96, 0x0a, 0xd0, 0x6f, 0xc0, 0x84, 0xfb, + 0x4e, 0x44, 0x79, 0x3f, 0x7a, 0x8f, 0x9a, 0x9a, 0x14, 0xf0, 0x48, 0x88, 0x26, 0x00, 0xe9, 0x40, + 0x92, 0x90, 0xa0, 0x24, 0xd2, 0x0f, 0x08, 0x3f, 0x11, 0xb5, 0x3d, 0x8b, 0xcc, 0x5a, 0x10, 0x7c, + 0x0f, 0x7b, 0x6e, 0x4e, 0xe3, 0x7e, 0x93, 0x59, 0x5c, 0x62, 0x57, 0x9d, 0xc1, 0xec, 0x09, 0xf7, + 0x76, 0xa9, 0x40, 0x26, 0x30, 0x06, 0x89, 0xdd, 0xb5, 0x63, 0x7c, 0x6d, 0x10, 0x9e, 0x84, 0x48, + 0xdb, 0x17, 0x94, 0xf6, 0x13, 0x84, 0xa7, 0x3b, 0x21, 0x04, 0x2a, 0xdf, 0x3c, 0xc4, 0xc9, 0x0b, + 0x9f, 0xb9, 0x37, 0xf1, 0x18, 0xc7, 0xb3, 0xc2, 0x1c, 0xb5, 0x9c, 0xa5, 0x5a, 0x95, 0x87, 0x1e, + 0xd6, 0xb4, 0x49, 0x5f, 0x22, 0x9c, 0x08, 0xab, 0x0f, 0xfc, 0xee, 0xe0, 0x41, 0x8b, 0x6a, 0xd5, + 0x5c, 0x91, 0x52, 0x8f, 0xd4, 0x58, 0xdb, 0x86, 0x79, 0x5b, 0xb5, 0xc0, 0x74, 0x23, 0x73, 0xd5, + 0x2d, 0xde, 0xa8, 0xa7, 0x4e, 0xd5, 0xd4, 0xf5, 0xf2, 0x53, 0x52, 0x33, 0x53, 0xfa, 0xf6, 0x97, + 0xd4, 0x54, 0x49, 0x77, 0x56, 0x2b, 0x79, 0x59, 0x63, 0xeb, 0x0a, 0x7c, 0xfb, 0xc4, 0x9f, 0x19, + 0xbb, 0xb0, 0xa6, 0x38, 0x35, 0x93, 0xda, 0xbc, 0x88, 0x9d, 0x1d, 0xb0, 0x00, 0x85, 0xf4, 0x06, + 0x8e, 0xb7, 0xb0, 0xcd, 0x6b, 0x6b, 0x87, 0x4b, 0xfd, 0x0b, 0xe4, 0x97, 0xb6, 0x59, 0x1e, 0x98, + 0xd7, 0xf0, 0x80, 0xaa, 0xad, 0x75, 0x48, 0x7c, 0x01, 0x88, 0xff, 0x5f, 0x10, 0xf7, 0x12, 0xbb, + 0xe3, 0xdd, 0xaf, 0x0a, 0x08, 0xd2, 0x4d, 0x3c, 0xde, 0xc2, 0xb5, 0xa2, 0xaf, 0x53, 0x56, 0x71, + 0x0e, 0x97, 0xfa, 0xd7, 0x08, 0x4f, 0x44, 0xb4, 0x00, 0xfa, 0x5b, 0x08, 0x0f, 0x3b, 0xe2, 0x79, + 0x87, 0x1a, 0x5c, 0x03, 0x0d, 0x46, 0x84, 0x06, 0xfe, 0xe4, 0xee, 0x74, 0x18, 0x72, 0x5a, 0x78, + 0x24, 0x0d, 0xc7, 0x38, 0xd0, 0x65, 0xb5, 0x46, 0xbd, 0x6f, 0x01, 0xb9, 0xd8, 0xf6, 0x9a, 0xbb, + 0x0a, 0x0c, 0x66, 0x1e, 0x6a, 0xd4, 0x53, 0x31, 0xd1, 0xba, 0xb5, 0x26, 0xf9, 0xdf, 0xfe, 0x38, + 0xee, 0xb7, 0x68, 0x59, 0xad, 0x51, 0x0b, 0xbe, 0x1a, 0xde, 0xad, 0x74, 0x03, 0x13, 0x7f, 0x13, + 0x90, 0xe0, 0x69, 0x7c, 0xd2, 0x74, 0x1f, 0xe4, 0xd4, 0x42, 0xc1, 0xa2, 0xb6, 0x0d, 0x8d, 0xe2, + 0x8d, 0x7a, 0x6a, 0x54, 0x34, 0x6a, 0x5b, 0x96, 0xb2, 0xc3, 0xfc, 0x7e, 0x1e, 0x6e, 0x19, 0x48, + 0xbc, 0xc0, 0x2a, 0x86, 0x43, 0x2d, 0x53, 0xb5, 0x9c, 0x7f, 0x97, 0x85, 0x01, 0x87, 0x53, 0x48, + 0x43, 0x60, 0x74, 0x1d, 0x13, 0xcd, 0xb7, 0x98, 0xe3, 0x78, 0xa1, 0xf3, 0x44, 0xa3, 0x9e, 0x1a, + 0x83, 0xce, 0x81, 0x18, 0x29, 0x1b, 0xd3, 0x1e, 0xac, 0x2a, 0x7d, 0xe4, 0x9d, 0x86, 0x8b, 0x94, + 0x3e, 0x67, 0xa8, 0xf9, 0x32, 0x2d, 0xc0, 0xe7, 0xf1, 0xbf, 0x30, 0x0a, 0x5f, 0x79, 0x67, 0x62, + 0x18, 0x1a, 0xe0, 0x7f, 0x17, 0xe1, 0xd1, 0x22, 0xa5, 0x39, 0x2a, 0xd6, 0x73, 0xa0, 0xaa, 0x37, + 0xdc, 0xd3, 0x91, 0x9f, 0xeb, 0x40, 0xcd, 0xcc, 0x59, 0x98, 0xf6, 0x47, 0x84, 0x64, 0x61, 0x55, + 0xa5, 0x2c, 0x29, 0x06, 0xb0, 0x48, 0xf7, 0xbc, 0x57, 0x2f, 0x50, 0xd3, 0x13, 0xed, 0x7c, 0xeb, + 0x74, 0x13, 0x5b, 0x43, 0x1a, 0xf5, 0xd4, 0xff, 0x60, 0xe2, 0xc4, 0x82, 0xd4, 0x3c, 0xf1, 0xda, + 0x87, 0xa8, 0xb7, 0xb3, 0x21, 0x92, 0x5e, 0x8b, 0xda, 0xb9, 0xa6, 0x54, 0x73, 0x78, 0xc8, 0xc7, + 0x89, 0x03, 0x19, 0xc8, 0x3c, 0xdc, 0xa8, 0xa7, 0x48, 0x80, 0xb0, 0x94, 0xc5, 0x2d, 0x9e, 0xe9, + 0xdf, 0x63, 0xf8, 0x38, 0xaf, 0x4d, 0xbe, 0x47, 0x78, 0x24, 0xe4, 0x14, 0x25, 0x97, 0x23, 0x65, + 0xde, 0xc7, 0x77, 0x26, 0xae, 0x1c, 0x20, 0x53, 0xf0, 0x91, 0x66, 0xee, 0xfd, 0xf8, 0xdb, 0xe7, + 0xbd, 0x8f, 0x93, 0x73, 0x0a, 0x38, 0xe5, 0xa6, 0x43, 0x0e, 0x3b, 0xbf, 0xc9, 0xa7, 0xbd, 0x98, + 0x04, 0xcb, 0x91, 0xb9, 0x6e, 0x01, 0x78, 0xc8, 0x2f, 0x77, 0x9f, 0x08, 0xc0, 0xb7, 0x10, 0x47, + 0xfe, 0x0e, 0xd9, 0x0c, 0x20, 0xf7, 0x06, 0x4d, 0xd9, 0x68, 0x1e, 0x07, 0x72, 0x6b, 0xc3, 0x37, + 0x15, 0x77, 0x44, 0xda, 0x16, 0x61, 0x7a, 0x36, 0x15, 0xdb, 0x85, 0x65, 0x68, 0xb4, 0x6d, 0xd5, + 0x7b, 0xb8, 0x19, 0x26, 0x09, 0xf9, 0x0b, 0xe1, 0x89, 0x3d, 0x3d, 0x11, 0xc9, 0x74, 0xbd, 0x3b, + 0x01, 0x87, 0x98, 0x58, 0xf8, 0x47, 0x35, 0x40, 0xb2, 0x1b, 0x5c, 0xb1, 0x97, 0xc8, 0x8b, 0x7b, + 0x28, 0x16, 0xa6, 0x93, 0xa7, 0x4e, 0xe8, 0x44, 0xfc, 0x89, 0xf0, 0xc9, 0x36, 0x8f, 0x44, 0xd2, + 0x7b, 0x63, 0x0d, 0x33, 0x6c, 0x89, 0x0b, 0x5d, 0xe5, 0x00, 0x9f, 0xbb, 0x62, 0x04, 0x36, 0x48, + 0xed, 0xe8, 0x46, 0xc0, 0x71, 0x91, 0xe4, 0x9a, 0x0e, 0x8e, 0xfc, 0x81, 0xf0, 0xb0, 0xdf, 0x27, + 0x91, 0xd9, 0x0e, 0x98, 0xb4, 0x5b, 0xb6, 0x44, 0xba, 0x9b, 0x14, 0xe0, 0xfe, 0xae, 0xe0, 0x7e, + 0x9b, 0xbc, 0x75, 0xd4, 0xdc, 0x3d, 0x13, 0x47, 0x3e, 0xe8, 0xc5, 0xa7, 0x1e, 0xf4, 0x49, 0xe4, + 0x52, 0x07, 0x5c, 0x82, 0xd6, 0x2d, 0xf1, 0x64, 0xb7, 0x69, 0x20, 0xc3, 0x7b, 0x42, 0x86, 0xb7, + 0xc9, 0x9d, 0xa3, 0x96, 0xc1, 0xef, 0xe3, 0xc8, 0x37, 0x08, 0x1f, 0xe7, 0x87, 0x3f, 0x99, 0xde, + 0x9b, 0x88, 0xdf, 0xe8, 0x24, 0xce, 0x77, 0x14, 0x0b, 0x4c, 0xaf, 0x71, 0xa2, 0xf3, 0xe4, 0x99, + 0x0e, 0x5f, 0x5e, 0x70, 0x3f, 0xb6, 0xb2, 0x01, 0x57, 0x9b, 0x0a, 0xb7, 0x2c, 0xe4, 0x67, 0x84, + 0x63, 0x01, 0x2b, 0x44, 0xf6, 0xd9, 0x80, 0x28, 0xb3, 0x96, 0x98, 0xeb, 0x3a, 0x0f, 0xf8, 0xac, + 0x70, 0x3e, 0x2f, 0x93, 0xeb, 0x07, 0xe7, 0x13, 0xf4, 0x63, 0xe4, 0x3b, 0x84, 0x49, 0xd0, 0xe8, + 0xec, 0x77, 0x3e, 0x45, 0x1a, 0xb5, 0xfd, 0xce, 0xa7, 0x68, 0x4f, 0x25, 0x3d, 0xca, 0xf9, 0x25, + 0xc9, 0x78, 0x80, 0x9f, 0xcf, 0x22, 0x90, 0x6d, 0x84, 0x63, 0x81, 0x22, 0xfb, 0x6d, 0x46, 0x94, + 0x43, 0x4a, 0xcc, 0x75, 0x9d, 0x07, 0x60, 0x5f, 0xe0, 0x60, 0xaf, 0x92, 0xcc, 0x01, 0x4f, 0x06, + 0x1f, 0xa5, 0xcc, 0x2b, 0xf7, 0x77, 0x92, 0x68, 0x7b, 0x27, 0x89, 0x7e, 0xdd, 0x49, 0xa2, 0xcf, + 0x76, 0x93, 0x3d, 0xdb, 0xbb, 0xc9, 0x9e, 0x9f, 0x76, 0x93, 0x3d, 0xaf, 0x5f, 0x0a, 0xfe, 0xd4, + 0xd1, 0xf3, 0xda, 0x4c, 0x89, 0x29, 0xd5, 0x8b, 0xca, 0x3a, 0x2b, 0x54, 0xca, 0xd4, 0x16, 0xcd, + 0xd3, 0x57, 0x66, 0xdc, 0xfe, 0xfc, 0xd7, 0x4f, 0xfe, 0x04, 0xff, 0x07, 0xdc, 0x85, 0xbf, 0x03, + 0x00, 0x00, 0xff, 0xff, 0xae, 0x96, 0x61, 0xf5, 0xad, 0x14, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/apps/29-fee/types/tx.pb.go b/modules/apps/29-fee/types/tx.pb.go index e62ca434e8d..4eec969d2c2 100644 --- a/modules/apps/29-fee/types/tx.pb.go +++ b/modules/apps/29-fee/types/tx.pb.go @@ -6,7 +6,7 @@ package types import ( context "context" fmt "fmt" - types "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + types "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -372,51 +372,51 @@ func init() { func init() { proto.RegisterFile("ibc/applications/fee/v1/tx.proto", fileDescriptor_05c93128649f1b96) } var fileDescriptor_05c93128649f1b96 = []byte{ - // 699 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0x4f, 0x4f, 0xdb, 0x4a, - 0x10, 0x8f, 0x09, 0xff, 0x32, 0xf0, 0x80, 0xac, 0xe0, 0xe1, 0x58, 0x10, 0xf3, 0xac, 0xa7, 0x27, - 0x9e, 0x2a, 0xec, 0x26, 0xc0, 0xa1, 0x48, 0x55, 0x55, 0x23, 0xa1, 0x22, 0x15, 0x35, 0xb2, 0x7a, - 0xaa, 0x2a, 0x21, 0xc7, 0xd9, 0x18, 0xb7, 0x89, 0xd7, 0xf2, 0x3a, 0x51, 0xfd, 0x0d, 0x7a, 0xa4, - 0xdf, 0x80, 0x6f, 0xd0, 0xaf, 0xc1, 0x91, 0x43, 0x0f, 0x3d, 0x59, 0x15, 0x5c, 0x7a, 0xab, 0x94, - 0x7e, 0x81, 0x6a, 0xed, 0xb5, 0xeb, 0x24, 0x0a, 0x4a, 0x7b, 0xea, 0x6d, 0x67, 0xe6, 0x37, 0xbf, - 0x9d, 0xf9, 0x79, 0xc6, 0x0b, 0x3b, 0x4e, 0xd3, 0xd2, 0x4c, 0xcf, 0xeb, 0x38, 0x96, 0x19, 0x38, - 0xc4, 0xa5, 0x5a, 0x1b, 0x63, 0xad, 0x5f, 0xd3, 0x82, 0x77, 0xaa, 0xe7, 0x93, 0x80, 0xa0, 0x4d, - 0xa7, 0x69, 0xa9, 0x79, 0x84, 0xda, 0xc6, 0x58, 0xed, 0xd7, 0xa4, 0x75, 0x9b, 0xd8, 0x24, 0xc6, - 0x68, 0xec, 0x94, 0xc0, 0xa5, 0x7f, 0x26, 0x11, 0xb2, 0xac, 0x1c, 0xc4, 0x22, 0x3e, 0xd6, 0xac, - 0x0b, 0xd3, 0x75, 0x71, 0x87, 0x85, 0xf9, 0x31, 0x81, 0x28, 0x1f, 0x05, 0x58, 0x3b, 0xa3, 0xb6, - 0x81, 0x6d, 0x87, 0x06, 0xd8, 0x6f, 0x98, 0x21, 0xc6, 0xe8, 0x01, 0x2c, 0x78, 0xc4, 0x0f, 0xce, - 0x9d, 0x96, 0x28, 0xec, 0x08, 0xbb, 0x25, 0x1d, 0x0d, 0x22, 0x79, 0x25, 0x34, 0xbb, 0x9d, 0x23, - 0x85, 0x07, 0x14, 0x63, 0x9e, 0x9d, 0x4e, 0x5b, 0xe8, 0x00, 0x80, 0x53, 0x32, 0xfc, 0x4c, 0x8c, - 0xdf, 0x18, 0x44, 0x72, 0x39, 0xc1, 0xff, 0x8c, 0x29, 0x46, 0x89, 0x1b, 0xa7, 0x2d, 0x24, 0xc2, - 0x82, 0x8f, 0x3b, 0x66, 0x88, 0x7d, 0xb1, 0xc8, 0x52, 0x8c, 0xd4, 0x44, 0xeb, 0x30, 0xe7, 0xb1, - 0x2a, 0xc4, 0xd9, 0xd8, 0x9f, 0x18, 0x47, 0x8b, 0xef, 0xaf, 0xe4, 0xc2, 0xd7, 0x2b, 0xb9, 0xa0, - 0x48, 0x20, 0x8e, 0x16, 0x6c, 0x60, 0xea, 0x11, 0x97, 0x62, 0xe5, 0xbb, 0x00, 0x5b, 0xb9, 0xe0, - 0x31, 0xe9, 0xb9, 0x01, 0xf6, 0x3d, 0xd3, 0x0f, 0xc2, 0x3f, 0xa0, 0xb3, 0xe7, 0x80, 0xac, 0x5c, - 0x45, 0xe7, 0xb9, 0x36, 0xf5, 0xed, 0x41, 0x24, 0x57, 0x38, 0xef, 0x18, 0x46, 0x31, 0xca, 0xd6, - 0x68, 0x2b, 0x39, 0x45, 0xfe, 0x83, 0x7f, 0xef, 0x6b, 0x3a, 0x53, 0xe7, 0x72, 0x06, 0x56, 0xcf, - 0xa8, 0xdd, 0x30, 0xc3, 0x86, 0x69, 0xbd, 0xc5, 0xc1, 0x09, 0xc6, 0xe8, 0x00, 0x8a, 0x6d, 0x8c, - 0x63, 0x31, 0x96, 0xea, 0x5b, 0xea, 0x84, 0x11, 0x54, 0x4f, 0x30, 0xd6, 0x67, 0xaf, 0x23, 0xb9, - 0x60, 0x30, 0x38, 0x7a, 0x02, 0x2b, 0x94, 0xf4, 0x7c, 0x0b, 0x9f, 0xa7, 0x6a, 0x26, 0xea, 0x54, - 0x06, 0x91, 0xbc, 0x91, 0x74, 0x31, 0x1c, 0x57, 0x8c, 0xe5, 0xc4, 0xd1, 0x48, 0xa4, 0x7d, 0x06, - 0x65, 0x0e, 0xc8, 0x29, 0x1c, 0xcb, 0xa5, 0x6f, 0x0d, 0x22, 0x59, 0x1c, 0xe2, 0xc8, 0x0b, 0xbd, - 0x9a, 0xf8, 0x8e, 0x33, 0xb9, 0xff, 0x86, 0x79, 0xea, 0xd8, 0x2e, 0xf6, 0xf9, 0xbc, 0x70, 0x0b, - 0x49, 0xb0, 0xc8, 0x75, 0xa7, 0xe2, 0xdc, 0x4e, 0x71, 0xb7, 0x64, 0x64, 0x76, 0x4e, 0xba, 0x0a, - 0x6c, 0x8e, 0x28, 0x92, 0xa9, 0xf5, 0x49, 0x80, 0xf5, 0x91, 0xd8, 0x53, 0x1a, 0xba, 0x16, 0x7a, - 0x09, 0x25, 0x2f, 0xf6, 0xa4, 0x53, 0xb4, 0x54, 0xdf, 0x8e, 0x85, 0x63, 0x9b, 0xa6, 0xa6, 0xeb, - 0xd5, 0xaf, 0xa9, 0x49, 0xde, 0x69, 0x4b, 0x17, 0x99, 0x72, 0x83, 0x48, 0x5e, 0xe3, 0x83, 0x96, - 0x66, 0x2b, 0xc6, 0xa2, 0xc7, 0x31, 0xe8, 0x35, 0x00, 0xf7, 0xb3, 0xef, 0x31, 0x13, 0xd3, 0x2a, - 0x13, 0xbf, 0x47, 0x56, 0x92, 0x5e, 0xe1, 0xdc, 0xe5, 0x21, 0xee, 0x36, 0x1b, 0x1a, 0x5e, 0xe6, - 0xc9, 0xd0, 0xb0, 0x54, 0xe3, 0x0d, 0x19, 0xeb, 0x2a, 0x6d, 0xbb, 0xfe, 0xad, 0x08, 0xc5, 0x33, - 0x6a, 0xa3, 0x2e, 0xfc, 0x35, 0xfc, 0x53, 0xf8, 0x7f, 0x62, 0x31, 0xa3, 0xeb, 0x28, 0xd5, 0xa6, - 0x86, 0xa6, 0xd7, 0xa2, 0x0f, 0x02, 0x54, 0x26, 0xaf, 0xed, 0xe1, 0x34, 0x84, 0x63, 0x69, 0xd2, - 0xe3, 0xdf, 0x4a, 0xcb, 0x6a, 0x7a, 0x03, 0xcb, 0x43, 0xbb, 0xb2, 0x7b, 0x1f, 0x5d, 0x1e, 0x29, - 0x3d, 0x9c, 0x16, 0x99, 0xdd, 0x15, 0x42, 0x79, 0x7c, 0xd2, 0xf6, 0xa6, 0xa5, 0x89, 0xe1, 0xd2, - 0xe1, 0x2f, 0xc1, 0xd3, 0xab, 0xf5, 0x17, 0xd7, 0xb7, 0x55, 0xe1, 0xe6, 0xb6, 0x2a, 0x7c, 0xb9, - 0xad, 0x0a, 0x97, 0x77, 0xd5, 0xc2, 0xcd, 0x5d, 0xb5, 0xf0, 0xf9, 0xae, 0x5a, 0x78, 0x75, 0x68, - 0x3b, 0xc1, 0x45, 0xaf, 0xa9, 0x5a, 0xa4, 0xab, 0x59, 0x84, 0x76, 0x09, 0xd5, 0x9c, 0xa6, 0xb5, - 0x67, 0x13, 0xad, 0xbf, 0xaf, 0x75, 0x49, 0xab, 0xd7, 0xc1, 0x94, 0x3d, 0x41, 0x54, 0xab, 0x3f, - 0xda, 0x63, 0xaf, 0x4f, 0x10, 0x7a, 0x98, 0x36, 0xe7, 0xe3, 0xa7, 0x65, 0xff, 0x47, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x59, 0xf9, 0x73, 0xbc, 0xf3, 0x06, 0x00, 0x00, + // 698 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0xcf, 0x6e, 0xd3, 0x4c, + 0x10, 0x8f, 0x9b, 0xfe, 0xcb, 0xb4, 0x5f, 0xdb, 0xac, 0xda, 0xaf, 0x8e, 0xd5, 0xc6, 0xfd, 0xac, + 0x4f, 0xa8, 0x08, 0xd5, 0x26, 0xa1, 0x3d, 0x50, 0x09, 0x21, 0x5c, 0xa9, 0xa2, 0x12, 0x15, 0x91, + 0xc5, 0x09, 0x21, 0x55, 0x8e, 0xb3, 0x71, 0x0d, 0x89, 0xd7, 0xf2, 0x3a, 0x11, 0x7e, 0x03, 0x8e, + 0xe5, 0x0d, 0xfa, 0x06, 0xbc, 0x46, 0x8f, 0x3d, 0x70, 0xe0, 0x64, 0xa1, 0xf6, 0xc2, 0x0d, 0x29, + 0xbc, 0x00, 0x5a, 0x7b, 0x6d, 0x9c, 0x44, 0xa9, 0x02, 0x27, 0x6e, 0x3b, 0x33, 0xbf, 0xf9, 0xed, + 0xcc, 0xcf, 0x33, 0x5e, 0xd8, 0x71, 0x9a, 0x96, 0x66, 0x7a, 0x5e, 0xc7, 0xb1, 0xcc, 0xc0, 0x21, + 0x2e, 0xd5, 0xda, 0x18, 0x6b, 0xfd, 0x9a, 0x16, 0xbc, 0x57, 0x3d, 0x9f, 0x04, 0x04, 0x6d, 0x3a, + 0x4d, 0x4b, 0xcd, 0x23, 0xd4, 0x36, 0xc6, 0x6a, 0xbf, 0x26, 0xad, 0xdb, 0xc4, 0x26, 0x31, 0x46, + 0x63, 0xa7, 0x04, 0x2e, 0xfd, 0x37, 0x89, 0x90, 0x65, 0xe5, 0x20, 0x16, 0xf1, 0xb1, 0x66, 0x9d, + 0x9b, 0xae, 0x8b, 0x3b, 0x2c, 0xcc, 0x8f, 0x09, 0x44, 0xf9, 0x24, 0xc0, 0xda, 0x29, 0xb5, 0x0d, + 0x6c, 0x3b, 0x34, 0xc0, 0x7e, 0xc3, 0x0c, 0x31, 0x46, 0x0f, 0x60, 0xc1, 0x23, 0x7e, 0x70, 0xe6, + 0xb4, 0x44, 0x61, 0x47, 0xd8, 0x2d, 0xe9, 0x68, 0x10, 0xc9, 0x2b, 0xa1, 0xd9, 0xed, 0x1c, 0x2a, + 0x3c, 0xa0, 0x18, 0xf3, 0xec, 0x74, 0xd2, 0x42, 0xfb, 0x00, 0x9c, 0x92, 0xe1, 0x67, 0x62, 0xfc, + 0xc6, 0x20, 0x92, 0xcb, 0x09, 0xfe, 0x57, 0x4c, 0x31, 0x4a, 0xdc, 0x38, 0x69, 0x21, 0x11, 0x16, + 0x7c, 0xdc, 0x31, 0x43, 0xec, 0x8b, 0x45, 0x96, 0x62, 0xa4, 0x26, 0x5a, 0x87, 0x39, 0x8f, 0x55, + 0x21, 0xce, 0xc6, 0xfe, 0xc4, 0x38, 0x5c, 0xfc, 0x70, 0x29, 0x17, 0xbe, 0x5d, 0xca, 0x05, 0x45, + 0x02, 0x71, 0xb4, 0x60, 0x03, 0x53, 0x8f, 0xb8, 0x14, 0x2b, 0x3f, 0x04, 0xd8, 0xca, 0x05, 0x8f, + 0x48, 0xcf, 0x0d, 0xb0, 0xef, 0x99, 0x7e, 0x10, 0xfe, 0x05, 0x9d, 0xbd, 0x00, 0x64, 0xe5, 0x2a, + 0x3a, 0xcb, 0xb5, 0xa9, 0x6f, 0x0f, 0x22, 0xb9, 0xc2, 0x79, 0xc7, 0x30, 0x8a, 0x51, 0xb6, 0x46, + 0x5b, 0xc9, 0x29, 0x72, 0x0f, 0xfe, 0xbf, 0xab, 0xe9, 0x4c, 0x9d, 0x8b, 0x19, 0x58, 0x3d, 0xa5, + 0x76, 0xc3, 0x0c, 0x1b, 0xa6, 0xf5, 0x0e, 0x07, 0xc7, 0x18, 0xa3, 0x7d, 0x28, 0xb6, 0x31, 0x8e, + 0xc5, 0x58, 0xaa, 0x6f, 0xa9, 0x13, 0x46, 0x50, 0x3d, 0xc6, 0x58, 0x9f, 0xbd, 0x8a, 0xe4, 0x82, + 0xc1, 0xe0, 0xe8, 0x29, 0xac, 0x50, 0xd2, 0xf3, 0x2d, 0x7c, 0x96, 0xaa, 0x99, 0xa8, 0x53, 0x19, + 0x44, 0xf2, 0x46, 0xd2, 0xc5, 0x70, 0x5c, 0x31, 0x96, 0x13, 0x47, 0x23, 0x91, 0xf6, 0x39, 0x94, + 0x39, 0x20, 0xa7, 0x70, 0x2c, 0x97, 0xbe, 0x35, 0x88, 0x64, 0x71, 0x88, 0x23, 0x2f, 0xf4, 0x6a, + 0xe2, 0x3b, 0xca, 0xe4, 0xfe, 0x17, 0xe6, 0xa9, 0x63, 0xbb, 0xd8, 0xe7, 0xf3, 0xc2, 0x2d, 0x24, + 0xc1, 0x22, 0xd7, 0x9d, 0x8a, 0x73, 0x3b, 0xc5, 0xdd, 0x92, 0x91, 0xd9, 0x39, 0xe9, 0x2a, 0xb0, + 0x39, 0xa2, 0x48, 0xa6, 0xd6, 0x67, 0x01, 0xd6, 0x47, 0x62, 0xcf, 0x68, 0xe8, 0x5a, 0xe8, 0x15, + 0x94, 0xbc, 0xd8, 0x93, 0x4e, 0xd1, 0x52, 0x7d, 0x3b, 0x16, 0x8e, 0x6d, 0x9a, 0x9a, 0xae, 0x57, + 0xbf, 0xa6, 0x26, 0x79, 0x27, 0x2d, 0x5d, 0x64, 0xca, 0x0d, 0x22, 0x79, 0x8d, 0x0f, 0x5a, 0x9a, + 0xad, 0x18, 0x8b, 0x1e, 0xc7, 0xa0, 0x37, 0x00, 0xdc, 0xcf, 0xbe, 0xc7, 0x4c, 0x4c, 0xab, 0x4c, + 0xfc, 0x1e, 0x59, 0x49, 0x7a, 0x85, 0x73, 0x97, 0x87, 0xb8, 0xdb, 0x6c, 0x68, 0x78, 0x99, 0xc7, + 0x43, 0xc3, 0x52, 0x8d, 0x37, 0x64, 0xac, 0xab, 0xb4, 0xed, 0xfa, 0xf7, 0x22, 0x14, 0x4f, 0xa9, + 0x8d, 0xba, 0xf0, 0xcf, 0xf0, 0x4f, 0xe1, 0xfe, 0xc4, 0x62, 0x46, 0xd7, 0x51, 0xaa, 0x4d, 0x0d, + 0x4d, 0xaf, 0x45, 0x1f, 0x05, 0xa8, 0x4c, 0x5e, 0xdb, 0x83, 0x69, 0x08, 0xc7, 0xd2, 0xa4, 0x27, + 0x7f, 0x94, 0x96, 0xd5, 0xf4, 0x16, 0x96, 0x87, 0x76, 0x65, 0xf7, 0x2e, 0xba, 0x3c, 0x52, 0x7a, + 0x38, 0x2d, 0x32, 0xbb, 0x2b, 0x84, 0xf2, 0xf8, 0xa4, 0xed, 0x4d, 0x4b, 0x13, 0xc3, 0xa5, 0x83, + 0xdf, 0x82, 0xa7, 0x57, 0xeb, 0x2f, 0xaf, 0x6e, 0xaa, 0xc2, 0xf5, 0x4d, 0x55, 0xf8, 0x7a, 0x53, + 0x15, 0x2e, 0x6e, 0xab, 0x85, 0xeb, 0xdb, 0x6a, 0xe1, 0xcb, 0x6d, 0xb5, 0xf0, 0xfa, 0xc0, 0x76, + 0x82, 0xf3, 0x5e, 0x53, 0xb5, 0x48, 0x57, 0xb3, 0x08, 0xed, 0x12, 0xaa, 0x39, 0x4d, 0x6b, 0xcf, + 0x26, 0x5a, 0x7f, 0x5f, 0xeb, 0x92, 0x56, 0xaf, 0x83, 0x29, 0x7b, 0x82, 0xa8, 0x56, 0x7f, 0xbc, + 0xc7, 0x5e, 0x9f, 0x20, 0xf4, 0x30, 0x6d, 0xce, 0xc7, 0x4f, 0xcb, 0xa3, 0x9f, 0x01, 0x00, 0x00, + 0xff, 0xff, 0xe2, 0x94, 0x3a, 0xbf, 0xf3, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/apps/transfer/client/cli/query.go b/modules/apps/transfer/client/cli/query.go index 2a6e3161a93..9f9ce97be71 100644 --- a/modules/apps/transfer/client/cli/query.go +++ b/modules/apps/transfer/client/cli/query.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) // GetCmdQueryDenomTrace defines the command to query a a denomination trace from a given trace hash or ibc denom. diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 02e006be5eb..cddff4b4d9a 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -13,9 +13,9 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channelutils "github.com/cosmos/ibc-go/v3/modules/core/04-channel/client/utils" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channelutils "github.com/cosmos/ibc-go/v4/modules/core/04-channel/client/utils" ) const ( diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 1e5f56280ce..7b87b33408c 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -9,12 +9,12 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" - "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/ibc-go/v4/modules/apps/transfer/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // IBCModule implements the ICS26 interface for transfer given the transfer keeper. diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index b11444b945e..3b8e0175517 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -5,11 +5,11 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *TransferTestSuite) TestOnChanOpenInit() { diff --git a/modules/apps/transfer/keeper/encoding.go b/modules/apps/transfer/keeper/encoding.go index 7e0333849d4..0dfa979cb91 100644 --- a/modules/apps/transfer/keeper/encoding.go +++ b/modules/apps/transfer/keeper/encoding.go @@ -1,7 +1,7 @@ package keeper import ( - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) // UnmarshalDenomTrace attempts to decode and return an DenomTrace object from diff --git a/modules/apps/transfer/keeper/genesis.go b/modules/apps/transfer/keeper/genesis.go index d4020508cc9..a3506e4e22d 100644 --- a/modules/apps/transfer/keeper/genesis.go +++ b/modules/apps/transfer/keeper/genesis.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) // InitGenesis initializes the ibc-transfer state and binds to PortID. diff --git a/modules/apps/transfer/keeper/genesis_test.go b/modules/apps/transfer/keeper/genesis_test.go index a8ded3f902d..e734967863c 100644 --- a/modules/apps/transfer/keeper/genesis_test.go +++ b/modules/apps/transfer/keeper/genesis_test.go @@ -3,7 +3,7 @@ package keeper_test import ( "fmt" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) func (suite *KeeperTestSuite) TestGenesis() { diff --git a/modules/apps/transfer/keeper/grpc_query.go b/modules/apps/transfer/keeper/grpc_query.go index 512e8e58396..5564ef04614 100644 --- a/modules/apps/transfer/keeper/grpc_query.go +++ b/modules/apps/transfer/keeper/grpc_query.go @@ -12,7 +12,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) var _ types.QueryServer = Keeper{} diff --git a/modules/apps/transfer/keeper/grpc_query_test.go b/modules/apps/transfer/keeper/grpc_query_test.go index c0edaea2a20..92dfbe24370 100644 --- a/modules/apps/transfer/keeper/grpc_query_test.go +++ b/modules/apps/transfer/keeper/grpc_query_test.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestQueryDenomTrace() { diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index b8681baa47b..2a9c5c16db0 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -10,8 +10,8 @@ import ( tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // Keeper defines the IBC fungible transfer keeper diff --git a/modules/apps/transfer/keeper/keeper_test.go b/modules/apps/transfer/keeper/keeper_test.go index 40ceb6d782f..051f3952234 100644 --- a/modules/apps/transfer/keeper/keeper_test.go +++ b/modules/apps/transfer/keeper/keeper_test.go @@ -6,8 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type KeeperTestSuite struct { diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 4366101f932..16aa831b37d 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -15,10 +15,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type TlaBalance struct { diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 5d8e5682200..eab992e958f 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) var _ types.MsgServer = Keeper{} diff --git a/modules/apps/transfer/keeper/params.go b/modules/apps/transfer/keeper/params.go index b88a1b93b69..9589ae04ec9 100644 --- a/modules/apps/transfer/keeper/params.go +++ b/modules/apps/transfer/keeper/params.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) // GetSendEnabled retrieves the send enabled boolean from the paramstore diff --git a/modules/apps/transfer/keeper/params_test.go b/modules/apps/transfer/keeper/params_test.go index c0c7ff62af0..e52f15cb247 100644 --- a/modules/apps/transfer/keeper/params_test.go +++ b/modules/apps/transfer/keeper/params_test.go @@ -1,6 +1,6 @@ package keeper_test -import "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" +import "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" func (suite *KeeperTestSuite) TestParams() { expParams := types.DefaultParams() diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index cb4b8c59fd5..8c023ebac5a 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -9,11 +9,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - coretypes "github.com/cosmos/ibc-go/v3/modules/core/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + coretypes "github.com/cosmos/ibc-go/v4/modules/core/types" ) // SendTransfer handles transfer sending logic. There are 2 possible cases: diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index d9d6f8a68c7..ac60ed3964b 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -5,12 +5,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) // test sending from chainA to chainB using both coin that orignate on diff --git a/modules/apps/transfer/module.go b/modules/apps/transfer/module.go index 0daa6dc3bf0..11279e4d93f 100644 --- a/modules/apps/transfer/module.go +++ b/modules/apps/transfer/module.go @@ -17,11 +17,11 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/client/cli" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/simulation" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/client/cli" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/simulation" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" ) var ( diff --git a/modules/apps/transfer/simulation/decoder.go b/modules/apps/transfer/simulation/decoder.go index 8758d904544..6e1fe37feeb 100644 --- a/modules/apps/transfer/simulation/decoder.go +++ b/modules/apps/transfer/simulation/decoder.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) // TransferUnmarshaler defines the expected encoding store functions. diff --git a/modules/apps/transfer/simulation/decoder_test.go b/modules/apps/transfer/simulation/decoder_test.go index a505dffb15d..13afd462be7 100644 --- a/modules/apps/transfer/simulation/decoder_test.go +++ b/modules/apps/transfer/simulation/decoder_test.go @@ -7,9 +7,9 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/simulation" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/simulation" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) func TestDecodeStore(t *testing.T) { diff --git a/modules/apps/transfer/simulation/genesis.go b/modules/apps/transfer/simulation/genesis.go index a74277d1671..693864ce12b 100644 --- a/modules/apps/transfer/simulation/genesis.go +++ b/modules/apps/transfer/simulation/genesis.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) // Simulation parameter constants diff --git a/modules/apps/transfer/simulation/genesis_test.go b/modules/apps/transfer/simulation/genesis_test.go index f2aa439b3ae..5b46c88f9d8 100644 --- a/modules/apps/transfer/simulation/genesis_test.go +++ b/modules/apps/transfer/simulation/genesis_test.go @@ -11,8 +11,8 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/simulation" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/simulation" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) // TestRandomizedGenState tests the normal scenario of applying RandomizedGenState. diff --git a/modules/apps/transfer/simulation/params.go b/modules/apps/transfer/simulation/params.go index c7193b47193..838015ae498 100644 --- a/modules/apps/transfer/simulation/params.go +++ b/modules/apps/transfer/simulation/params.go @@ -8,7 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/simulation" gogotypes "github.com/gogo/protobuf/types" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) // ParamChanges defines the parameters that can be modified by param change proposals diff --git a/modules/apps/transfer/simulation/params_test.go b/modules/apps/transfer/simulation/params_test.go index 491fee0d3f3..86c16c67c5c 100644 --- a/modules/apps/transfer/simulation/params_test.go +++ b/modules/apps/transfer/simulation/params_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/simulation" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/simulation" ) func TestParamChanges(t *testing.T) { diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index 5190cdc8d29..d1089f0ee82 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -6,9 +6,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type TransferTestSuite struct { diff --git a/modules/apps/transfer/types/ack_test.go b/modules/apps/transfer/types/ack_test.go new file mode 100644 index 00000000000..b0782dd96ba --- /dev/null +++ b/modules/apps/transfer/types/ack_test.go @@ -0,0 +1,29 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + ibctesting "github.com/cosmos/ibc-go/v4/testing" +) + +type TypesTestSuite struct { + suite.Suite + + coordinator *ibctesting.Coordinator + + chainA *ibctesting.TestChain + chainB *ibctesting.TestChain +} + +func (suite *TypesTestSuite) SetupTest() { + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) + + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) +} + +func TestTypesTestSuite(t *testing.T) { + suite.Run(t, new(TypesTestSuite)) +} diff --git a/modules/apps/transfer/types/expected_keepers.go b/modules/apps/transfer/types/expected_keepers.go index 22ad54b9e62..c696a2d75d8 100644 --- a/modules/apps/transfer/types/expected_keepers.go +++ b/modules/apps/transfer/types/expected_keepers.go @@ -5,9 +5,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // AccountKeeper defines the contract required for account APIs. diff --git a/modules/apps/transfer/types/genesis.go b/modules/apps/transfer/types/genesis.go index 73dbe111a2e..db1f5489558 100644 --- a/modules/apps/transfer/types/genesis.go +++ b/modules/apps/transfer/types/genesis.go @@ -1,7 +1,7 @@ package types import ( - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // NewGenesisState creates a new ibc-transfer GenesisState instance. diff --git a/modules/apps/transfer/types/genesis.pb.go b/modules/apps/transfer/types/genesis.pb.go index 6c40ef48a3d..bac7416d405 100644 --- a/modules/apps/transfer/types/genesis.pb.go +++ b/modules/apps/transfer/types/genesis.pb.go @@ -96,24 +96,24 @@ var fileDescriptor_a4f788affd5bea89 = []byte{ // 324 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xc1, 0x4a, 0xc3, 0x30, 0x1c, 0xc6, 0x1b, 0x27, 0x15, 0xbb, 0xe1, 0xa1, 0x7a, 0x18, 0x43, 0xda, 0x51, 0x14, 0x8a, 0xc3, - 0x84, 0x6d, 0x07, 0xc1, 0x63, 0x11, 0xc4, 0x9b, 0x4e, 0x4f, 0x5e, 0x46, 0x9a, 0xc6, 0x1a, 0x58, - 0x9b, 0x92, 0x7f, 0x36, 0xd8, 0x5b, 0xf8, 0x1c, 0x3e, 0xc9, 0x8e, 0x3b, 0x7a, 0x9a, 0xb2, 0xbd, - 0xc1, 0x7c, 0x01, 0x49, 0x37, 0xc7, 0x4e, 0xbd, 0x7d, 0x24, 0xbf, 0xef, 0xfb, 0xfe, 0x7c, 0xce, - 0x95, 0x88, 0x19, 0xa1, 0x45, 0x31, 0x12, 0x8c, 0x6a, 0x21, 0x73, 0x20, 0x5a, 0xd1, 0x1c, 0xde, - 0xb8, 0x22, 0x93, 0x2e, 0x49, 0x79, 0xce, 0x41, 0x00, 0x2e, 0x94, 0xd4, 0xd2, 0x3d, 0x17, 0x31, - 0xc3, 0xfb, 0x2c, 0xfe, 0x67, 0xf1, 0xa4, 0xdb, 0xea, 0x54, 0x26, 0xed, 0xc8, 0x32, 0xaa, 0x75, - 0x96, 0xca, 0x54, 0x96, 0x92, 0x18, 0xb5, 0x79, 0x0d, 0x7e, 0x91, 0xd3, 0xb8, 0xdf, 0x54, 0x3e, - 0x6b, 0xaa, 0xb9, 0xdb, 0x71, 0x8e, 0x0a, 0xa9, 0xf4, 0x50, 0x24, 0x4d, 0xd4, 0x46, 0xe1, 0x71, - 0xe4, 0xae, 0x17, 0xfe, 0xc9, 0x94, 0x66, 0xa3, 0xdb, 0x60, 0xfb, 0x11, 0x0c, 0x6c, 0xa3, 0x1e, - 0x12, 0x57, 0x39, 0x8d, 0x84, 0xe7, 0x32, 0x1b, 0x6a, 0x45, 0x19, 0x87, 0xe6, 0x41, 0xbb, 0x16, - 0xd6, 0x7b, 0x21, 0xae, 0xba, 0x1a, 0xdf, 0x19, 0xc7, 0x8b, 0x31, 0x44, 0x97, 0xb3, 0x85, 0x6f, - 0xad, 0x17, 0xfe, 0xe9, 0x26, 0x7f, 0x3f, 0x2b, 0xf8, 0xfc, 0xf6, 0xed, 0x92, 0x82, 0x41, 0x3d, - 0xd9, 0x59, 0xc0, 0x8d, 0x1c, 0xbb, 0xa0, 0x8a, 0x66, 0xd0, 0xac, 0xb5, 0x51, 0x58, 0xef, 0x5d, - 0x54, 0xb7, 0x3d, 0x96, 0x6c, 0x74, 0x68, 0x9a, 0x06, 0x5b, 0x67, 0xf4, 0x34, 0x5b, 0x7a, 0x68, - 0xbe, 0xf4, 0xd0, 0xcf, 0xd2, 0x43, 0x1f, 0x2b, 0xcf, 0x9a, 0xaf, 0x3c, 0xeb, 0x6b, 0xe5, 0x59, - 0xaf, 0x37, 0xa9, 0xd0, 0xef, 0xe3, 0x18, 0x33, 0x99, 0x11, 0x26, 0x21, 0x93, 0x40, 0x44, 0xcc, - 0xae, 0x53, 0x49, 0x26, 0x7d, 0x92, 0xc9, 0x64, 0x3c, 0xe2, 0x60, 0x26, 0xdf, 0x9b, 0x5a, 0x4f, - 0x0b, 0x0e, 0xb1, 0x5d, 0xee, 0xd9, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x49, 0x1b, 0x71, 0xa7, + 0x84, 0x4d, 0x41, 0xf0, 0x58, 0x04, 0xf1, 0xa6, 0xd3, 0x93, 0x97, 0x91, 0xa6, 0xb1, 0x06, 0xd6, + 0xa6, 0xe4, 0x9f, 0x0d, 0xf6, 0x16, 0x3e, 0x87, 0x4f, 0xb2, 0xe3, 0x8e, 0x9e, 0xa6, 0x6c, 0x6f, + 0x30, 0x5f, 0x40, 0xd2, 0xcd, 0xb1, 0x53, 0x6f, 0x1f, 0xc9, 0xef, 0xfb, 0xbe, 0x3f, 0x9f, 0x73, + 0x21, 0x62, 0x46, 0x68, 0x51, 0x0c, 0x05, 0xa3, 0x5a, 0xc8, 0x1c, 0x88, 0x56, 0x34, 0x87, 0x37, + 0xae, 0xc8, 0xb8, 0x4b, 0x52, 0x9e, 0x73, 0x10, 0x80, 0x0b, 0x25, 0xb5, 0x74, 0x4f, 0x45, 0xcc, + 0xf0, 0x2e, 0x8b, 0xff, 0x59, 0x3c, 0xee, 0xb6, 0x3a, 0x95, 0x49, 0x5b, 0xb2, 0x8c, 0x6a, 0x9d, + 0xa4, 0x32, 0x95, 0xa5, 0x24, 0x46, 0xad, 0x5f, 0x83, 0x5f, 0xe4, 0x34, 0xee, 0xd7, 0x95, 0xcf, + 0x9a, 0x6a, 0xee, 0x76, 0x9c, 0x83, 0x42, 0x2a, 0x3d, 0x10, 0x49, 0x13, 0xb5, 0x51, 0x78, 0x18, + 0xb9, 0xab, 0xb9, 0x7f, 0x34, 0xa1, 0xd9, 0xf0, 0x36, 0xd8, 0x7c, 0x04, 0x7d, 0xdb, 0xa8, 0x87, + 0xc4, 0x55, 0x4e, 0x23, 0xe1, 0xb9, 0xcc, 0x06, 0x5a, 0x51, 0xc6, 0xa1, 0xb9, 0xd7, 0xae, 0x85, + 0xf5, 0x5e, 0x88, 0xab, 0xae, 0xc6, 0x77, 0xc6, 0xf1, 0x62, 0x0c, 0xd1, 0xf9, 0x74, 0xee, 0x5b, + 0xab, 0xb9, 0x7f, 0xbc, 0xce, 0xdf, 0xcd, 0x0a, 0x3e, 0xbf, 0x7d, 0xbb, 0xa4, 0xa0, 0x5f, 0x4f, + 0xb6, 0x16, 0x70, 0x23, 0xc7, 0x2e, 0xa8, 0xa2, 0x19, 0x34, 0x6b, 0x6d, 0x14, 0xd6, 0x7b, 0x67, + 0xd5, 0x6d, 0x8f, 0x25, 0x1b, 0xed, 0x9b, 0xa6, 0xfe, 0xc6, 0x19, 0x3d, 0x4d, 0x17, 0x1e, 0x9a, + 0x2d, 0x3c, 0xf4, 0xb3, 0xf0, 0xd0, 0xc7, 0xd2, 0xb3, 0x66, 0x4b, 0xcf, 0xfa, 0x5a, 0x7a, 0xd6, + 0xeb, 0x4d, 0x2a, 0xf4, 0xfb, 0x28, 0xc6, 0x4c, 0x66, 0x84, 0x49, 0xc8, 0x24, 0x10, 0x11, 0xb3, + 0xcb, 0x54, 0x92, 0xf1, 0x35, 0xc9, 0x64, 0x32, 0x1a, 0x72, 0x30, 0x93, 0xef, 0x4c, 0xad, 0x27, + 0x05, 0x87, 0xd8, 0x2e, 0xf7, 0xbc, 0xfa, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x96, 0x72, 0x43, 0x93, 0xde, 0x01, 0x00, 0x00, } diff --git a/modules/apps/transfer/types/genesis_test.go b/modules/apps/transfer/types/genesis_test.go index 534eefba7ab..fb63fbede64 100644 --- a/modules/apps/transfer/types/genesis_test.go +++ b/modules/apps/transfer/types/genesis_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) func TestValidateGenesis(t *testing.T) { diff --git a/modules/apps/transfer/types/keys_test.go b/modules/apps/transfer/types/keys_test.go index 3270dba55be..d69dc6e30c6 100644 --- a/modules/apps/transfer/types/keys_test.go +++ b/modules/apps/transfer/types/keys_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" ) // Test that there is domain separation between the port id and the channel id otherwise an diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index dab9fb21d46..00ef9fe5386 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // msg types diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index 00570ac15ed..929de3a4d6f 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ) // define constants used for testing diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go index 3ebd1106f66..ca0ffa46e9e 100644 --- a/modules/apps/transfer/types/packet.pb.go +++ b/modules/apps/transfer/types/packet.pb.go @@ -108,20 +108,20 @@ func init() { var fileDescriptor_653ca2ce9a5ca313 = []byte{ // 242 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x8f, 0xbd, 0x4a, 0x04, 0x31, - 0x14, 0x46, 0x27, 0xfe, 0x2c, 0x9a, 0x72, 0x10, 0x1d, 0x44, 0x82, 0x58, 0x69, 0x61, 0x02, 0xbb, - 0x85, 0xbd, 0x88, 0xb5, 0x8a, 0x95, 0x5d, 0x92, 0xb9, 0x8e, 0x61, 0x27, 0xb9, 0x21, 0xc9, 0x0c, - 0x88, 0x2f, 0xe1, 0x63, 0x59, 0x6e, 0x69, 0x29, 0x33, 0x2f, 0x22, 0x9b, 0xd1, 0x65, 0xcb, 0x73, - 0xee, 0x77, 0x8b, 0x43, 0xaf, 0x8c, 0xd2, 0x42, 0x7a, 0xdf, 0x1a, 0x2d, 0x93, 0x41, 0x17, 0x45, - 0x0a, 0xd2, 0xc5, 0x57, 0x08, 0xa2, 0x9f, 0x0b, 0x2f, 0xf5, 0x12, 0x12, 0xf7, 0x01, 0x13, 0x96, - 0x67, 0x46, 0x69, 0xbe, 0x3d, 0xe5, 0xff, 0x53, 0xde, 0xcf, 0x2f, 0x3e, 0xe8, 0xc9, 0x7d, 0xe7, - 0x1a, 0xa3, 0x5a, 0x78, 0xc6, 0x25, 0xb8, 0x87, 0xfc, 0x7a, 0x27, 0x93, 0x2c, 0x8f, 0xe8, 0x7e, - 0x0d, 0x0e, 0x6d, 0x45, 0xce, 0xc9, 0xe5, 0xe1, 0xd3, 0x04, 0xe5, 0x31, 0x9d, 0x49, 0x8b, 0x9d, - 0x4b, 0xd5, 0x4e, 0xd6, 0x7f, 0xb4, 0xf6, 0x11, 0x5c, 0x0d, 0xa1, 0xda, 0x9d, 0xfc, 0x44, 0xe5, - 0x29, 0x3d, 0x08, 0xa0, 0xc1, 0xf4, 0x10, 0xaa, 0xbd, 0x7c, 0xd9, 0xf0, 0xed, 0xe3, 0xd7, 0xc0, - 0xc8, 0x6a, 0x60, 0xe4, 0x67, 0x60, 0xe4, 0x73, 0x64, 0xc5, 0x6a, 0x64, 0xc5, 0xf7, 0xc8, 0x8a, - 0x97, 0x9b, 0xc6, 0xa4, 0xb7, 0x4e, 0x71, 0x8d, 0x56, 0x68, 0x8c, 0x16, 0xa3, 0x30, 0x4a, 0x5f, - 0x37, 0x28, 0xfa, 0x85, 0xb0, 0x58, 0x77, 0x2d, 0xc4, 0x75, 0xff, 0x56, 0x77, 0x7a, 0xf7, 0x10, - 0xd5, 0x2c, 0x47, 0x2f, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0x82, 0x62, 0x02, 0xc6, 0x21, 0x01, + 0x14, 0x46, 0x27, 0xfe, 0x2c, 0x9a, 0x72, 0x10, 0x1d, 0x44, 0x82, 0x58, 0x69, 0x61, 0x02, 0xab, + 0x60, 0x2f, 0x62, 0xad, 0x62, 0x65, 0x97, 0x64, 0xae, 0x63, 0xd8, 0x49, 0x6e, 0x48, 0x32, 0x03, + 0xe2, 0x4b, 0xf8, 0x58, 0x96, 0x5b, 0x5a, 0xca, 0xcc, 0x8b, 0xc8, 0x66, 0x74, 0xd9, 0xf2, 0x9c, + 0xfb, 0xdd, 0xe2, 0xd0, 0x0b, 0xa3, 0xb4, 0x90, 0xde, 0xb7, 0x46, 0xcb, 0x64, 0xd0, 0x45, 0x91, + 0x82, 0x74, 0xf1, 0x15, 0x82, 0xe8, 0xe7, 0xc2, 0x4b, 0xbd, 0x80, 0xc4, 0x7d, 0xc0, 0x84, 0xe5, + 0x89, 0x51, 0x9a, 0x6f, 0x4e, 0xf9, 0xff, 0x94, 0xf7, 0xf3, 0xb3, 0x0f, 0x7a, 0x74, 0xdf, 0xb9, + 0xc6, 0xa8, 0x16, 0x9e, 0x71, 0x01, 0xee, 0x21, 0xbf, 0xde, 0xc9, 0x24, 0xcb, 0x03, 0xba, 0x5b, + 0x83, 0x43, 0x5b, 0x91, 0x53, 0x72, 0xbe, 0xff, 0x34, 0x41, 0x79, 0x48, 0x67, 0xd2, 0x62, 0xe7, + 0x52, 0xb5, 0x95, 0xf5, 0x1f, 0xad, 0x7c, 0x04, 0x57, 0x43, 0xa8, 0xb6, 0x27, 0x3f, 0x51, 0x79, + 0x4c, 0xf7, 0x02, 0x68, 0x30, 0x3d, 0x84, 0x6a, 0x27, 0x5f, 0xd6, 0x7c, 0xfb, 0xf8, 0x35, 0x30, + 0xb2, 0x1c, 0x18, 0xf9, 0x19, 0x18, 0xf9, 0x1c, 0x59, 0xb1, 0x1c, 0x59, 0xf1, 0x3d, 0xb2, 0xe2, + 0xe5, 0xa6, 0x31, 0xe9, 0xad, 0x53, 0x5c, 0xa3, 0x15, 0x1a, 0xa3, 0xc5, 0x28, 0x8c, 0xd2, 0x97, + 0x0d, 0x8a, 0xfe, 0x5a, 0x58, 0xac, 0xbb, 0x16, 0xe2, 0xaa, 0x7f, 0xa3, 0x3b, 0xbd, 0x7b, 0x88, + 0x6a, 0x96, 0xa3, 0xaf, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0x5d, 0x0b, 0x30, 0xf2, 0x21, 0x01, 0x00, 0x00, } diff --git a/modules/apps/transfer/types/query.pb.go b/modules/apps/transfer/types/query.pb.go index a137649a094..d654e4b30a5 100644 --- a/modules/apps/transfer/types/query.pb.go +++ b/modules/apps/transfer/types/query.pb.go @@ -566,9 +566,9 @@ var fileDescriptor_a638e2800a01538c = []byte{ 0xe3, 0x83, 0xde, 0xd6, 0xb6, 0x71, 0xb2, 0xcb, 0x1c, 0x1f, 0xa8, 0x0d, 0x6f, 0xe3, 0xec, 0x52, 0x6e, 0x6c, 0x1f, 0x9f, 0x1a, 0xda, 0xc9, 0xa9, 0xa1, 0xfd, 0x3a, 0x35, 0xb4, 0x8f, 0x67, 0x46, 0xe1, 0xe4, 0xcc, 0x28, 0x7c, 0x3f, 0x33, 0x0a, 0x6f, 0xd6, 0x3d, 0x3f, 0xae, 0x35, 0x6d, 0xcb, - 0x61, 0x0d, 0xac, 0xfe, 0x9b, 0xbe, 0xed, 0x2c, 0x7b, 0x0c, 0xb7, 0x56, 0x71, 0x83, 0xb9, 0xcd, + 0x61, 0x0d, 0xac, 0xfe, 0x9b, 0xbe, 0xed, 0x2c, 0x7b, 0x0c, 0xb7, 0xd6, 0x70, 0x83, 0xb9, 0xcd, 0x3a, 0xe5, 0xff, 0x90, 0x88, 0xf7, 0x43, 0xca, 0xed, 0xa2, 0xf8, 0xeb, 0xad, 0xfe, 0x0d, 0x00, - 0x00, 0xff, 0xff, 0x32, 0xbb, 0x42, 0xe2, 0xcc, 0x07, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xed, 0xd2, 0x70, 0xd6, 0xcc, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/apps/transfer/types/trace.go b/modules/apps/transfer/types/trace.go index e0a68ef8d9b..8d15f3bacf0 100644 --- a/modules/apps/transfer/types/trace.go +++ b/modules/apps/transfer/types/trace.go @@ -12,7 +12,7 @@ import ( tmbytes "github.com/tendermint/tendermint/libs/bytes" tmtypes "github.com/tendermint/tendermint/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // ParseDenomTrace parses a string with the ibc prefix (denom trace) and the base denomination diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index 5ed7c9bd835..9ef18d9d5b0 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -153,23 +153,23 @@ var fileDescriptor_5041673e96e97901 = []byte{ // 300 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x90, 0xc1, 0x4a, 0x2b, 0x31, 0x14, 0x86, 0x9b, 0x72, 0x29, 0xb7, 0x51, 0x14, 0xa2, 0x68, 0x29, 0x9a, 0xca, 0xac, 0x04, 0x71, - 0x42, 0xe9, 0x42, 0xe8, 0x46, 0xa8, 0xba, 0xd7, 0xe2, 0xca, 0x4d, 0x49, 0x32, 0xc7, 0x69, 0x60, - 0x32, 0x19, 0x92, 0x74, 0xa0, 0x8f, 0xe0, 0xce, 0xc7, 0x72, 0xd9, 0xa5, 0xab, 0x22, 0xed, 0x1b, - 0xf4, 0x09, 0x64, 0xd2, 0x52, 0x06, 0x77, 0xff, 0x39, 0xe7, 0xfb, 0xce, 0xe2, 0xc7, 0x37, 0x4a, - 0x48, 0xc6, 0x8b, 0x22, 0x53, 0x92, 0x7b, 0x65, 0x72, 0xc7, 0xbc, 0xe5, 0xb9, 0x7b, 0x07, 0xcb, - 0xca, 0xfe, 0x3e, 0xc7, 0x85, 0x35, 0xde, 0x90, 0x0b, 0x25, 0x64, 0x5c, 0x87, 0xe3, 0x3d, 0x50, - 0xf6, 0xbb, 0xa7, 0xa9, 0x49, 0x4d, 0x00, 0x59, 0x95, 0xb6, 0x4e, 0x74, 0x8f, 0xf1, 0x23, 0xe4, - 0x46, 0xbf, 0x5a, 0x2e, 0x81, 0x10, 0xfc, 0xaf, 0xe0, 0x7e, 0xda, 0x41, 0x57, 0xe8, 0xba, 0x3d, - 0x0e, 0x99, 0x5c, 0x62, 0x2c, 0xb8, 0x83, 0x49, 0x52, 0x61, 0x9d, 0x66, 0xb8, 0xb4, 0xab, 0x4d, - 0xf0, 0xa2, 0x0f, 0x84, 0x5b, 0xcf, 0xdc, 0x72, 0xed, 0xc8, 0x10, 0x1f, 0x3a, 0xc8, 0x93, 0x09, - 0xe4, 0x5c, 0x64, 0x90, 0x84, 0x2f, 0xff, 0x47, 0xe7, 0x9b, 0x65, 0xef, 0x64, 0xce, 0x75, 0x36, - 0x8c, 0xea, 0xd7, 0x68, 0x7c, 0x50, 0x8d, 0x4f, 0xdb, 0x89, 0x3c, 0xe0, 0x63, 0x0b, 0x12, 0x54, - 0x09, 0x7b, 0xbd, 0x19, 0xf4, 0xee, 0x66, 0xd9, 0x3b, 0xdb, 0xea, 0x7f, 0x80, 0x68, 0x7c, 0xb4, - 0xdb, 0xec, 0x9e, 0x8c, 0x5e, 0xbe, 0x56, 0x14, 0x2d, 0x56, 0x14, 0xfd, 0xac, 0x28, 0xfa, 0x5c, - 0xd3, 0xc6, 0x62, 0x4d, 0x1b, 0xdf, 0x6b, 0xda, 0x78, 0xbb, 0x4b, 0x95, 0x9f, 0xce, 0x44, 0x2c, - 0x8d, 0x66, 0xd2, 0x38, 0x6d, 0x1c, 0x53, 0x42, 0xde, 0xa6, 0x86, 0x95, 0x03, 0xa6, 0x4d, 0x32, - 0xcb, 0xc0, 0x55, 0x3d, 0xd7, 0xfa, 0xf5, 0xf3, 0x02, 0x9c, 0x68, 0x85, 0x9a, 0x06, 0xbf, 0x01, - 0x00, 0x00, 0xff, 0xff, 0xae, 0xdf, 0x93, 0x8e, 0x89, 0x01, 0x00, 0x00, + 0x42, 0x51, 0x10, 0xba, 0x11, 0xaa, 0xee, 0xb5, 0xb8, 0x72, 0x53, 0x92, 0xcc, 0x71, 0x1a, 0x98, + 0x4c, 0x86, 0x24, 0x1d, 0xe8, 0x23, 0xb8, 0xf3, 0xb1, 0x5c, 0x76, 0xe9, 0xaa, 0x48, 0xfb, 0x06, + 0x7d, 0x02, 0x99, 0xb4, 0x94, 0xc1, 0xdd, 0x7f, 0xce, 0xf9, 0xbe, 0xb3, 0xf8, 0xf1, 0x95, 0x12, + 0x92, 0xf1, 0xa2, 0xc8, 0x94, 0xe4, 0x5e, 0x99, 0xdc, 0x31, 0x6f, 0x79, 0xee, 0xde, 0xc1, 0xb2, + 0xb2, 0xbf, 0xcb, 0x71, 0x61, 0x8d, 0x37, 0xe4, 0x4c, 0x09, 0x19, 0xd7, 0xe1, 0x78, 0x07, 0x94, + 0xfd, 0xee, 0x71, 0x6a, 0x52, 0x13, 0x40, 0x56, 0xa5, 0x8d, 0x13, 0xdd, 0x63, 0xfc, 0x08, 0xb9, + 0xd1, 0xaf, 0x96, 0x4b, 0x20, 0x04, 0xff, 0x2b, 0xb8, 0x9f, 0x74, 0xd0, 0x05, 0xba, 0x6c, 0x8f, + 0x42, 0x26, 0xe7, 0x18, 0x0b, 0xee, 0x60, 0x9c, 0x54, 0x58, 0xa7, 0x19, 0x2e, 0xed, 0x6a, 0x13, + 0xbc, 0xe8, 0x03, 0xe1, 0xd6, 0x33, 0xb7, 0x5c, 0x3b, 0x32, 0xc0, 0xfb, 0x0e, 0xf2, 0x64, 0x0c, + 0x39, 0x17, 0x19, 0x24, 0xe1, 0xcb, 0xff, 0xe1, 0xe9, 0x7a, 0xd1, 0x3b, 0x9a, 0x71, 0x9d, 0x0d, + 0xa2, 0xfa, 0x35, 0x1a, 0xed, 0x55, 0xe3, 0xd3, 0x66, 0x22, 0x0f, 0xf8, 0xd0, 0x82, 0x04, 0x55, + 0xc2, 0x4e, 0x6f, 0x06, 0xbd, 0xbb, 0x5e, 0xf4, 0x4e, 0x36, 0xfa, 0x1f, 0x20, 0x1a, 0x1d, 0x6c, + 0x37, 0xdb, 0x27, 0xc3, 0x97, 0xaf, 0x25, 0x45, 0xf3, 0x25, 0x45, 0x3f, 0x4b, 0x8a, 0x3e, 0x57, + 0xb4, 0x31, 0x5f, 0xd1, 0xc6, 0xf7, 0x8a, 0x36, 0xde, 0xee, 0x52, 0xe5, 0x27, 0x53, 0x11, 0x4b, + 0xa3, 0x99, 0x34, 0x4e, 0x1b, 0xc7, 0x94, 0x90, 0xd7, 0xa9, 0x61, 0xe5, 0x2d, 0xd3, 0x26, 0x99, + 0x66, 0xe0, 0xaa, 0x9e, 0x6b, 0xfd, 0xfa, 0x59, 0x01, 0x4e, 0xb4, 0x42, 0x4d, 0x37, 0xbf, 0x01, + 0x00, 0x00, 0xff, 0xff, 0x71, 0xb6, 0xa1, 0xba, 0x89, 0x01, 0x00, 0x00, } func (m *DenomTrace) Marshal() (dAtA []byte, err error) { diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index f240ba7368e..1cf3dcabc22 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -7,7 +7,7 @@ import ( context "context" fmt "fmt" types "github.com/cosmos/cosmos-sdk/types" - types1 "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + types1 "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -135,35 +135,35 @@ var fileDescriptor_7401ed9bed2f8e09 = []byte{ // 494 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x31, 0x6f, 0xd3, 0x40, 0x14, 0xc7, 0x6d, 0x92, 0x86, 0x70, 0x51, 0x2b, 0x30, 0xb4, 0x72, 0xa3, 0x62, 0x47, 0x96, 0x90, - 0xc2, 0xc0, 0x9d, 0xdc, 0x0a, 0x55, 0xea, 0x84, 0xd2, 0x05, 0x86, 0x4a, 0x60, 0x75, 0x62, 0x29, - 0xf6, 0xf5, 0x70, 0x4e, 0xc4, 0xf7, 0xac, 0xbb, 0x8b, 0x45, 0xbf, 0x01, 0x23, 0x1f, 0xa1, 0x33, - 0x9f, 0xa4, 0x63, 0x47, 0xa6, 0x08, 0x25, 0x0b, 0x73, 0x3e, 0x01, 0x3a, 0xfb, 0x12, 0x92, 0x05, - 0x31, 0xd9, 0xef, 0xfd, 0x7f, 0xef, 0xfe, 0x7a, 0xf7, 0xde, 0xa1, 0x17, 0x3c, 0xa3, 0x24, 0x2d, - 0xcb, 0x09, 0xa7, 0xa9, 0xe6, 0x20, 0x14, 0xd1, 0x32, 0x15, 0xea, 0x33, 0x93, 0xa4, 0x8a, 0x89, - 0xfe, 0x8a, 0x4b, 0x09, 0x1a, 0xbc, 0x23, 0x9e, 0x51, 0xbc, 0x89, 0xe1, 0x15, 0x86, 0xab, 0xb8, - 0xff, 0x2c, 0x87, 0x1c, 0x6a, 0x90, 0x98, 0xbf, 0xa6, 0xa6, 0x1f, 0x50, 0x50, 0x05, 0x28, 0x92, - 0xa5, 0x8a, 0x91, 0x2a, 0xce, 0x98, 0x4e, 0x63, 0x42, 0x81, 0x0b, 0xab, 0x87, 0xc6, 0x9a, 0x82, - 0x64, 0x84, 0x4e, 0x38, 0x13, 0xda, 0x18, 0x36, 0x7f, 0x0d, 0x10, 0xfd, 0x68, 0xa1, 0xde, 0x85, - 0xca, 0x2f, 0xad, 0x93, 0x77, 0x8a, 0x7a, 0x0a, 0xa6, 0x92, 0xb2, 0xab, 0x12, 0xa4, 0xf6, 0xdd, - 0x81, 0x3b, 0x7c, 0x34, 0x3a, 0x58, 0xce, 0x42, 0xef, 0x26, 0x2d, 0x26, 0x67, 0xd1, 0x86, 0x18, - 0x25, 0xa8, 0x89, 0xde, 0x83, 0xd4, 0xde, 0x1b, 0xb4, 0x67, 0x35, 0x3a, 0x4e, 0x85, 0x60, 0x13, - 0xff, 0x41, 0x5d, 0x7b, 0xb8, 0x9c, 0x85, 0xfb, 0x5b, 0xb5, 0x56, 0x8f, 0x92, 0xdd, 0x26, 0x71, - 0xde, 0xc4, 0xde, 0x6b, 0xb4, 0xa3, 0xe1, 0x0b, 0x13, 0x7e, 0x6b, 0xe0, 0x0e, 0x7b, 0xc7, 0x87, - 0xb8, 0xe9, 0x0d, 0x9b, 0xde, 0xb0, 0xed, 0x0d, 0x9f, 0x03, 0x17, 0xa3, 0xf6, 0xdd, 0x2c, 0x74, - 0x92, 0x86, 0xf6, 0x0e, 0x50, 0x47, 0x31, 0x71, 0xcd, 0xa4, 0xdf, 0x36, 0x86, 0x89, 0x8d, 0xbc, - 0x3e, 0xea, 0x4a, 0x46, 0x19, 0xaf, 0x98, 0xf4, 0x77, 0x6a, 0x65, 0x1d, 0x7b, 0x9f, 0xd0, 0x9e, - 0xe6, 0x05, 0x83, 0xa9, 0xbe, 0x1a, 0x33, 0x9e, 0x8f, 0xb5, 0xdf, 0xa9, 0x3d, 0xfb, 0xd8, 0xcc, - 0xc0, 0xdc, 0x17, 0xb6, 0xb7, 0x54, 0xc5, 0xf8, 0x6d, 0x4d, 0x8c, 0x9e, 0x1b, 0xd3, 0xbf, 0xcd, - 0x6c, 0xd7, 0x47, 0xc9, 0xae, 0x4d, 0x34, 0xb4, 0xf7, 0x0e, 0x3d, 0x59, 0x11, 0xe6, 0xab, 0x74, - 0x5a, 0x94, 0xfe, 0xc3, 0x81, 0x3b, 0x6c, 0x8f, 0x8e, 0x96, 0xb3, 0xd0, 0xdf, 0x3e, 0x64, 0x8d, - 0x44, 0xc9, 0x63, 0x9b, 0xbb, 0x5c, 0xa5, 0xce, 0xba, 0xdf, 0x6e, 0x43, 0xe7, 0xf7, 0x6d, 0xe8, - 0x44, 0xfb, 0xe8, 0xe9, 0xc6, 0xac, 0x12, 0xa6, 0x4a, 0x10, 0x8a, 0x1d, 0x03, 0x6a, 0x5d, 0xa8, - 0xdc, 0x1b, 0xa3, 0xee, 0x7a, 0x8c, 0x2f, 0xf1, 0xbf, 0x96, 0x09, 0x6f, 0x9c, 0xd2, 0x8f, 0xff, - 0x1b, 0x5d, 0x19, 0x8e, 0x3e, 0xdc, 0xcd, 0x03, 0xf7, 0x7e, 0x1e, 0xb8, 0xbf, 0xe6, 0x81, 0xfb, - 0x7d, 0x11, 0x38, 0xf7, 0x8b, 0xc0, 0xf9, 0xb9, 0x08, 0x9c, 0x8f, 0xa7, 0x39, 0xd7, 0xe3, 0x69, - 0x86, 0x29, 0x14, 0xc4, 0xae, 0x26, 0xcf, 0xe8, 0xab, 0x1c, 0x48, 0x75, 0x42, 0x0a, 0xb8, 0x9e, - 0x4e, 0x98, 0x32, 0x4f, 0x61, 0xe3, 0x09, 0xe8, 0x9b, 0x92, 0xa9, 0xac, 0x53, 0xaf, 0xe3, 0xc9, - 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x07, 0x3c, 0x39, 0x2c, 0x03, 0x00, 0x00, + 0xc2, 0xc0, 0x9d, 0x5c, 0x40, 0x95, 0x3a, 0xa1, 0x74, 0x81, 0xa1, 0x12, 0x58, 0x9d, 0x58, 0x8a, + 0x7d, 0x3d, 0x9c, 0x13, 0xf1, 0x3d, 0xeb, 0xee, 0x62, 0xd1, 0x6f, 0xc0, 0xc8, 0x47, 0xe8, 0xcc, + 0x27, 0xe9, 0xd8, 0x91, 0x29, 0x42, 0xc9, 0xc2, 0x9c, 0x4f, 0x80, 0xce, 0xbe, 0x84, 0x64, 0x41, + 0x4c, 0xf6, 0x7b, 0xff, 0xdf, 0xbb, 0xbf, 0xde, 0xbd, 0x77, 0xe8, 0x19, 0xcf, 0x28, 0x49, 0xcb, + 0x72, 0xc2, 0x69, 0xaa, 0x39, 0x08, 0x45, 0xb4, 0x4c, 0x85, 0xfa, 0xcc, 0x24, 0xa9, 0x62, 0xa2, + 0xbf, 0xe2, 0x52, 0x82, 0x06, 0xef, 0x88, 0x67, 0x14, 0x6f, 0x62, 0x78, 0x85, 0xe1, 0x2a, 0xee, + 0x3f, 0xc9, 0x21, 0x87, 0x1a, 0x24, 0xe6, 0xaf, 0xa9, 0xe9, 0x07, 0x14, 0x54, 0x01, 0x8a, 0x64, + 0xa9, 0x62, 0xa4, 0x8a, 0x33, 0xa6, 0xd3, 0x98, 0x50, 0xe0, 0xc2, 0xea, 0xa1, 0xb1, 0xa6, 0x20, + 0x19, 0xa1, 0x13, 0xce, 0x84, 0x36, 0x86, 0xcd, 0x5f, 0x03, 0x44, 0x3f, 0x5a, 0xa8, 0x77, 0xae, + 0xf2, 0x0b, 0xeb, 0xe4, 0x9d, 0xa0, 0x9e, 0x82, 0xa9, 0xa4, 0xec, 0xb2, 0x04, 0xa9, 0x7d, 0x77, + 0xe0, 0x0e, 0x1f, 0x8c, 0x0e, 0x96, 0xb3, 0xd0, 0xbb, 0x4e, 0x8b, 0xc9, 0x69, 0xb4, 0x21, 0x46, + 0x09, 0x6a, 0xa2, 0xf7, 0x20, 0xb5, 0xf7, 0x06, 0xed, 0x59, 0x8d, 0x8e, 0x53, 0x21, 0xd8, 0xc4, + 0xbf, 0x57, 0xd7, 0x1e, 0x2e, 0x67, 0xe1, 0xfe, 0x56, 0xad, 0xd5, 0xa3, 0x64, 0xb7, 0x49, 0x9c, + 0x35, 0xb1, 0xf7, 0x1a, 0xed, 0x68, 0xf8, 0xc2, 0x84, 0xdf, 0x1a, 0xb8, 0xc3, 0xde, 0xf1, 0x21, + 0x6e, 0x7a, 0xc3, 0xa6, 0x37, 0x6c, 0x7b, 0xc3, 0x67, 0xc0, 0xc5, 0xa8, 0x7d, 0x3b, 0x0b, 0x9d, + 0xa4, 0xa1, 0xbd, 0x03, 0xd4, 0x51, 0x4c, 0x5c, 0x31, 0xe9, 0xb7, 0x8d, 0x61, 0x62, 0x23, 0xaf, + 0x8f, 0xba, 0x92, 0x51, 0xc6, 0x2b, 0x26, 0xfd, 0x9d, 0x5a, 0x59, 0xc7, 0xde, 0x27, 0xb4, 0xa7, + 0x79, 0xc1, 0x60, 0xaa, 0x2f, 0xc7, 0x8c, 0xe7, 0x63, 0xed, 0x77, 0x6a, 0xcf, 0x3e, 0x36, 0x33, + 0x30, 0xf7, 0x85, 0xed, 0x2d, 0x55, 0x31, 0x7e, 0x5b, 0x13, 0xa3, 0xa7, 0xc6, 0xf4, 0x6f, 0x33, + 0xdb, 0xf5, 0x51, 0xb2, 0x6b, 0x13, 0x0d, 0xed, 0xbd, 0x43, 0x8f, 0x56, 0x84, 0xf9, 0x2a, 0x9d, + 0x16, 0xa5, 0x7f, 0x7f, 0xe0, 0x0e, 0xdb, 0xa3, 0xa3, 0xe5, 0x2c, 0xf4, 0xb7, 0x0f, 0x59, 0x23, + 0x51, 0xf2, 0xd0, 0xe6, 0x2e, 0x56, 0xa9, 0xd3, 0xee, 0xb7, 0x9b, 0xd0, 0xf9, 0x7d, 0x13, 0x3a, + 0xd1, 0x3e, 0x7a, 0xbc, 0x31, 0xab, 0x84, 0xa9, 0x12, 0x84, 0x62, 0xc7, 0x80, 0x5a, 0xe7, 0x2a, + 0xf7, 0xc6, 0xa8, 0xbb, 0x1e, 0xe3, 0x73, 0xfc, 0xaf, 0x65, 0xc2, 0x1b, 0xa7, 0xf4, 0xe3, 0xff, + 0x46, 0x57, 0x86, 0xa3, 0x0f, 0xb7, 0xf3, 0xc0, 0xbd, 0x9b, 0x07, 0xee, 0xaf, 0x79, 0xe0, 0x7e, + 0x5f, 0x04, 0xce, 0xdd, 0x22, 0x70, 0x7e, 0x2e, 0x02, 0xe7, 0xe3, 0x49, 0xce, 0xf5, 0x78, 0x9a, + 0x61, 0x0a, 0x05, 0xb1, 0xab, 0xc9, 0x33, 0xfa, 0x22, 0x07, 0x52, 0xbd, 0x22, 0x05, 0x5c, 0x4d, + 0x27, 0x4c, 0x99, 0xa7, 0xb0, 0xf1, 0x04, 0xf4, 0x75, 0xc9, 0x54, 0xd6, 0xa9, 0xd7, 0xf1, 0xe5, + 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd0, 0x6e, 0x0e, 0x0d, 0x2c, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/02-client/abci.go b/modules/core/02-client/abci.go index aa13295e1c9..87039aeee10 100644 --- a/modules/core/02-client/abci.go +++ b/modules/core/02-client/abci.go @@ -3,9 +3,9 @@ package client import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/keeper" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/keeper" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) // BeginBlocker updates an existing localhost client with the latest block height. diff --git a/modules/core/02-client/abci_test.go b/modules/core/02-client/abci_test.go index 80ebdb338ec..27f8f7f4b12 100644 --- a/modules/core/02-client/abci_test.go +++ b/modules/core/02-client/abci_test.go @@ -8,12 +8,12 @@ import ( abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - client "github.com/cosmos/ibc-go/v3/modules/core/02-client" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + client "github.com/cosmos/ibc-go/v4/modules/core/02-client" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + localhosttypes "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type ClientTestSuite struct { diff --git a/modules/core/02-client/client/cli/cli.go b/modules/core/02-client/client/cli/cli.go index d06977016bd..74bb514ae1d 100644 --- a/modules/core/02-client/client/cli/cli.go +++ b/modules/core/02-client/client/cli/cli.go @@ -4,7 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ) // GetQueryCmd returns the query commands for IBC clients diff --git a/modules/core/02-client/client/cli/query.go b/modules/core/02-client/client/cli/query.go index 56093a8368f..66e114902fe 100644 --- a/modules/core/02-client/client/cli/query.go +++ b/modules/core/02-client/client/cli/query.go @@ -9,9 +9,9 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/client/utils" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/client/utils" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) const ( diff --git a/modules/core/02-client/client/cli/tx.go b/modules/core/02-client/client/cli/tx.go index ca65d5b2b17..fdf9b8e5b89 100644 --- a/modules/core/02-client/client/cli/tx.go +++ b/modules/core/02-client/client/cli/tx.go @@ -16,8 +16,8 @@ import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // NewCreateClientCmd defines the command to create a new IBC light client. diff --git a/modules/core/02-client/client/proposal_handler.go b/modules/core/02-client/client/proposal_handler.go index 93e98dbc8b2..2c5aa8911d1 100644 --- a/modules/core/02-client/client/proposal_handler.go +++ b/modules/core/02-client/client/proposal_handler.go @@ -8,7 +8,7 @@ import ( govclient "github.com/cosmos/cosmos-sdk/x/gov/client" govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/client/cli" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/client/cli" ) var ( diff --git a/modules/core/02-client/client/utils/utils.go b/modules/core/02-client/client/utils/utils.go index a596ff61410..d4361098085 100644 --- a/modules/core/02-client/client/utils/utils.go +++ b/modules/core/02-client/client/utils/utils.go @@ -8,12 +8,12 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/client" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/client" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) // QueryClientState returns a client state. If prove is true, it performs an ABCI store query diff --git a/modules/core/02-client/genesis.go b/modules/core/02-client/genesis.go index 6ba20b22510..8d4654d6438 100644 --- a/modules/core/02-client/genesis.go +++ b/modules/core/02-client/genesis.go @@ -5,9 +5,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/keeper" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/keeper" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // InitGenesis initializes the ibc client submodule's state from a provided genesis diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index 0360952e75a..4b770dafe19 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -8,8 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // CreateClient creates a new client state and populates it with a given consensus diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index cde30cbb0fe..d3492e9f25e 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -8,14 +8,14 @@ import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibctestingmock "github.com/cosmos/ibc-go/v3/testing/mock" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + localhosttypes "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibctestingmock "github.com/cosmos/ibc-go/v4/testing/mock" ) func (suite *KeeperTestSuite) TestCreateClient() { diff --git a/modules/core/02-client/keeper/encoding.go b/modules/core/02-client/keeper/encoding.go index 9a8156df37e..6c036455ce3 100644 --- a/modules/core/02-client/keeper/encoding.go +++ b/modules/core/02-client/keeper/encoding.go @@ -1,8 +1,8 @@ package keeper import ( - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // UnmarshalClientState attempts to decode and return an ClientState object from diff --git a/modules/core/02-client/keeper/events.go b/modules/core/02-client/keeper/events.go index ad82292dc61..0702651a611 100644 --- a/modules/core/02-client/keeper/events.go +++ b/modules/core/02-client/keeper/events.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // EmitCreateClientEvent emits a create client event diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index bc7ce9f8241..3fc7b6e7cde 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -14,9 +14,9 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ types.QueryServer = Keeper{} diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index e6d3a1ae1ba..1fb29d06964 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -9,10 +9,10 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" "google.golang.org/grpc/metadata" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestQueryClientState() { diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 74a043e9dea..fbb911f8997 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -14,11 +14,11 @@ import ( "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/light" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) // Keeper represents a type that grants read and write permissions to any client diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index bbcc6dafde9..11acea3df7d 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -15,15 +15,15 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/keeper" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibctestingmock "github.com/cosmos/ibc-go/v3/testing/mock" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/keeper" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + localhosttypes "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibctestingmock "github.com/cosmos/ibc-go/v4/testing/mock" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) const ( diff --git a/modules/core/02-client/keeper/migrations.go b/modules/core/02-client/keeper/migrations.go index 53ff8a657e7..c0ad7210341 100644 --- a/modules/core/02-client/keeper/migrations.go +++ b/modules/core/02-client/keeper/migrations.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - v100 "github.com/cosmos/ibc-go/v3/modules/core/02-client/legacy/v100" + v100 "github.com/cosmos/ibc-go/v4/modules/core/02-client/legacy/v100" ) // Migrator is a struct for handling in-place store migrations. diff --git a/modules/core/02-client/keeper/params.go b/modules/core/02-client/keeper/params.go index 84bd2845ba3..d2ba2000792 100644 --- a/modules/core/02-client/keeper/params.go +++ b/modules/core/02-client/keeper/params.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ) // GetAllowedClients retrieves the allowed clients from the paramstore diff --git a/modules/core/02-client/keeper/params_test.go b/modules/core/02-client/keeper/params_test.go index c293f7ec195..fe136a6346b 100644 --- a/modules/core/02-client/keeper/params_test.go +++ b/modules/core/02-client/keeper/params_test.go @@ -1,7 +1,7 @@ package keeper_test import ( - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ) func (suite *KeeperTestSuite) TestParams() { diff --git a/modules/core/02-client/keeper/proposal.go b/modules/core/02-client/keeper/proposal.go index 5e483d8a110..4b182e5e7c3 100644 --- a/modules/core/02-client/keeper/proposal.go +++ b/modules/core/02-client/keeper/proposal.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // ClientUpdateProposal will retrieve the subject and substitute client. diff --git a/modules/core/02-client/keeper/proposal_test.go b/modules/core/02-client/keeper/proposal_test.go index 277354f9e9b..5a635d99ecc 100644 --- a/modules/core/02-client/keeper/proposal_test.go +++ b/modules/core/02-client/keeper/proposal_test.go @@ -4,10 +4,10 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestClientUpdateProposal() { diff --git a/modules/core/02-client/legacy/v100/genesis.go b/modules/core/02-client/legacy/v100/genesis.go index 014dd3870c0..156a067f386 100644 --- a/modules/core/02-client/legacy/v100/genesis.go +++ b/modules/core/02-client/legacy/v100/genesis.go @@ -7,10 +7,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) // MigrateGenesis accepts exported v1.0.0 IBC client genesis file and migrates it to: diff --git a/modules/core/02-client/legacy/v100/genesis_test.go b/modules/core/02-client/legacy/v100/genesis_test.go index c4daa6c9bfc..04f6b33f053 100644 --- a/modules/core/02-client/legacy/v100/genesis_test.go +++ b/modules/core/02-client/legacy/v100/genesis_test.go @@ -9,14 +9,14 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/02-client" - v100 "github.com/cosmos/ibc-go/v3/modules/core/02-client/legacy/v100" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - "github.com/cosmos/ibc-go/v3/testing/simapp" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/02-client" + v100 "github.com/cosmos/ibc-go/v4/modules/core/02-client/legacy/v100" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) func (suite *LegacyTestSuite) TestMigrateGenesisSolomachine() { diff --git a/modules/core/02-client/legacy/v100/solomachine.go b/modules/core/02-client/legacy/v100/solomachine.go index b9ae2b1005e..a9b8fa49340 100644 --- a/modules/core/02-client/legacy/v100/solomachine.go +++ b/modules/core/02-client/legacy/v100/solomachine.go @@ -7,7 +7,7 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // NOTE: this is a mock implmentation for exported.ClientState. This implementation diff --git a/modules/core/02-client/legacy/v100/solomachine.pb.go b/modules/core/02-client/legacy/v100/solomachine.pb.go index 1c87a4d9d2f..3ed69fb1b21 100644 --- a/modules/core/02-client/legacy/v100/solomachine.pb.go +++ b/modules/core/02-client/legacy/v100/solomachine.pb.go @@ -6,8 +6,8 @@ package v100 import ( fmt "fmt" types "github.com/cosmos/cosmos-sdk/codec/types" - types1 "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - types2 "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + types1 "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + types2 "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -826,90 +826,90 @@ var fileDescriptor_6cc2ee18f7f86d4e = []byte{ // 1369 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x5f, 0x6f, 0xdb, 0x54, 0x14, 0xaf, 0xb3, 0xac, 0x6b, 0x4e, 0xba, 0x36, 0x78, 0xd9, 0x96, 0x7a, 0x53, 0x62, 0x8c, 0x18, - 0x05, 0xb1, 0x78, 0xed, 0xc4, 0x84, 0x26, 0x34, 0x70, 0x1c, 0xc3, 0xb2, 0xb5, 0x6e, 0x70, 0x5c, - 0xd8, 0x26, 0x24, 0xcb, 0x71, 0x6e, 0x53, 0x6b, 0x89, 0x6f, 0x88, 0x9d, 0x74, 0x41, 0x42, 0x42, - 0x3c, 0x8d, 0x88, 0x07, 0xbe, 0x40, 0x24, 0x04, 0xe2, 0xab, 0x00, 0x8f, 0xe3, 0x8d, 0xa7, 0x80, - 0xb6, 0x6f, 0x90, 0x4f, 0x80, 0xec, 0x7b, 0x13, 0xdb, 0xe9, 0x9a, 0x8a, 0x7f, 0x6f, 0xf7, 0x9e, - 0xf3, 0x3b, 0xbf, 0x73, 0xee, 0x39, 0xc7, 0xe7, 0x5e, 0xc3, 0x96, 0x5d, 0xb7, 0xc4, 0x96, 0xdd, - 0x3c, 0xf4, 0xac, 0x96, 0x8d, 0x1c, 0xcf, 0x15, 0x5d, 0xdc, 0xc2, 0x6d, 0xd3, 0x3a, 0xb4, 0x1d, - 0x24, 0xf6, 0xb7, 0xa2, 0xdb, 0x62, 0xa7, 0x8b, 0x3d, 0xcc, 0x16, 0xec, 0xba, 0x55, 0x8c, 0x9a, - 0x14, 0xa3, 0x98, 0xfe, 0x16, 0xf7, 0x86, 0xcf, 0x69, 0xe1, 0x2e, 0x12, 0x2d, 0xec, 0x38, 0xc8, - 0xf2, 0x6c, 0xec, 0xf8, 0x54, 0xe1, 0x8e, 0x30, 0x71, 0xaf, 0x86, 0xc0, 0x43, 0xd3, 0x71, 0x50, - 0x2b, 0x40, 0x91, 0x25, 0x85, 0x64, 0x9b, 0xb8, 0x89, 0x83, 0xa5, 0xe8, 0xaf, 0xa8, 0x74, 0xa3, - 0x89, 0x71, 0xb3, 0x85, 0xc4, 0x60, 0x57, 0xef, 0x1d, 0x88, 0xa6, 0x33, 0x20, 0x2a, 0xe1, 0xb7, - 0x04, 0xa4, 0xe5, 0x20, 0xae, 0x9a, 0x67, 0x7a, 0x88, 0xe5, 0x60, 0xc5, 0x45, 0x9f, 0xf7, 0x90, - 0x63, 0xa1, 0x1c, 0xc3, 0x33, 0x9b, 0x49, 0x6d, 0xb6, 0x67, 0x65, 0x58, 0x3f, 0xe8, 0xe2, 0x2f, - 0x90, 0x63, 0xcc, 0x20, 0x09, 0x1f, 0x52, 0xe2, 0x26, 0xe3, 0xc2, 0xa5, 0x81, 0xd9, 0x6e, 0xdd, - 0x16, 0xe6, 0x00, 0x82, 0xb6, 0x46, 0x24, 0xb5, 0x29, 0x89, 0x07, 0xeb, 0x16, 0x76, 0x5c, 0xe4, - 0xb8, 0x3d, 0xd7, 0x70, 0x7d, 0x9f, 0xb9, 0x33, 0x3c, 0xb3, 0x99, 0xde, 0x16, 0x8b, 0xa7, 0x24, - 0xaa, 0x28, 0x4f, 0xed, 0x82, 0x50, 0xa3, 0x5e, 0xe7, 0x18, 0x05, 0x6d, 0xcd, 0x8a, 0x61, 0x59, - 0x04, 0x57, 0xcc, 0x56, 0x0b, 0x1f, 0x19, 0xbd, 0x4e, 0xc3, 0xf4, 0x90, 0x61, 0x1e, 0x78, 0xa8, - 0x6b, 0x74, 0xba, 0xb8, 0x83, 0x5d, 0xb3, 0x95, 0x4b, 0xf2, 0xcc, 0xe6, 0x4a, 0xe9, 0xda, 0x64, - 0x5c, 0x10, 0x08, 0xe1, 0x02, 0xb0, 0xa0, 0xe5, 0x02, 0xed, 0x7e, 0xa0, 0x94, 0x7c, 0x5d, 0x95, - 0xaa, 0x6e, 0x27, 0x9f, 0x7e, 0x5f, 0x58, 0x12, 0x7e, 0x60, 0x60, 0x2d, 0x1e, 0x2b, 0x7b, 0x0f, - 0xa0, 0xd3, 0xab, 0xb7, 0x6c, 0xcb, 0x78, 0x8c, 0x06, 0x41, 0x62, 0xd3, 0xdb, 0xd9, 0x22, 0x29, - 0x4b, 0x71, 0x5a, 0x96, 0xa2, 0xe4, 0x0c, 0x4a, 0x17, 0x27, 0xe3, 0xc2, 0x2b, 0x24, 0x88, 0xd0, - 0x42, 0xd0, 0x52, 0x64, 0x73, 0x1f, 0x0d, 0x58, 0x1e, 0xd2, 0x0d, 0xbb, 0x8f, 0xba, 0xae, 0x7d, - 0x60, 0xa3, 0x6e, 0x50, 0x82, 0x94, 0x16, 0x15, 0xb1, 0x57, 0x21, 0xe5, 0xd9, 0x6d, 0xe4, 0x7a, - 0x66, 0xbb, 0x13, 0x64, 0x37, 0xa9, 0x85, 0x02, 0x1a, 0xe4, 0xd7, 0x09, 0x58, 0xbe, 0x8b, 0xcc, - 0x06, 0xea, 0x2e, 0xac, 0x79, 0x8c, 0x2a, 0x31, 0x47, 0xe5, 0x6b, 0x5d, 0xbb, 0xe9, 0x98, 0x5e, - 0xaf, 0x4b, 0xca, 0xb8, 0xaa, 0x85, 0x02, 0x76, 0x1f, 0xd6, 0x1c, 0x74, 0x64, 0x44, 0x0e, 0x9e, - 0x5c, 0x70, 0xf0, 0x8d, 0xc9, 0xb8, 0x70, 0x91, 0x1c, 0x3c, 0x6e, 0x25, 0x68, 0xab, 0x0e, 0x3a, - 0xaa, 0xce, 0xce, 0x2f, 0xc3, 0xba, 0x0f, 0x88, 0xe6, 0xe0, 0xac, 0x9f, 0x83, 0x68, 0x43, 0xcc, - 0x01, 0x04, 0xcd, 0x8f, 0xa4, 0x1c, 0x0a, 0x68, 0x12, 0x7e, 0x49, 0xc0, 0xea, 0xae, 0xed, 0xd6, - 0xd1, 0xa1, 0xd9, 0xb7, 0x71, 0xaf, 0xcb, 0x6e, 0x41, 0x8a, 0x34, 0x9f, 0x61, 0x37, 0x82, 0x5c, - 0xa4, 0x4a, 0xd9, 0xc9, 0xb8, 0x90, 0xa1, 0x6d, 0x36, 0x55, 0x09, 0xda, 0x0a, 0x59, 0x57, 0x1a, - 0xb1, 0xec, 0x25, 0xe6, 0xb2, 0xd7, 0x81, 0xf3, 0xb3, 0x74, 0x18, 0xd8, 0x99, 0xb6, 0xfa, 0xd6, - 0xa9, 0xad, 0x5e, 0x9b, 0x5a, 0x49, 0x4e, 0xa3, 0x6c, 0x7a, 0x66, 0x29, 0x37, 0x19, 0x17, 0xb2, - 0x24, 0x8a, 0x18, 0xa3, 0xa0, 0xad, 0xce, 0xf6, 0x7b, 0xce, 0x9c, 0x47, 0xef, 0x08, 0xd3, 0x94, - 0xff, 0x57, 0x1e, 0xbd, 0x23, 0x1c, 0xf5, 0xa8, 0x1f, 0x61, 0x9a, 0xc9, 0x9f, 0x19, 0xc8, 0xcc, - 0x53, 0xc4, 0xdb, 0x83, 0x99, 0x6f, 0x8f, 0xcf, 0x20, 0xd5, 0x30, 0x3d, 0xd3, 0xf0, 0x06, 0x1d, - 0x92, 0xb9, 0xb5, 0xed, 0x37, 0x4f, 0x0d, 0xd3, 0xe7, 0xd5, 0x07, 0x1d, 0x14, 0x2d, 0xcb, 0x8c, - 0x45, 0xd0, 0x56, 0x1a, 0x54, 0xcf, 0xb2, 0x90, 0xf4, 0xd7, 0xb4, 0x2b, 0x83, 0x75, 0xbc, 0x99, - 0x93, 0x2f, 0xff, 0x2e, 0xbe, 0x62, 0x20, 0xa7, 0x4f, 0x65, 0xa8, 0x31, 0x3b, 0x53, 0x70, 0xa0, - 0x0f, 0x60, 0x2d, 0xcc, 0x45, 0x40, 0x1f, 0x9c, 0x2a, 0xda, 0xbb, 0x71, 0xbd, 0xa0, 0x85, 0xe5, - 0x28, 0x1f, 0x0b, 0x21, 0xf1, 0xf2, 0x10, 0xfe, 0x60, 0x20, 0xe5, 0xfb, 0x2d, 0x0d, 0x3c, 0xe4, - 0xfe, 0x8b, 0xaf, 0x73, 0x6e, 0x50, 0x9c, 0x39, 0x3e, 0x28, 0x62, 0x25, 0x48, 0xfe, 0x5f, 0x25, - 0x38, 0x1b, 0x96, 0x80, 0x9e, 0xf0, 0x27, 0x06, 0x80, 0x0c, 0x9f, 0x20, 0x29, 0x3b, 0x90, 0xa6, - 0x9f, 0xfc, 0xa9, 0xe3, 0xf1, 0xd2, 0x64, 0x5c, 0x60, 0x63, 0x53, 0x82, 0xce, 0x47, 0x32, 0x22, - 0x4e, 0x98, 0x0f, 0x89, 0x7f, 0x38, 0x1f, 0xbe, 0x84, 0xf5, 0xc8, 0xe5, 0x18, 0xc4, 0xca, 0x42, - 0xb2, 0x63, 0x7a, 0x87, 0xb4, 0x9d, 0x83, 0x35, 0x5b, 0x85, 0x55, 0x3a, 0x1a, 0xc8, 0x85, 0x96, - 0x58, 0x70, 0x80, 0xcb, 0x93, 0x71, 0xe1, 0x42, 0x6c, 0x9c, 0xd0, 0x2b, 0x2b, 0x6d, 0x85, 0x9e, - 0xa8, 0xfb, 0x6f, 0x18, 0x60, 0xe3, 0x17, 0xc9, 0x89, 0x21, 0x3c, 0x3c, 0x7e, 0xad, 0x2e, 0x8a, - 0xe2, 0x6f, 0xdc, 0x9d, 0x34, 0x96, 0x3e, 0x5c, 0x90, 0x67, 0x0f, 0x92, 0xc5, 0xb1, 0x28, 0x00, - 0xe1, 0xdb, 0x85, 0x86, 0xf1, 0x7a, 0xd0, 0x56, 0xfe, 0xe3, 0xa5, 0x18, 0x79, 0xd7, 0x90, 0x4b, - 0x9d, 0xee, 0x14, 0xa7, 0xa1, 0x45, 0x0c, 0xa9, 0xdf, 0x06, 0x64, 0x64, 0xf2, 0xc4, 0x59, 0xec, - 0xf4, 0x16, 0x9c, 0xa3, 0x4f, 0x21, 0xea, 0xf1, 0x6a, 0xc4, 0x23, 0x7d, 0x23, 0xf9, 0xee, 0xc8, - 0x52, 0x9b, 0x82, 0xa9, 0x97, 0x7b, 0x90, 0xad, 0x9a, 0xd6, 0x63, 0xe4, 0xc9, 0xb8, 0xdd, 0xb6, - 0xbd, 0x36, 0x72, 0xbc, 0x13, 0x3d, 0xe5, 0xfd, 0xe3, 0x4d, 0x51, 0x81, 0xb3, 0x55, 0x2d, 0x22, - 0x11, 0x1e, 0xc2, 0x06, 0xe1, 0x92, 0xac, 0xc7, 0x0e, 0x3e, 0x6a, 0xa1, 0x46, 0x13, 0x2d, 0x24, - 0xdc, 0x84, 0x75, 0x33, 0x0e, 0xa5, 0xac, 0xf3, 0x62, 0xa1, 0x08, 0x39, 0x42, 0xad, 0x21, 0x0b, - 0xd9, 0x1d, 0x4f, 0xaa, 0xbb, 0xfe, 0x1c, 0x38, 0x89, 0x59, 0x38, 0x84, 0xac, 0x8a, 0x9e, 0x78, - 0xd3, 0xc7, 0x97, 0x86, 0xac, 0xfe, 0x89, 0x51, 0xbc, 0x07, 0xe7, 0x1d, 0xf4, 0xc4, 0xf3, 0x9f, - 0x6e, 0x46, 0x17, 0x59, 0x7d, 0xfa, 0xb6, 0x8b, 0x5c, 0x03, 0x31, 0xb5, 0xa0, 0xa5, 0x1d, 0x42, - 0xed, 0xb3, 0xbe, 0xf5, 0x6d, 0x12, 0x56, 0xa6, 0x83, 0x81, 0x7d, 0x17, 0x5e, 0x2b, 0x4b, 0xba, - 0x64, 0xe8, 0x0f, 0xab, 0x8a, 0xb1, 0xaf, 0x56, 0xd4, 0x8a, 0x5e, 0x91, 0x76, 0x2a, 0x8f, 0x94, - 0xb2, 0xb1, 0xaf, 0xd6, 0xaa, 0x8a, 0x5c, 0xf9, 0xb0, 0xa2, 0x94, 0x33, 0x4b, 0xdc, 0xfa, 0x70, - 0xc4, 0xa7, 0x23, 0x22, 0xf6, 0x1a, 0x5c, 0x0a, 0x2d, 0xe5, 0x9d, 0x8a, 0xa2, 0xea, 0x46, 0x4d, - 0x97, 0x74, 0x25, 0xc3, 0x70, 0x30, 0x1c, 0xf1, 0xcb, 0x44, 0xc6, 0xbe, 0x0d, 0x1b, 0x11, 0xdc, - 0x9e, 0x5a, 0x53, 0xd4, 0xda, 0x7e, 0x8d, 0x42, 0x13, 0xdc, 0xf9, 0xe1, 0x88, 0x4f, 0xcd, 0xc4, - 0x6c, 0x11, 0xb8, 0x18, 0x5a, 0x55, 0x64, 0xbd, 0xb2, 0xa7, 0x52, 0xf8, 0x19, 0x6e, 0x6d, 0x38, - 0xe2, 0x21, 0x94, 0xb3, 0x9b, 0x70, 0x39, 0x82, 0xbf, 0x2b, 0xa9, 0xaa, 0xb2, 0x43, 0xc1, 0x49, - 0x2e, 0x3d, 0x1c, 0xf1, 0xe7, 0xa8, 0x90, 0x7d, 0x07, 0xae, 0x84, 0xc8, 0xaa, 0x24, 0xdf, 0x57, - 0x74, 0x43, 0xde, 0xdb, 0xdd, 0xad, 0xe8, 0xbb, 0x8a, 0xaa, 0x67, 0xce, 0x72, 0xd9, 0xe1, 0x88, - 0xcf, 0x10, 0x45, 0x28, 0x67, 0xdf, 0x07, 0xfe, 0x98, 0x99, 0x24, 0xdf, 0x57, 0xf7, 0x3e, 0xdd, - 0x51, 0xca, 0x1f, 0x29, 0x81, 0xed, 0x32, 0xb7, 0x31, 0x1c, 0xf1, 0x17, 0x89, 0x76, 0x4e, 0xc9, - 0xde, 0x79, 0x09, 0x81, 0xa6, 0xc8, 0x4a, 0xa5, 0xaa, 0x1b, 0x52, 0xa9, 0xa6, 0xa8, 0xb2, 0x92, - 0x39, 0xc7, 0xe5, 0x86, 0x23, 0x3e, 0x4b, 0xb4, 0x54, 0x49, 0x75, 0xec, 0x2d, 0xb8, 0x1a, 0xda, - 0xab, 0xca, 0x03, 0xdd, 0xa8, 0x29, 0x1f, 0xef, 0xfb, 0x2a, 0x9f, 0xe6, 0x93, 0xcc, 0x0a, 0x09, - 0xdc, 0xd7, 0x4c, 0x15, 0xbe, 0x9c, 0xe5, 0x21, 0x13, 0xda, 0xdd, 0x55, 0xa4, 0xb2, 0xa2, 0x65, - 0x52, 0xa4, 0x32, 0x64, 0xc7, 0x25, 0x9f, 0xfe, 0x98, 0x5f, 0x2a, 0x3d, 0xf8, 0xf5, 0x79, 0x9e, - 0x79, 0xf6, 0x3c, 0xcf, 0xfc, 0xf9, 0x3c, 0xcf, 0x7c, 0xf7, 0x22, 0xbf, 0xf4, 0xec, 0x45, 0x7e, - 0xe9, 0xf7, 0x17, 0xf9, 0xa5, 0x47, 0x77, 0x9a, 0xb6, 0x77, 0xd8, 0xab, 0x17, 0x2d, 0xdc, 0x16, - 0x2d, 0xec, 0xb6, 0xb1, 0x2b, 0xda, 0x75, 0xeb, 0x7a, 0x13, 0x8b, 0xfd, 0x9b, 0x62, 0x1b, 0x37, - 0x7a, 0x2d, 0xe4, 0x92, 0x9f, 0x9c, 0x1b, 0xdb, 0xd7, 0xc9, 0x48, 0x14, 0x5b, 0xa8, 0x69, 0x5a, - 0x03, 0xb1, 0xbf, 0x75, 0xe3, 0x46, 0x7d, 0x39, 0x98, 0x63, 0x37, 0xff, 0x0a, 0x00, 0x00, 0xff, - 0xff, 0x48, 0x29, 0x5f, 0x10, 0x8a, 0x0d, 0x00, 0x00, + 0x05, 0xb1, 0x78, 0x2d, 0x30, 0xa1, 0x09, 0x0d, 0x1c, 0xc7, 0xb0, 0x6c, 0xad, 0x1b, 0x1c, 0x17, + 0xb6, 0x09, 0xc9, 0x72, 0x9c, 0xdb, 0xd4, 0x5a, 0xe2, 0x1b, 0x62, 0x27, 0x5d, 0x90, 0x90, 0x10, + 0x4f, 0x23, 0xe2, 0x81, 0x2f, 0x10, 0x09, 0x81, 0xf8, 0x2a, 0xc0, 0xe3, 0x78, 0xe3, 0x29, 0xa0, + 0xed, 0x1b, 0xe4, 0x13, 0x20, 0xfb, 0xde, 0xc4, 0x76, 0xba, 0xa6, 0xe2, 0xdf, 0xdb, 0xbd, 0xe7, + 0xfc, 0xce, 0xef, 0x9c, 0x7b, 0xce, 0xf1, 0xb9, 0xd7, 0xb0, 0x65, 0xd7, 0x2d, 0xb1, 0x65, 0x37, + 0x0f, 0x3d, 0xab, 0x65, 0x23, 0xc7, 0x73, 0x45, 0x17, 0xb7, 0x70, 0xdb, 0xb4, 0x0e, 0x6d, 0x07, + 0x89, 0xfd, 0xad, 0xe8, 0xb6, 0xd8, 0xe9, 0x62, 0x0f, 0xb3, 0x05, 0xbb, 0x6e, 0x15, 0xa3, 0x26, + 0xc5, 0x28, 0xa6, 0xbf, 0xc5, 0xbd, 0xe6, 0x73, 0x5a, 0xb8, 0x8b, 0x44, 0x0b, 0x3b, 0x0e, 0xb2, + 0x3c, 0x1b, 0x3b, 0x3e, 0x55, 0xb8, 0x23, 0x4c, 0xdc, 0xcb, 0x21, 0xf0, 0xd0, 0x74, 0x1c, 0xd4, + 0x0a, 0x50, 0x64, 0x49, 0x21, 0xd9, 0x26, 0x6e, 0xe2, 0x60, 0x29, 0xfa, 0x2b, 0x2a, 0xdd, 0x68, + 0x62, 0xdc, 0x6c, 0x21, 0x31, 0xd8, 0xd5, 0x7b, 0x07, 0xa2, 0xe9, 0x0c, 0x88, 0x4a, 0xf8, 0x2d, + 0x01, 0x69, 0x39, 0x88, 0xab, 0xe6, 0x99, 0x1e, 0x62, 0x39, 0x58, 0x71, 0xd1, 0xe7, 0x3d, 0xe4, + 0x58, 0x28, 0xc7, 0xf0, 0xcc, 0x66, 0x52, 0x9b, 0xed, 0x59, 0x19, 0xd6, 0x0f, 0xba, 0xf8, 0x0b, + 0xe4, 0x18, 0x33, 0x48, 0xc2, 0x87, 0x94, 0xb8, 0xc9, 0xb8, 0x70, 0x69, 0x60, 0xb6, 0x5b, 0xb7, + 0x84, 0x39, 0x80, 0xa0, 0xad, 0x11, 0x49, 0x6d, 0x4a, 0xe2, 0xc1, 0xba, 0x85, 0x1d, 0x17, 0x39, + 0x6e, 0xcf, 0x35, 0x5c, 0xdf, 0x67, 0xee, 0x0c, 0xcf, 0x6c, 0xa6, 0xb7, 0xc5, 0xe2, 0x29, 0x89, + 0x2a, 0xca, 0x53, 0xbb, 0x20, 0xd4, 0xa8, 0xd7, 0x39, 0x46, 0x41, 0x5b, 0xb3, 0x62, 0x58, 0x16, + 0xc1, 0x15, 0xb3, 0xd5, 0xc2, 0x47, 0x46, 0xaf, 0xd3, 0x30, 0x3d, 0x64, 0x98, 0x07, 0x1e, 0xea, + 0x1a, 0x9d, 0x2e, 0xee, 0x60, 0xd7, 0x6c, 0xe5, 0x92, 0x3c, 0xb3, 0xb9, 0x52, 0xba, 0x36, 0x19, + 0x17, 0x04, 0x42, 0xb8, 0x00, 0x2c, 0x68, 0xb9, 0x40, 0xbb, 0x1f, 0x28, 0x25, 0x5f, 0x57, 0xa5, + 0xaa, 0x5b, 0xc9, 0x27, 0xdf, 0x17, 0x96, 0x84, 0x1f, 0x18, 0x58, 0x8b, 0xc7, 0xca, 0xde, 0x05, + 0xe8, 0xf4, 0xea, 0x2d, 0xdb, 0x32, 0x1e, 0xa1, 0x41, 0x90, 0xd8, 0xf4, 0x76, 0xb6, 0x48, 0xca, + 0x52, 0x9c, 0x96, 0xa5, 0x28, 0x39, 0x83, 0xd2, 0xc5, 0xc9, 0xb8, 0xf0, 0x12, 0x09, 0x22, 0xb4, + 0x10, 0xb4, 0x14, 0xd9, 0xdc, 0x43, 0x03, 0x96, 0x87, 0x74, 0xc3, 0xee, 0xa3, 0xae, 0x6b, 0x1f, + 0xd8, 0xa8, 0x1b, 0x94, 0x20, 0xa5, 0x45, 0x45, 0xec, 0x55, 0x48, 0x79, 0x76, 0x1b, 0xb9, 0x9e, + 0xd9, 0xee, 0x04, 0xd9, 0x4d, 0x6a, 0xa1, 0x80, 0x06, 0xf9, 0x75, 0x02, 0x96, 0xef, 0x20, 0xb3, + 0x81, 0xba, 0x0b, 0x6b, 0x1e, 0xa3, 0x4a, 0xcc, 0x51, 0xf9, 0x5a, 0xd7, 0x6e, 0x3a, 0xa6, 0xd7, + 0xeb, 0x92, 0x32, 0xae, 0x6a, 0xa1, 0x80, 0xdd, 0x87, 0x35, 0x07, 0x1d, 0x19, 0x91, 0x83, 0x27, + 0x17, 0x1c, 0x7c, 0x63, 0x32, 0x2e, 0x5c, 0x24, 0x07, 0x8f, 0x5b, 0x09, 0xda, 0xaa, 0x83, 0x8e, + 0xaa, 0xb3, 0xf3, 0xcb, 0xb0, 0xee, 0x03, 0xa2, 0x39, 0x38, 0xeb, 0xe7, 0x20, 0xda, 0x10, 0x73, + 0x00, 0x41, 0xf3, 0x23, 0x29, 0x87, 0x02, 0x9a, 0x84, 0x5f, 0x12, 0xb0, 0xba, 0x6b, 0xbb, 0x75, + 0x74, 0x68, 0xf6, 0x6d, 0xdc, 0xeb, 0xb2, 0x5b, 0x90, 0x22, 0xcd, 0x67, 0xd8, 0x8d, 0x20, 0x17, + 0xa9, 0x52, 0x76, 0x32, 0x2e, 0x64, 0x68, 0x9b, 0x4d, 0x55, 0x82, 0xb6, 0x42, 0xd6, 0x95, 0x46, + 0x2c, 0x7b, 0x89, 0xb9, 0xec, 0x75, 0xe0, 0xfc, 0x2c, 0x1d, 0x06, 0x76, 0xa6, 0xad, 0xbe, 0x75, + 0x6a, 0xab, 0xd7, 0xa6, 0x56, 0x92, 0xd3, 0x28, 0x9b, 0x9e, 0x59, 0xca, 0x4d, 0xc6, 0x85, 0x2c, + 0x89, 0x22, 0xc6, 0x28, 0x68, 0xab, 0xb3, 0xfd, 0x9e, 0x33, 0xe7, 0xd1, 0x3b, 0xc2, 0x34, 0xe5, + 0xff, 0x95, 0x47, 0xef, 0x08, 0x47, 0x3d, 0xea, 0x47, 0x98, 0x66, 0xf2, 0x67, 0x06, 0x32, 0xf3, + 0x14, 0xf1, 0xf6, 0x60, 0xe6, 0xdb, 0xe3, 0x33, 0x48, 0x35, 0x4c, 0xcf, 0x34, 0xbc, 0x41, 0x87, + 0x64, 0x6e, 0x6d, 0xfb, 0xf5, 0x53, 0xc3, 0xf4, 0x79, 0xf5, 0x41, 0x07, 0x45, 0xcb, 0x32, 0x63, + 0x11, 0xb4, 0x95, 0x06, 0xd5, 0xb3, 0x2c, 0x24, 0xfd, 0x35, 0xed, 0xca, 0x60, 0x1d, 0x6f, 0xe6, + 0xe4, 0x8b, 0xbf, 0x8b, 0xaf, 0x18, 0xc8, 0xe9, 0x53, 0x19, 0x6a, 0xcc, 0xce, 0x14, 0x1c, 0xe8, + 0x03, 0x58, 0x0b, 0x73, 0x11, 0xd0, 0x07, 0xa7, 0x8a, 0xf6, 0x6e, 0x5c, 0x2f, 0x68, 0x61, 0x39, + 0xca, 0xc7, 0x42, 0x48, 0xbc, 0x38, 0x84, 0x3f, 0x18, 0x48, 0xf9, 0x7e, 0x4b, 0x03, 0x0f, 0xb9, + 0xff, 0xe2, 0xeb, 0x9c, 0x1b, 0x14, 0x67, 0x8e, 0x0f, 0x8a, 0x58, 0x09, 0x92, 0xff, 0x57, 0x09, + 0xce, 0x86, 0x25, 0xa0, 0x27, 0xfc, 0x89, 0x01, 0x20, 0xc3, 0x27, 0x48, 0xca, 0x0e, 0xa4, 0xe9, + 0x27, 0x7f, 0xea, 0x78, 0xbc, 0x34, 0x19, 0x17, 0xd8, 0xd8, 0x94, 0xa0, 0xf3, 0x91, 0x8c, 0x88, + 0x13, 0xe6, 0x43, 0xe2, 0x1f, 0xce, 0x87, 0x2f, 0x61, 0x3d, 0x72, 0x39, 0x06, 0xb1, 0xb2, 0x90, + 0xec, 0x98, 0xde, 0x21, 0x6d, 0xe7, 0x60, 0xcd, 0x56, 0x61, 0x95, 0x8e, 0x06, 0x72, 0xa1, 0x25, + 0x16, 0x1c, 0xe0, 0xf2, 0x64, 0x5c, 0xb8, 0x10, 0x1b, 0x27, 0xf4, 0xca, 0x4a, 0x5b, 0xa1, 0x27, + 0xea, 0xfe, 0x1b, 0x06, 0xd8, 0xf8, 0x45, 0x72, 0x62, 0x08, 0x0f, 0x8e, 0x5f, 0xab, 0x8b, 0xa2, + 0xf8, 0x1b, 0x77, 0x27, 0x8d, 0xa5, 0x0f, 0x17, 0xe4, 0xd9, 0x83, 0x64, 0x71, 0x2c, 0x0a, 0x40, + 0xf8, 0x76, 0xa1, 0x61, 0xbc, 0x1a, 0xb4, 0x95, 0xff, 0x78, 0x29, 0x46, 0xde, 0x35, 0xe4, 0x52, + 0xa7, 0x3b, 0xc5, 0x69, 0x68, 0x11, 0x43, 0xea, 0xb7, 0x01, 0x19, 0x99, 0x3c, 0x71, 0x16, 0x3b, + 0xbd, 0x09, 0xe7, 0xe8, 0x53, 0x88, 0x7a, 0xbc, 0x1a, 0xf1, 0x48, 0xdf, 0x48, 0xbe, 0x3b, 0xb2, + 0xd4, 0xa6, 0x60, 0xea, 0xe5, 0x2e, 0x64, 0xab, 0xa6, 0xf5, 0x08, 0x79, 0x32, 0x6e, 0xb7, 0x6d, + 0xaf, 0x8d, 0x1c, 0xef, 0x44, 0x4f, 0x79, 0xff, 0x78, 0x53, 0x54, 0xe0, 0x6c, 0x55, 0x8b, 0x48, + 0x84, 0x07, 0xb0, 0x41, 0xb8, 0x24, 0xeb, 0x91, 0x83, 0x8f, 0x5a, 0xa8, 0xd1, 0x44, 0x0b, 0x09, + 0x37, 0x61, 0xdd, 0x8c, 0x43, 0x29, 0xeb, 0xbc, 0x58, 0x28, 0x42, 0x8e, 0x50, 0x6b, 0xc8, 0x42, + 0x76, 0xc7, 0x93, 0xea, 0xae, 0x3f, 0x07, 0x4e, 0x62, 0x16, 0x0e, 0x21, 0xab, 0xa2, 0xc7, 0xde, + 0xf4, 0xf1, 0xa5, 0x21, 0xab, 0x7f, 0x62, 0x14, 0xef, 0xc1, 0x79, 0x07, 0x3d, 0xf6, 0xfc, 0xa7, + 0x9b, 0xd1, 0x45, 0x56, 0x9f, 0xbe, 0xed, 0x22, 0xd7, 0x40, 0x4c, 0x2d, 0x68, 0x69, 0x87, 0x50, + 0xfb, 0xac, 0x6f, 0x7c, 0x9b, 0x84, 0x95, 0xe9, 0x60, 0x60, 0xdf, 0x85, 0x57, 0xca, 0x92, 0x2e, + 0x19, 0xfa, 0x83, 0xaa, 0x62, 0xec, 0xab, 0x15, 0xb5, 0xa2, 0x57, 0xa4, 0x9d, 0xca, 0x43, 0xa5, + 0x6c, 0xec, 0xab, 0xb5, 0xaa, 0x22, 0x57, 0x3e, 0xac, 0x28, 0xe5, 0xcc, 0x12, 0xb7, 0x3e, 0x1c, + 0xf1, 0xe9, 0x88, 0x88, 0xbd, 0x06, 0x97, 0x42, 0x4b, 0x79, 0xa7, 0xa2, 0xa8, 0xba, 0x51, 0xd3, + 0x25, 0x5d, 0xc9, 0x30, 0x1c, 0x0c, 0x47, 0xfc, 0x32, 0x91, 0xb1, 0x6f, 0xc2, 0x46, 0x04, 0xb7, + 0xa7, 0xd6, 0x14, 0xb5, 0xb6, 0x5f, 0xa3, 0xd0, 0x04, 0x77, 0x7e, 0x38, 0xe2, 0x53, 0x33, 0x31, + 0x5b, 0x04, 0x2e, 0x86, 0x56, 0x15, 0x59, 0xaf, 0xec, 0xa9, 0x14, 0x7e, 0x86, 0x5b, 0x1b, 0x8e, + 0x78, 0x08, 0xe5, 0xec, 0x26, 0x5c, 0x8e, 0xe0, 0xef, 0x48, 0xaa, 0xaa, 0xec, 0x50, 0x70, 0x92, + 0x4b, 0x0f, 0x47, 0xfc, 0x39, 0x2a, 0x64, 0xdf, 0x81, 0x2b, 0x21, 0xb2, 0x2a, 0xc9, 0xf7, 0x14, + 0xdd, 0x90, 0xf7, 0x76, 0x77, 0x2b, 0xfa, 0xae, 0xa2, 0xea, 0x99, 0xb3, 0x5c, 0x76, 0x38, 0xe2, + 0x33, 0x44, 0x11, 0xca, 0xd9, 0xf7, 0x81, 0x3f, 0x66, 0x26, 0xc9, 0xf7, 0xd4, 0xbd, 0x4f, 0x77, + 0x94, 0xf2, 0x47, 0x4a, 0x60, 0xbb, 0xcc, 0x6d, 0x0c, 0x47, 0xfc, 0x45, 0xa2, 0x9d, 0x53, 0xb2, + 0xb7, 0x5f, 0x40, 0xa0, 0x29, 0xb2, 0x52, 0xa9, 0xea, 0x86, 0x54, 0xaa, 0x29, 0xaa, 0xac, 0x64, + 0xce, 0x71, 0xb9, 0xe1, 0x88, 0xcf, 0x12, 0x2d, 0x55, 0x52, 0x1d, 0x7b, 0x13, 0xae, 0x86, 0xf6, + 0xaa, 0x72, 0x5f, 0x37, 0x6a, 0xca, 0xc7, 0xfb, 0xbe, 0xca, 0xa7, 0xf9, 0x24, 0xb3, 0x42, 0x02, + 0xf7, 0x35, 0x53, 0x85, 0x2f, 0x67, 0x79, 0xc8, 0x84, 0x76, 0x77, 0x14, 0xa9, 0xac, 0x68, 0x99, + 0x14, 0xa9, 0x0c, 0xd9, 0x71, 0xc9, 0x27, 0x3f, 0xe6, 0x97, 0x4a, 0xf7, 0x7f, 0x7d, 0x96, 0x67, + 0x9e, 0x3e, 0xcb, 0x33, 0x7f, 0x3e, 0xcb, 0x33, 0xdf, 0x3d, 0xcf, 0x2f, 0x3d, 0x7d, 0x9e, 0x5f, + 0xfa, 0xfd, 0x79, 0x7e, 0xe9, 0xe1, 0xed, 0xa6, 0xed, 0x1d, 0xf6, 0xea, 0x45, 0x0b, 0xb7, 0x45, + 0x0b, 0xbb, 0x6d, 0xec, 0x8a, 0x76, 0xdd, 0xba, 0xde, 0xc4, 0x62, 0xff, 0x6d, 0xb1, 0x8d, 0x1b, + 0xbd, 0x16, 0x72, 0xc9, 0x4f, 0xce, 0x8d, 0xed, 0xeb, 0x64, 0x24, 0x8a, 0x2d, 0xd4, 0x34, 0xad, + 0x81, 0xd8, 0xdf, 0xba, 0x71, 0xa3, 0xbe, 0x1c, 0xcc, 0xb1, 0xb7, 0xfe, 0x0a, 0x00, 0x00, 0xff, + 0xff, 0x66, 0x80, 0x87, 0xc6, 0x8a, 0x0d, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { diff --git a/modules/core/02-client/legacy/v100/store.go b/modules/core/02-client/legacy/v100/store.go index f92aa224676..70827a89b6a 100644 --- a/modules/core/02-client/legacy/v100/store.go +++ b/modules/core/02-client/legacy/v100/store.go @@ -10,12 +10,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - smtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + smtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) // MigrateStore performs in-place store migrations from SDK v0.40 of the IBC module to v1.0.0 of ibc-go. diff --git a/modules/core/02-client/legacy/v100/store_test.go b/modules/core/02-client/legacy/v100/store_test.go index a1c1be3034a..cb51908f05f 100644 --- a/modules/core/02-client/legacy/v100/store_test.go +++ b/modules/core/02-client/legacy/v100/store_test.go @@ -6,12 +6,12 @@ import ( "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/legacy/v100" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + v100 "github.com/cosmos/ibc-go/v4/modules/core/02-client/legacy/v100" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type LegacyTestSuite struct { diff --git a/modules/core/02-client/module.go b/modules/core/02-client/module.go index c15bef6bf97..6cef3aac5c0 100644 --- a/modules/core/02-client/module.go +++ b/modules/core/02-client/module.go @@ -4,8 +4,8 @@ import ( "github.com/gogo/protobuf/grpc" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/client/cli" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/client/cli" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ) // Name returns the IBC client name diff --git a/modules/core/02-client/proposal_handler.go b/modules/core/02-client/proposal_handler.go index d1b15ce2dad..fbbdf311b7f 100644 --- a/modules/core/02-client/proposal_handler.go +++ b/modules/core/02-client/proposal_handler.go @@ -5,8 +5,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/keeper" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/keeper" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ) // NewClientProposalHandler defines the 02-client proposal handler diff --git a/modules/core/02-client/proposal_handler_test.go b/modules/core/02-client/proposal_handler_test.go index b83455b39c2..d86794b7534 100644 --- a/modules/core/02-client/proposal_handler_test.go +++ b/modules/core/02-client/proposal_handler_test.go @@ -5,10 +5,10 @@ import ( distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - client "github.com/cosmos/ibc-go/v3/modules/core/02-client" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + client "github.com/cosmos/ibc-go/v4/modules/core/02-client" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *ClientTestSuite) TestNewClientUpdateProposalHandler() { diff --git a/modules/core/02-client/simulation/decoder.go b/modules/core/02-client/simulation/decoder.go index 8aa19dd7c9c..9334d1ca01a 100644 --- a/modules/core/02-client/simulation/decoder.go +++ b/modules/core/02-client/simulation/decoder.go @@ -6,9 +6,9 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/keeper" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/keeper" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ ClientUnmarshaler = (*keeper.Keeper)(nil) diff --git a/modules/core/02-client/simulation/decoder_test.go b/modules/core/02-client/simulation/decoder_test.go index 0e106614f64..fcd6e847475 100644 --- a/modules/core/02-client/simulation/decoder_test.go +++ b/modules/core/02-client/simulation/decoder_test.go @@ -8,11 +8,11 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/simulation" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/simulation" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) func TestDecodeStore(t *testing.T) { diff --git a/modules/core/02-client/simulation/genesis.go b/modules/core/02-client/simulation/genesis.go index ddf592dfad2..f4c6082628a 100644 --- a/modules/core/02-client/simulation/genesis.go +++ b/modules/core/02-client/simulation/genesis.go @@ -5,7 +5,7 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ) // GenClientGenesis returns the default client genesis state. diff --git a/modules/core/02-client/types/client.go b/modules/core/02-client/types/client.go index bb3d5c4f3d3..a09a910e815 100644 --- a/modules/core/02-client/types/client.go +++ b/modules/core/02-client/types/client.go @@ -10,8 +10,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" proto "github.com/gogo/protobuf/proto" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( diff --git a/modules/core/02-client/types/client.pb.go b/modules/core/02-client/types/client.pb.go index 34eb54cc90f..cf3d0fd93a9 100644 --- a/modules/core/02-client/types/client.pb.go +++ b/modules/core/02-client/types/client.pb.go @@ -400,48 +400,48 @@ var fileDescriptor_b6bc4c8185546947 = []byte{ // 705 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x3f, 0x6f, 0xd3, 0x4e, 0x18, 0x8e, 0xdb, 0xfc, 0xa2, 0xe6, 0x52, 0x35, 0xfd, 0xb9, 0x29, 0x0d, 0xa1, 0xca, 0x45, 0x27, - 0x86, 0x0c, 0xd4, 0x26, 0xa9, 0x84, 0xaa, 0x6c, 0x24, 0x4b, 0x3b, 0x80, 0x82, 0x51, 0x85, 0x60, - 0x89, 0xfc, 0xe7, 0xea, 0x5c, 0xe5, 0xf8, 0x22, 0xdf, 0x39, 0x90, 0x6f, 0xc0, 0xc8, 0xc8, 0xc0, - 0xd0, 0x6f, 0xc0, 0x97, 0x60, 0xe8, 0xd8, 0x91, 0xc9, 0x42, 0xed, 0xc2, 0x4a, 0x56, 0x16, 0x94, - 0xbb, 0x73, 0x1b, 0xf7, 0x0f, 0x42, 0xb0, 0xdd, 0x3d, 0xf7, 0xdc, 0x73, 0xcf, 0xf3, 0xda, 0xef, - 0x0b, 0x20, 0x71, 0x5c, 0xd3, 0xa5, 0x11, 0x36, 0xdd, 0x80, 0xe0, 0x90, 0x9b, 0x93, 0x96, 0x5a, - 0x19, 0xe3, 0x88, 0x72, 0xaa, 0xeb, 0xc4, 0x71, 0x8d, 0x39, 0xc1, 0x50, 0xf0, 0xa4, 0x55, 0xab, - 0xf8, 0xd4, 0xa7, 0xe2, 0xd8, 0x9c, 0xaf, 0x24, 0xb3, 0x76, 0xdf, 0xa7, 0xd4, 0x0f, 0xb0, 0x29, - 0x76, 0x4e, 0x7c, 0x64, 0xda, 0xe1, 0x54, 0x1d, 0x3d, 0x74, 0x29, 0x1b, 0x51, 0x66, 0xc6, 0x63, - 0x3f, 0xb2, 0x3d, 0x6c, 0x4e, 0x5a, 0x0e, 0xe6, 0x76, 0x2b, 0xdd, 0x4b, 0x16, 0xfa, 0xa4, 0x81, - 0xcd, 0x03, 0x0f, 0x87, 0x9c, 0x1c, 0x11, 0xec, 0xf5, 0xc4, 0x73, 0x2f, 0xb9, 0xcd, 0xb1, 0xde, - 0x02, 0x45, 0xf9, 0xfa, 0x80, 0x78, 0x55, 0xad, 0xa1, 0x35, 0x8b, 0xdd, 0xca, 0x2c, 0x81, 0xeb, - 0x53, 0x7b, 0x14, 0x74, 0xd0, 0xe5, 0x11, 0xb2, 0x56, 0xe4, 0xfa, 0xc0, 0xd3, 0xfb, 0x60, 0x55, - 0xe1, 0x6c, 0x2e, 0x51, 0x5d, 0x6a, 0x68, 0xcd, 0x52, 0xbb, 0x62, 0x48, 0x93, 0x46, 0x6a, 0xd2, - 0x78, 0x1a, 0x4e, 0xbb, 0x5b, 0xb3, 0x04, 0x6e, 0x64, 0xb4, 0xc4, 0x1d, 0x64, 0x95, 0xdc, 0x2b, - 0x13, 0xe8, 0xb3, 0x06, 0xaa, 0x3d, 0x1a, 0x32, 0x1c, 0xb2, 0x98, 0x09, 0xe8, 0x15, 0xe1, 0xc3, - 0x7d, 0x4c, 0xfc, 0x21, 0xd7, 0xf7, 0x40, 0x61, 0x28, 0x56, 0xc2, 0x5e, 0xa9, 0x5d, 0x33, 0x6e, - 0xd6, 0xcd, 0x90, 0xdc, 0x6e, 0xfe, 0x34, 0x81, 0x39, 0x4b, 0xf1, 0xf5, 0xd7, 0xa0, 0xec, 0xa6, - 0xaa, 0x7f, 0xe0, 0xb5, 0x36, 0x4b, 0xe0, 0x3d, 0xe5, 0x35, 0x7b, 0x0d, 0x59, 0x6b, 0x6e, 0xc6, - 0x1e, 0xfa, 0xa2, 0x81, 0x4d, 0x59, 0xc6, 0xac, 0x6f, 0xf6, 0x37, 0x05, 0x7d, 0x07, 0xd6, 0xaf, - 0x3d, 0xc8, 0xaa, 0x4b, 0x8d, 0xe5, 0x66, 0xa9, 0xfd, 0xe8, 0xb6, 0xac, 0x77, 0x55, 0xaa, 0x0b, - 0xe7, 0xe9, 0x67, 0x09, 0xdc, 0xba, 0x35, 0x04, 0x43, 0x56, 0x39, 0x9b, 0x82, 0xa1, 0x1f, 0x1a, - 0xa8, 0xc8, 0x18, 0x87, 0x63, 0xcf, 0xe6, 0xb8, 0x1f, 0xd1, 0x31, 0x65, 0x76, 0xa0, 0x57, 0xc0, - 0x7f, 0x9c, 0xf0, 0x00, 0xcb, 0x04, 0x96, 0xdc, 0xe8, 0x0d, 0x50, 0xf2, 0x30, 0x73, 0x23, 0x32, - 0xe6, 0x84, 0x86, 0xa2, 0x98, 0x45, 0x6b, 0x11, 0xd2, 0xf7, 0xc1, 0xff, 0x2c, 0x76, 0x8e, 0xb1, - 0xcb, 0x07, 0x57, 0x55, 0x58, 0x16, 0x55, 0xd8, 0x9e, 0x25, 0xb0, 0x2a, 0x9d, 0xdd, 0xa0, 0x20, - 0xab, 0xac, 0xb0, 0x5e, 0x5a, 0x94, 0x17, 0xa0, 0xc2, 0x62, 0x87, 0x71, 0xc2, 0x63, 0x8e, 0x17, - 0xc4, 0xf2, 0x42, 0x0c, 0xce, 0x12, 0xf8, 0xe0, 0x52, 0xec, 0x06, 0x0b, 0x59, 0xfa, 0x15, 0x9c, - 0x4a, 0x76, 0xf2, 0xef, 0x4f, 0x60, 0x0e, 0xfd, 0xd4, 0x40, 0xf9, 0x50, 0x76, 0xc7, 0x3f, 0xc7, - 0x7d, 0x02, 0xf2, 0xe3, 0xc0, 0x0e, 0x45, 0xc2, 0x52, 0x7b, 0xdb, 0x90, 0xcd, 0x68, 0xa4, 0xcd, - 0xa7, 0x9a, 0xd1, 0xe8, 0x07, 0x76, 0xa8, 0xfe, 0x4d, 0xc1, 0xd7, 0x8f, 0xc1, 0xa6, 0xe2, 0x78, - 0x83, 0x4c, 0x2f, 0xe5, 0x7f, 0xf3, 0x7f, 0x36, 0x66, 0x09, 0xdc, 0x96, 0x99, 0x6f, 0xbd, 0x8c, - 0xac, 0x8d, 0x14, 0x5f, 0xe8, 0xf0, 0xce, 0xea, 0x3c, 0xf5, 0xc7, 0x13, 0x98, 0xfb, 0x7e, 0x02, - 0xb5, 0xf9, 0x24, 0x28, 0xa8, 0xc6, 0xea, 0x81, 0x72, 0x84, 0x27, 0x84, 0x11, 0x1a, 0x0e, 0xc2, - 0x78, 0xe4, 0xe0, 0x48, 0xc4, 0xcf, 0x2f, 0x36, 0xc2, 0x35, 0x02, 0xb2, 0xd6, 0x52, 0xe4, 0xb9, - 0x00, 0x32, 0x22, 0xaa, 0x4d, 0x97, 0xee, 0x14, 0x91, 0x84, 0x05, 0x11, 0xe9, 0xa4, 0xb3, 0x92, - 0x5a, 0x44, 0xcf, 0x40, 0xa1, 0x6f, 0x47, 0xf6, 0x88, 0xcd, 0x85, 0xed, 0x20, 0xa0, 0x6f, 0x2f, - 0x43, 0xb2, 0xaa, 0xd6, 0x58, 0x6e, 0x16, 0x17, 0x85, 0xaf, 0x11, 0x90, 0xb5, 0xa6, 0x10, 0x99, - 0x9f, 0x75, 0xad, 0xd3, 0xf3, 0xba, 0x76, 0x76, 0x5e, 0xd7, 0xbe, 0x9d, 0xd7, 0xb5, 0x0f, 0x17, - 0xf5, 0xdc, 0xd9, 0x45, 0x3d, 0xf7, 0xf5, 0xa2, 0x9e, 0x7b, 0xb3, 0xe7, 0x13, 0x3e, 0x8c, 0x1d, - 0xc3, 0xa5, 0x23, 0x53, 0x8d, 0x50, 0xe2, 0xb8, 0x3b, 0x3e, 0x35, 0x27, 0xbb, 0xe6, 0x88, 0x7a, - 0x71, 0x80, 0x99, 0x9c, 0xde, 0x8f, 0xdb, 0x3b, 0x6a, 0x80, 0xf3, 0xe9, 0x18, 0x33, 0xa7, 0x20, - 0x3e, 0xca, 0xee, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb6, 0x6f, 0x16, 0x77, 0xe0, 0x05, 0x00, + 0x86, 0x0c, 0xd4, 0x26, 0x01, 0xa1, 0x2a, 0x1b, 0xc9, 0xd2, 0x0e, 0xa0, 0x60, 0x54, 0x21, 0x58, + 0x22, 0xff, 0xb9, 0x3a, 0x57, 0x39, 0xbe, 0xc8, 0x77, 0x0e, 0xe4, 0x1b, 0x30, 0x32, 0x32, 0x30, + 0xf4, 0x1b, 0xf0, 0x25, 0x18, 0x3a, 0x76, 0x64, 0xb2, 0x50, 0xbb, 0xb0, 0x92, 0x95, 0x05, 0xe5, + 0xee, 0xdc, 0xc6, 0xfd, 0x83, 0x10, 0x6c, 0x77, 0xcf, 0x3d, 0xf7, 0xdc, 0xf3, 0xbc, 0xf6, 0xfb, + 0x02, 0x48, 0x1c, 0xd7, 0x74, 0x69, 0x84, 0x4d, 0x37, 0x20, 0x38, 0xe4, 0xe6, 0xa4, 0xa5, 0x56, + 0xc6, 0x38, 0xa2, 0x9c, 0xea, 0x3a, 0x71, 0x5c, 0x63, 0x4e, 0x30, 0x14, 0x3c, 0x69, 0xd5, 0x2a, + 0x3e, 0xf5, 0xa9, 0x38, 0x36, 0xe7, 0x2b, 0xc9, 0xac, 0xdd, 0xf5, 0x29, 0xf5, 0x03, 0x6c, 0x8a, + 0x9d, 0x13, 0x1f, 0x9a, 0x76, 0x38, 0x55, 0x47, 0xf7, 0x5d, 0xca, 0x46, 0x94, 0x99, 0xf1, 0xd8, + 0x8f, 0x6c, 0x0f, 0x9b, 0x93, 0x96, 0x83, 0xb9, 0xdd, 0x4a, 0xf7, 0x92, 0x85, 0x3e, 0x69, 0x60, + 0x73, 0xdf, 0xc3, 0x21, 0x27, 0x87, 0x04, 0x7b, 0x3d, 0xf1, 0xdc, 0x4b, 0x6e, 0x73, 0xac, 0xb7, + 0x40, 0x51, 0xbe, 0x3e, 0x20, 0x5e, 0x55, 0x6b, 0x68, 0xcd, 0x62, 0xb7, 0x32, 0x4b, 0xe0, 0xfa, + 0xd4, 0x1e, 0x05, 0x1d, 0x74, 0x71, 0x84, 0xac, 0x15, 0xb9, 0xde, 0xf7, 0xf4, 0x3e, 0x58, 0x55, + 0x38, 0x9b, 0x4b, 0x54, 0x97, 0x1a, 0x5a, 0xb3, 0xd4, 0xae, 0x18, 0xd2, 0xa4, 0x91, 0x9a, 0x34, + 0x9e, 0x86, 0xd3, 0xee, 0xd6, 0x2c, 0x81, 0x1b, 0x19, 0x2d, 0x71, 0x07, 0x59, 0x25, 0xf7, 0xd2, + 0x04, 0xfa, 0xac, 0x81, 0x6a, 0x8f, 0x86, 0x0c, 0x87, 0x2c, 0x66, 0x02, 0x7a, 0x45, 0xf8, 0x70, + 0x0f, 0x13, 0x7f, 0xc8, 0xf5, 0x5d, 0x50, 0x18, 0x8a, 0x95, 0xb0, 0x57, 0x6a, 0xd7, 0x8c, 0xeb, + 0x75, 0x33, 0x24, 0xb7, 0x9b, 0x3f, 0x49, 0x60, 0xce, 0x52, 0x7c, 0xfd, 0x35, 0x28, 0xbb, 0xa9, + 0xea, 0x1f, 0x78, 0xad, 0xcd, 0x12, 0x78, 0x47, 0x79, 0xcd, 0x5e, 0x43, 0xd6, 0x9a, 0x9b, 0xb1, + 0x87, 0xbe, 0x68, 0x60, 0x53, 0x96, 0x31, 0xeb, 0x9b, 0xfd, 0x4d, 0x41, 0xdf, 0x81, 0xf5, 0x2b, + 0x0f, 0xb2, 0xea, 0x52, 0x63, 0xb9, 0x59, 0x6a, 0x3f, 0xb8, 0x29, 0xeb, 0x6d, 0x95, 0xea, 0xc2, + 0x79, 0xfa, 0x59, 0x02, 0xb7, 0x6e, 0x0c, 0xc1, 0x90, 0x55, 0xce, 0xa6, 0x60, 0xe8, 0x87, 0x06, + 0x2a, 0x32, 0xc6, 0xc1, 0xd8, 0xb3, 0x39, 0xee, 0x47, 0x74, 0x4c, 0x99, 0x1d, 0xe8, 0x15, 0xf0, + 0x1f, 0x27, 0x3c, 0xc0, 0x32, 0x81, 0x25, 0x37, 0x7a, 0x03, 0x94, 0x3c, 0xcc, 0xdc, 0x88, 0x8c, + 0x39, 0xa1, 0xa1, 0x28, 0x66, 0xd1, 0x5a, 0x84, 0xf4, 0x3d, 0xf0, 0x3f, 0x8b, 0x9d, 0x23, 0xec, + 0xf2, 0xc1, 0x65, 0x15, 0x96, 0x45, 0x15, 0xb6, 0x67, 0x09, 0xac, 0x4a, 0x67, 0xd7, 0x28, 0xc8, + 0x2a, 0x2b, 0xac, 0x97, 0x16, 0xe5, 0x05, 0xa8, 0xb0, 0xd8, 0x61, 0x9c, 0xf0, 0x98, 0xe3, 0x05, + 0xb1, 0xbc, 0x10, 0x83, 0xb3, 0x04, 0xde, 0xbb, 0x10, 0xbb, 0xc6, 0x42, 0x96, 0x7e, 0x09, 0xa7, + 0x92, 0x9d, 0xfc, 0xfb, 0x63, 0x98, 0x43, 0x3f, 0x35, 0x50, 0x3e, 0x90, 0xdd, 0xf1, 0xcf, 0x71, + 0x9f, 0x80, 0xfc, 0x38, 0xb0, 0x43, 0x91, 0xb0, 0xd4, 0xde, 0x36, 0x64, 0x33, 0x1a, 0x69, 0xf3, + 0xa9, 0x66, 0x34, 0xfa, 0x81, 0x1d, 0xaa, 0x7f, 0x53, 0xf0, 0xf5, 0x23, 0xb0, 0xa9, 0x38, 0xde, + 0x20, 0xd3, 0x4b, 0xf9, 0xdf, 0xfc, 0x9f, 0x8d, 0x59, 0x02, 0xb7, 0x65, 0xe6, 0x1b, 0x2f, 0x23, + 0x6b, 0x23, 0xc5, 0x17, 0x3a, 0xbc, 0xb3, 0x3a, 0x4f, 0xfd, 0xf1, 0x18, 0xe6, 0xbe, 0x1f, 0x43, + 0x6d, 0x3e, 0x09, 0x0a, 0xaa, 0xb1, 0x7a, 0xa0, 0x1c, 0xe1, 0x09, 0x61, 0x84, 0x86, 0x83, 0x30, + 0x1e, 0x39, 0x38, 0x12, 0xf1, 0xf3, 0x8b, 0x8d, 0x70, 0x85, 0x80, 0xac, 0xb5, 0x14, 0x79, 0x2e, + 0x80, 0x8c, 0x88, 0x6a, 0xd3, 0xa5, 0x5b, 0x45, 0x24, 0x61, 0x41, 0x44, 0x3a, 0xe9, 0xac, 0xa4, + 0x16, 0xd1, 0x33, 0x50, 0xe8, 0xdb, 0x91, 0x3d, 0x62, 0x73, 0x61, 0x3b, 0x08, 0xe8, 0xdb, 0x8b, + 0x90, 0xac, 0xaa, 0x35, 0x96, 0x9b, 0xc5, 0x45, 0xe1, 0x2b, 0x04, 0x64, 0xad, 0x29, 0x44, 0xe6, + 0x67, 0x5d, 0xeb, 0xe4, 0xac, 0xae, 0x9d, 0x9e, 0xd5, 0xb5, 0x6f, 0x67, 0x75, 0xed, 0xc3, 0x79, + 0x3d, 0x77, 0x7a, 0x5e, 0xcf, 0x7d, 0x3d, 0xaf, 0xe7, 0xde, 0xec, 0xfa, 0x84, 0x0f, 0x63, 0xc7, + 0x70, 0xe9, 0xc8, 0x54, 0x23, 0x94, 0x38, 0xee, 0x8e, 0x4f, 0xcd, 0xc9, 0x63, 0x73, 0x44, 0xbd, + 0x38, 0xc0, 0x4c, 0x4e, 0xef, 0x87, 0xed, 0x1d, 0x35, 0xc0, 0xf9, 0x74, 0x8c, 0x99, 0x53, 0x10, + 0x1f, 0xe5, 0xd1, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9a, 0x92, 0x4e, 0x61, 0xe0, 0x05, 0x00, 0x00, } diff --git a/modules/core/02-client/types/client_test.go b/modules/core/02-client/types/client_test.go index cefe567619c..dfc52f2190b 100644 --- a/modules/core/02-client/types/client_test.go +++ b/modules/core/02-client/types/client_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *TypesTestSuite) TestMarshalConsensusStateWithHeight() { diff --git a/modules/core/02-client/types/codec.go b/modules/core/02-client/types/codec.go index 0497fa15f37..0aec6bc1d7c 100644 --- a/modules/core/02-client/types/codec.go +++ b/modules/core/02-client/types/codec.go @@ -8,7 +8,7 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" proto "github.com/gogo/protobuf/proto" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // RegisterInterfaces registers the client interfaces to protobuf Any. diff --git a/modules/core/02-client/types/codec_test.go b/modules/core/02-client/types/codec_test.go index bb706d87fd1..da970cd181a 100644 --- a/modules/core/02-client/types/codec_test.go +++ b/modules/core/02-client/types/codec_test.go @@ -3,12 +3,12 @@ package types_test import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + localhosttypes "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type caseAny struct { diff --git a/modules/core/02-client/types/encoding.go b/modules/core/02-client/types/encoding.go index 5693ba41e2a..26a6bf32626 100644 --- a/modules/core/02-client/types/encoding.go +++ b/modules/core/02-client/types/encoding.go @@ -5,7 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // MustUnmarshalClientState attempts to decode and return an ClientState object from diff --git a/modules/core/02-client/types/encoding_test.go b/modules/core/02-client/types/encoding_test.go index 75ee99e6c85..298285a828f 100644 --- a/modules/core/02-client/types/encoding_test.go +++ b/modules/core/02-client/types/encoding_test.go @@ -1,8 +1,8 @@ package types_test import ( - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) func (suite *TypesTestSuite) TestMarshalHeader() { diff --git a/modules/core/02-client/types/events.go b/modules/core/02-client/types/events.go index 93aa27afa0b..d23f6d24e02 100644 --- a/modules/core/02-client/types/events.go +++ b/modules/core/02-client/types/events.go @@ -3,7 +3,7 @@ package types import ( "fmt" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // IBC client events diff --git a/modules/core/02-client/types/genesis.go b/modules/core/02-client/types/genesis.go index ccf797e0d49..4dd61fdc7a2 100644 --- a/modules/core/02-client/types/genesis.go +++ b/modules/core/02-client/types/genesis.go @@ -6,8 +6,8 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( diff --git a/modules/core/02-client/types/genesis.pb.go b/modules/core/02-client/types/genesis.pb.go index 9f85bc06008..4edc4f302b8 100644 --- a/modules/core/02-client/types/genesis.pb.go +++ b/modules/core/02-client/types/genesis.pb.go @@ -221,38 +221,38 @@ var fileDescriptor_bcd0c0f1f2e6a91a = []byte{ // 539 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0x41, 0x6e, 0xd3, 0x40, 0x14, 0xcd, 0x34, 0x69, 0x68, 0xa7, 0x15, 0x0d, 0xa3, 0xa8, 0x98, 0x54, 0xb2, 0x2d, 0xb3, 0x09, - 0x8b, 0xd8, 0x24, 0xdd, 0x54, 0xd9, 0x20, 0xb9, 0x12, 0xa8, 0x12, 0x48, 0x60, 0x76, 0x6c, 0xac, - 0xc9, 0x78, 0x48, 0x47, 0xd8, 0x9e, 0x90, 0x99, 0x44, 0xe4, 0x06, 0x2c, 0x11, 0x27, 0x60, 0xcd, - 0x19, 0x38, 0x40, 0x97, 0x5d, 0x76, 0x15, 0x50, 0x72, 0x83, 0x9c, 0x00, 0x79, 0x66, 0x4c, 0xdb, - 0x34, 0x65, 0xf7, 0xf3, 0xfc, 0xde, 0xfb, 0x4f, 0xef, 0x67, 0xa0, 0xcb, 0x06, 0x24, 0x20, 0x7c, - 0x4c, 0x03, 0x92, 0x32, 0x9a, 0xcb, 0x60, 0xda, 0x0d, 0x86, 0x34, 0xa7, 0x82, 0x09, 0x7f, 0x34, - 0xe6, 0x92, 0x23, 0xc4, 0x06, 0xc4, 0x2f, 0x18, 0xbe, 0x66, 0xf8, 0xd3, 0x6e, 0xcb, 0xd9, 0xa0, - 0x32, 0x5f, 0x95, 0xa8, 0xd5, 0x1c, 0xf2, 0x21, 0x57, 0x63, 0x50, 0x4c, 0x1a, 0xf5, 0xae, 0x6a, - 0x70, 0xff, 0x95, 0x36, 0x7f, 0x2f, 0xb1, 0xa4, 0x88, 0xc0, 0x07, 0x5a, 0x26, 0x2c, 0xe0, 0x56, - 0xdb, 0x7b, 0xbd, 0x67, 0xfe, 0xdd, 0x6d, 0xfe, 0x59, 0x42, 0x73, 0xc9, 0x3e, 0x32, 0x9a, 0x9c, - 0x2a, 0x4c, 0x69, 0x43, 0xfb, 0x62, 0xee, 0x54, 0x7e, 0xfe, 0x76, 0x0e, 0x37, 0x7e, 0x16, 0x51, - 0xe9, 0x8c, 0xbe, 0x03, 0xf8, 0xc8, 0xcc, 0x31, 0xe1, 0xb9, 0xa0, 0xb9, 0x98, 0x08, 0x6b, 0xeb, - 0xfe, 0x7d, 0xda, 0xe6, 0xb4, 0xa4, 0x6a, 0xbf, 0xb0, 0x5f, 0xec, 0x5b, 0xcd, 0x1d, 0x6b, 0x86, - 0xb3, 0xb4, 0xef, 0xdd, 0x71, 0xf4, 0x8a, 0x2c, 0x5a, 0x2a, 0xd6, 0xb4, 0x51, 0x83, 0xac, 0xe1, - 0x68, 0x06, 0x4b, 0x2c, 0xce, 0xa8, 0xc4, 0x09, 0x96, 0xd8, 0xaa, 0xaa, 0x48, 0x9d, 0xff, 0x57, - 0x60, 0xfa, 0x7b, 0x63, 0x44, 0xa1, 0x63, 0x62, 0x3d, 0xbe, 0x1d, 0xab, 0x34, 0xf5, 0xa2, 0x03, - 0x03, 0x95, 0x0a, 0x74, 0x02, 0xeb, 0x23, 0x3c, 0xc6, 0x99, 0xb0, 0x6a, 0x2e, 0x68, 0xef, 0xf5, - 0x5a, 0x9b, 0x16, 0xbe, 0x55, 0x8c, 0xb0, 0x56, 0xb8, 0x47, 0x86, 0x8f, 0x5e, 0xc2, 0x06, 0x19, - 0x53, 0x2c, 0x69, 0x9c, 0x72, 0x82, 0xd3, 0x73, 0x2e, 0xa4, 0xb5, 0xed, 0x82, 0xf6, 0x4e, 0x78, - 0x74, 0x23, 0xc1, 0x1a, 0xa3, 0x48, 0xa0, 0xa0, 0xd7, 0x25, 0x82, 0xde, 0xc1, 0x66, 0x4e, 0xbf, - 0xc8, 0x58, 0xaf, 0x8b, 0x05, 0xfd, 0x3c, 0xa1, 0x39, 0xa1, 0x56, 0xdd, 0x05, 0xed, 0x5a, 0xe8, - 0xac, 0xe6, 0xce, 0x91, 0xf6, 0xda, 0xc4, 0xf2, 0x22, 0x54, 0xc0, 0xe6, 0xd6, 0x25, 0xf8, 0x02, - 0x1e, 0xac, 0x35, 0x83, 0x1a, 0xb0, 0xfa, 0x89, 0xce, 0x2c, 0xe0, 0x82, 0xf6, 0x7e, 0x54, 0x8c, - 0xa8, 0x09, 0xb7, 0xa7, 0x38, 0x9d, 0x50, 0x6b, 0x4b, 0x61, 0xfa, 0x47, 0xbf, 0xf6, 0xf5, 0x87, - 0x53, 0xf1, 0x7e, 0x01, 0xf8, 0xe4, 0xde, 0x96, 0x51, 0x17, 0xee, 0x9a, 0x18, 0x2c, 0x51, 0x8e, - 0xbb, 0x61, 0x73, 0x35, 0x77, 0x1a, 0x37, 0x4b, 0x8f, 0x59, 0xe2, 0x45, 0x3b, 0x7a, 0x3e, 0x4b, - 0x50, 0x0a, 0x4d, 0xf3, 0xd7, 0x07, 0xd6, 0xff, 0xb9, 0xa7, 0x9b, 0xfa, 0x5e, 0x3f, 0xab, 0x6d, - 0xce, 0x7a, 0x78, 0x6b, 0xc3, 0xf5, 0x55, 0x1f, 0x6a, 0xe4, 0x1f, 0x3f, 0xba, 0x58, 0xd8, 0xe0, - 0x72, 0x61, 0x83, 0x3f, 0x0b, 0x1b, 0x7c, 0x5b, 0xda, 0x95, 0xcb, 0xa5, 0x5d, 0xb9, 0x5a, 0xda, - 0x95, 0x0f, 0x27, 0x43, 0x26, 0xcf, 0x27, 0x03, 0x9f, 0xf0, 0x2c, 0x20, 0x5c, 0x64, 0x5c, 0x04, - 0x6c, 0x40, 0x3a, 0x43, 0x1e, 0x4c, 0x8f, 0x83, 0x8c, 0x27, 0x93, 0x94, 0x0a, 0xfd, 0x96, 0x9f, - 0xf7, 0x3a, 0xe6, 0x39, 0xcb, 0xd9, 0x88, 0x8a, 0x41, 0x5d, 0xbd, 0xda, 0xe3, 0xbf, 0x01, 0x00, - 0x00, 0xff, 0xff, 0x29, 0x4b, 0x29, 0xf0, 0x24, 0x04, 0x00, 0x00, + 0x8b, 0xd8, 0x24, 0xb0, 0xa8, 0xb2, 0x41, 0x72, 0x25, 0x50, 0x25, 0x90, 0xc0, 0xec, 0xd8, 0x58, + 0x93, 0xf1, 0x90, 0x8e, 0xb0, 0x3d, 0x21, 0x33, 0x89, 0xc8, 0x0d, 0x58, 0x22, 0x4e, 0xc0, 0x9a, + 0x33, 0x70, 0x80, 0x2e, 0xbb, 0xec, 0x2a, 0xa0, 0xe4, 0x06, 0x39, 0x01, 0xf2, 0xcc, 0x98, 0xb6, + 0x69, 0xca, 0xee, 0xe7, 0xf9, 0xbd, 0xf7, 0x9f, 0xde, 0xcf, 0x40, 0x97, 0x0d, 0x48, 0x40, 0xf8, + 0x98, 0x06, 0x24, 0x65, 0x34, 0x97, 0xc1, 0xb4, 0x1b, 0x0c, 0x69, 0x4e, 0x05, 0x13, 0xfe, 0x68, + 0xcc, 0x25, 0x47, 0x88, 0x0d, 0x88, 0x5f, 0x30, 0x7c, 0xcd, 0xf0, 0xa7, 0xdd, 0x96, 0xb3, 0x41, + 0x65, 0xbe, 0x2a, 0x51, 0xab, 0x39, 0xe4, 0x43, 0xae, 0xc6, 0xa0, 0x98, 0x34, 0xea, 0x5d, 0xd6, + 0xe0, 0xfe, 0x2b, 0x6d, 0xfe, 0x5e, 0x62, 0x49, 0x11, 0x81, 0xf7, 0xb4, 0x4c, 0x58, 0xc0, 0xad, + 0xb6, 0xf7, 0x7a, 0x4f, 0xfc, 0xdb, 0xdb, 0xfc, 0xd3, 0x84, 0xe6, 0x92, 0x7d, 0x64, 0x34, 0x39, + 0x51, 0x98, 0xd2, 0x86, 0xf6, 0xf9, 0xdc, 0xa9, 0xfc, 0xfc, 0xed, 0x1c, 0x6e, 0xfc, 0x2c, 0xa2, + 0xd2, 0x19, 0x7d, 0x07, 0xf0, 0x81, 0x99, 0x63, 0xc2, 0x73, 0x41, 0x73, 0x31, 0x11, 0xd6, 0xd6, + 0xdd, 0xfb, 0xb4, 0xcd, 0x49, 0x49, 0xd5, 0x7e, 0x61, 0xbf, 0xd8, 0xb7, 0x9a, 0x3b, 0xd6, 0x0c, + 0x67, 0x69, 0xdf, 0xbb, 0xe5, 0xe8, 0x15, 0x59, 0xb4, 0x54, 0xac, 0x69, 0xa3, 0x06, 0x59, 0xc3, + 0xd1, 0x0c, 0x96, 0x58, 0x9c, 0x51, 0x89, 0x13, 0x2c, 0xb1, 0x55, 0x55, 0x91, 0x3a, 0xff, 0xaf, + 0xc0, 0xf4, 0xf7, 0xc6, 0x88, 0x42, 0xc7, 0xc4, 0x7a, 0x78, 0x33, 0x56, 0x69, 0xea, 0x45, 0x07, + 0x06, 0x2a, 0x15, 0xe8, 0x18, 0xd6, 0x47, 0x78, 0x8c, 0x33, 0x61, 0xd5, 0x5c, 0xd0, 0xde, 0xeb, + 0xb5, 0x36, 0x2d, 0x7c, 0xab, 0x18, 0x61, 0xad, 0x70, 0x8f, 0x0c, 0x1f, 0xbd, 0x84, 0x0d, 0x32, + 0xa6, 0x58, 0xd2, 0x38, 0xe5, 0x04, 0xa7, 0x67, 0x5c, 0x48, 0x6b, 0xdb, 0x05, 0xed, 0x9d, 0xf0, + 0xe8, 0x5a, 0x82, 0x35, 0x46, 0x91, 0x40, 0x41, 0xaf, 0x4b, 0x04, 0xbd, 0x83, 0xcd, 0x9c, 0x7e, + 0x91, 0xb1, 0x5e, 0x17, 0x0b, 0xfa, 0x79, 0x42, 0x73, 0x42, 0xad, 0xba, 0x0b, 0xda, 0xb5, 0xd0, + 0x59, 0xcd, 0x9d, 0x23, 0xed, 0xb5, 0x89, 0xe5, 0x45, 0xa8, 0x80, 0xcd, 0xad, 0x4b, 0xf0, 0x05, + 0x3c, 0x58, 0x6b, 0x06, 0x35, 0x60, 0xf5, 0x13, 0x9d, 0x59, 0xc0, 0x05, 0xed, 0xfd, 0xa8, 0x18, + 0x51, 0x13, 0x6e, 0x4f, 0x71, 0x3a, 0xa1, 0xd6, 0x96, 0xc2, 0xf4, 0x8f, 0x7e, 0xed, 0xeb, 0x0f, + 0xa7, 0xe2, 0xfd, 0x02, 0xf0, 0xd1, 0x9d, 0x2d, 0xa3, 0x2e, 0xdc, 0x35, 0x31, 0x58, 0xa2, 0x1c, + 0x77, 0xc3, 0xe6, 0x6a, 0xee, 0x34, 0xae, 0x97, 0x1e, 0xb3, 0xc4, 0x8b, 0x76, 0xf4, 0x7c, 0x9a, + 0xa0, 0x14, 0x9a, 0xe6, 0xaf, 0x0e, 0xac, 0xff, 0x73, 0x8f, 0x37, 0xf5, 0xbd, 0x7e, 0x56, 0xdb, + 0x9c, 0xf5, 0xf0, 0xc6, 0x86, 0xab, 0xab, 0xde, 0xd7, 0xc8, 0x3f, 0x7e, 0x74, 0xbe, 0xb0, 0xc1, + 0xc5, 0xc2, 0x06, 0x7f, 0x16, 0x36, 0xf8, 0xb6, 0xb4, 0x2b, 0x17, 0x4b, 0xbb, 0x72, 0xb9, 0xb4, + 0x2b, 0x1f, 0x8e, 0x87, 0x4c, 0x9e, 0x4d, 0x06, 0x3e, 0xe1, 0x59, 0x40, 0xb8, 0xc8, 0xb8, 0x08, + 0xd8, 0x80, 0x74, 0x86, 0x3c, 0x98, 0x3e, 0x0f, 0x32, 0x9e, 0x4c, 0x52, 0x2a, 0xf4, 0x5b, 0x7e, + 0xda, 0xeb, 0x98, 0xe7, 0x2c, 0x67, 0x23, 0x2a, 0x06, 0x75, 0xf5, 0x6a, 0x9f, 0xfd, 0x0d, 0x00, + 0x00, 0xff, 0xff, 0x05, 0xb6, 0x71, 0xe6, 0x24, 0x04, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/modules/core/02-client/types/genesis_test.go b/modules/core/02-client/types/genesis_test.go index 6fc37070b31..c627d173327 100644 --- a/modules/core/02-client/types/genesis_test.go +++ b/modules/core/02-client/types/genesis_test.go @@ -5,14 +5,14 @@ import ( tmtypes "github.com/tendermint/tendermint/types" - client "github.com/cosmos/ibc-go/v3/modules/core/02-client" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibctestingmock "github.com/cosmos/ibc-go/v3/testing/mock" + client "github.com/cosmos/ibc-go/v4/modules/core/02-client" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + localhosttypes "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibctestingmock "github.com/cosmos/ibc-go/v4/testing/mock" ) const ( diff --git a/modules/core/02-client/types/height.go b/modules/core/02-client/types/height.go index 40125b23f2e..152c052cf1b 100644 --- a/modules/core/02-client/types/height.go +++ b/modules/core/02-client/types/height.go @@ -10,7 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.Height = (*Height)(nil) diff --git a/modules/core/02-client/types/height_test.go b/modules/core/02-client/types/height_test.go index 16415c3d61e..d7e2c3650d2 100644 --- a/modules/core/02-client/types/height_test.go +++ b/modules/core/02-client/types/height_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ) func TestZeroHeight(t *testing.T) { diff --git a/modules/core/02-client/types/keys.go b/modules/core/02-client/types/keys.go index 426747b0f6c..c90e3784a1b 100644 --- a/modules/core/02-client/types/keys.go +++ b/modules/core/02-client/types/keys.go @@ -8,7 +8,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) const ( diff --git a/modules/core/02-client/types/keys_test.go b/modules/core/02-client/types/keys_test.go index da722040e1c..2a042b82eae 100644 --- a/modules/core/02-client/types/keys_test.go +++ b/modules/core/02-client/types/keys_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ) // tests ParseClientIdentifier and IsValidClientID diff --git a/modules/core/02-client/types/msgs.go b/modules/core/02-client/types/msgs.go index e329a58ab49..58586887b51 100644 --- a/modules/core/02-client/types/msgs.go +++ b/modules/core/02-client/types/msgs.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // message types for the IBC client diff --git a/modules/core/02-client/types/msgs_test.go b/modules/core/02-client/types/msgs_test.go index ec0b87ac0bb..cf625f93bcc 100644 --- a/modules/core/02-client/types/msgs_test.go +++ b/modules/core/02-client/types/msgs_test.go @@ -7,12 +7,12 @@ import ( "github.com/golang/protobuf/proto" "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - solomachinetypes "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + solomachinetypes "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type TypesTestSuite struct { diff --git a/modules/core/02-client/types/params.go b/modules/core/02-client/types/params.go index 884fec2e5f4..ce4af7d0369 100644 --- a/modules/core/02-client/types/params.go +++ b/modules/core/02-client/types/params.go @@ -6,7 +6,7 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( diff --git a/modules/core/02-client/types/params_test.go b/modules/core/02-client/types/params_test.go index 87fed77622e..bcff83f1f46 100644 --- a/modules/core/02-client/types/params_test.go +++ b/modules/core/02-client/types/params_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) func TestValidateParams(t *testing.T) { diff --git a/modules/core/02-client/types/proposal.go b/modules/core/02-client/types/proposal.go index 75c9778e8c9..3040122a35f 100644 --- a/modules/core/02-client/types/proposal.go +++ b/modules/core/02-client/types/proposal.go @@ -8,7 +8,7 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) const ( diff --git a/modules/core/02-client/types/proposal_test.go b/modules/core/02-client/types/proposal_test.go index d1a6f52cf71..c722cc3c886 100644 --- a/modules/core/02-client/types/proposal_test.go +++ b/modules/core/02-client/types/proposal_test.go @@ -8,9 +8,9 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *TypesTestSuite) TestValidateBasic() { diff --git a/modules/core/02-client/types/query.go b/modules/core/02-client/types/query.go index ac9519b9298..81e80dc8793 100644 --- a/modules/core/02-client/types/query.go +++ b/modules/core/02-client/types/query.go @@ -3,7 +3,7 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( diff --git a/modules/core/02-client/types/query.pb.go b/modules/core/02-client/types/query.pb.go index bcb5ccd498e..9b733d70b51 100644 --- a/modules/core/02-client/types/query.pb.go +++ b/modules/core/02-client/types/query.pb.go @@ -984,73 +984,73 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/query.proto", fileDescriptor_dc42cdfd1d52d76e) } var fileDescriptor_dc42cdfd1d52d76e = []byte{ - // 1055 bytes of a gzipped FileDescriptorProto + // 1056 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x6f, 0x1b, 0x45, 0x14, 0xcf, 0xa4, 0x69, 0xd4, 0x3e, 0xbb, 0x09, 0x9a, 0xe6, 0xc3, 0xdd, 0x16, 0xc7, 0xd9, 0x20, - 0x9a, 0x96, 0x64, 0x27, 0x71, 0x68, 0x12, 0x21, 0x21, 0x41, 0x2a, 0x95, 0xf6, 0x52, 0xca, 0x22, - 0x04, 0x42, 0x42, 0xd1, 0xee, 0x7a, 0xb2, 0x59, 0xc9, 0xde, 0x71, 0x3d, 0xbb, 0x96, 0xa2, 0x2a, - 0x97, 0x9e, 0x10, 0x27, 0x24, 0x24, 0xae, 0x48, 0x1c, 0x39, 0x54, 0x1c, 0x90, 0xb8, 0x72, 0x82, - 0x1c, 0x38, 0x54, 0x82, 0x03, 0x27, 0x8a, 0x12, 0xfe, 0x10, 0xe4, 0x99, 0x59, 0x7b, 0xd7, 0x1e, - 0xd7, 0x6b, 0x14, 0xb8, 0xed, 0xbe, 0xcf, 0xdf, 0xfb, 0xbd, 0xe7, 0xf7, 0xd6, 0x50, 0x0e, 0x5c, - 0x8f, 0x78, 0xac, 0x45, 0x89, 0x57, 0x0f, 0x68, 0x18, 0x91, 0xf6, 0x26, 0x79, 0x1c, 0xd3, 0xd6, - 0x91, 0xd5, 0x6c, 0xb1, 0x88, 0x61, 0x1c, 0xb8, 0x9e, 0xd5, 0xd1, 0x5b, 0x52, 0x6f, 0xb5, 0x37, - 0x8d, 0xdb, 0x1e, 0xe3, 0x0d, 0xc6, 0x89, 0xeb, 0x70, 0x2a, 0x8d, 0x49, 0x7b, 0xd3, 0xa5, 0x91, - 0xb3, 0x49, 0x9a, 0x8e, 0x1f, 0x84, 0x4e, 0x14, 0xb0, 0x50, 0xfa, 0x1b, 0x4b, 0x9a, 0xf8, 0x2a, - 0x92, 0x34, 0xb8, 0xe6, 0x33, 0xe6, 0xd7, 0x29, 0x11, 0x6f, 0x6e, 0x7c, 0x40, 0x9c, 0x50, 0xe5, - 0x36, 0x6e, 0x28, 0x95, 0xd3, 0x0c, 0x88, 0x13, 0x86, 0x2c, 0x12, 0x81, 0xb9, 0xd2, 0xce, 0xf9, - 0xcc, 0x67, 0xe2, 0x91, 0x74, 0x9e, 0xa4, 0xd4, 0xdc, 0x86, 0xc5, 0x0f, 0x3a, 0x88, 0xee, 0x8a, - 0x1c, 0x1f, 0x46, 0x4e, 0x44, 0x6d, 0xfa, 0x38, 0xa6, 0x3c, 0xc2, 0xd7, 0xe1, 0xb2, 0xcc, 0xbc, - 0x1f, 0xd4, 0x4a, 0xa8, 0x82, 0x56, 0x2f, 0xdb, 0x97, 0xa4, 0xe0, 0x41, 0xcd, 0x7c, 0x86, 0xa0, - 0x34, 0xe8, 0xc8, 0x9b, 0x2c, 0xe4, 0x14, 0xef, 0x40, 0x51, 0x79, 0xf2, 0x8e, 0x5c, 0x38, 0x17, - 0xaa, 0x73, 0x96, 0xc4, 0x67, 0x25, 0xd0, 0xad, 0x77, 0xc3, 0x23, 0xbb, 0xe0, 0xf5, 0x02, 0xe0, - 0x39, 0xb8, 0xd8, 0x6c, 0x31, 0x76, 0x50, 0x9a, 0xac, 0xa0, 0xd5, 0xa2, 0x2d, 0x5f, 0xf0, 0x5d, - 0x28, 0x8a, 0x87, 0xfd, 0x43, 0x1a, 0xf8, 0x87, 0x51, 0xe9, 0x82, 0x08, 0x67, 0x58, 0x83, 0x54, - 0x5b, 0xf7, 0x85, 0xc5, 0xde, 0xd4, 0xc9, 0x9f, 0x4b, 0x13, 0x76, 0x41, 0x78, 0x49, 0x91, 0xe9, - 0x0e, 0xe2, 0xe5, 0x49, 0xa5, 0xf7, 0x00, 0x7a, 0x8d, 0x50, 0x68, 0x5f, 0xb7, 0x64, 0xd7, 0xac, - 0x4e, 0xd7, 0x2c, 0xd9, 0x62, 0xd5, 0x35, 0xeb, 0x91, 0xe3, 0x27, 0x2c, 0xd9, 0x29, 0x4f, 0xf3, - 0x77, 0x04, 0xd7, 0x34, 0x49, 0x14, 0x2b, 0x21, 0x5c, 0x49, 0xb3, 0xc2, 0x4b, 0xa8, 0x72, 0x61, - 0xb5, 0x50, 0xbd, 0xa5, 0xab, 0xe3, 0x41, 0x8d, 0x86, 0x51, 0x70, 0x10, 0xd0, 0x5a, 0x2a, 0xd4, - 0x5e, 0xb9, 0x53, 0xd6, 0x77, 0x2f, 0x96, 0x16, 0xb4, 0x6a, 0x6e, 0x17, 0x53, 0x5c, 0x72, 0xfc, - 0x5e, 0xa6, 0xaa, 0x49, 0x51, 0xd5, 0xcd, 0x91, 0x55, 0x49, 0xb0, 0x99, 0xb2, 0xbe, 0x47, 0x60, - 0xc8, 0xb2, 0x3a, 0xaa, 0x90, 0xc7, 0x3c, 0xf7, 0x9c, 0xe0, 0x9b, 0x30, 0xdb, 0xa2, 0xed, 0x80, - 0x07, 0x2c, 0xdc, 0x0f, 0xe3, 0x86, 0x4b, 0x5b, 0x02, 0xc9, 0x94, 0x3d, 0x93, 0x88, 0x1f, 0x0a, - 0x69, 0xc6, 0x30, 0xd5, 0xe7, 0x94, 0xa1, 0x6c, 0x24, 0x5e, 0x81, 0x2b, 0xf5, 0x4e, 0x7d, 0x51, - 0x62, 0x36, 0x55, 0x41, 0xab, 0x97, 0xec, 0xa2, 0x14, 0xaa, 0x6e, 0xff, 0x88, 0xe0, 0xba, 0x16, - 0xb2, 0xea, 0xc5, 0xdb, 0x30, 0xeb, 0x25, 0x9a, 0x1c, 0x43, 0x3a, 0xe3, 0x65, 0xc2, 0xfc, 0x97, - 0x73, 0xfa, 0x54, 0x8f, 0x9c, 0xe7, 0x62, 0xfb, 0x9e, 0xa6, 0xe5, 0xff, 0x66, 0x90, 0x7f, 0x46, - 0x70, 0x43, 0x0f, 0x42, 0xf1, 0xf7, 0x19, 0xbc, 0xd2, 0xc7, 0x5f, 0x32, 0xce, 0x6b, 0xba, 0x72, - 0xb3, 0x61, 0x3e, 0x0e, 0xa2, 0xc3, 0x0c, 0x01, 0xb3, 0x59, 0x7a, 0xcf, 0x71, 0x74, 0x3f, 0x47, - 0xb0, 0xac, 0x29, 0x44, 0x66, 0xff, 0x7f, 0x39, 0xfd, 0x05, 0x81, 0xf9, 0x32, 0x28, 0x8a, 0xd9, - 0x4f, 0x60, 0xb1, 0x8f, 0x59, 0x35, 0x4e, 0x09, 0xc1, 0xa3, 0xe7, 0x69, 0xde, 0xd3, 0x65, 0x38, - 0x3f, 0x52, 0x77, 0x06, 0x56, 0x69, 0x9c, 0x8b, 0x4a, 0x73, 0x6b, 0x60, 0x3d, 0xc6, 0xbd, 0xc2, - 0x17, 0x60, 0x9a, 0x0b, 0x89, 0x72, 0x53, 0x6f, 0xa6, 0x91, 0xc9, 0xf6, 0xc8, 0x69, 0x39, 0x8d, - 0x24, 0x9b, 0xf9, 0x7e, 0x26, 0x60, 0xa2, 0x53, 0x01, 0xab, 0x30, 0xdd, 0x14, 0x12, 0xf5, 0xd3, - 0xd6, 0x12, 0xa7, 0x7c, 0x94, 0xa5, 0xb9, 0x0c, 0x4b, 0x22, 0xe0, 0x47, 0x4d, 0xbf, 0xe5, 0xd4, - 0x32, 0xeb, 0x35, 0xc9, 0x59, 0x87, 0xca, 0x70, 0x13, 0x95, 0xfa, 0x3e, 0xcc, 0xc7, 0x4a, 0xbd, - 0x9f, 0xfb, 0x12, 0x5e, 0x8d, 0x07, 0x23, 0x9a, 0xaf, 0xa9, 0xa1, 0xe9, 0x66, 0xd3, 0xad, 0x60, - 0x33, 0x86, 0x95, 0x97, 0x5a, 0x29, 0x58, 0x0f, 0xa1, 0xd4, 0x83, 0x35, 0xc6, 0xfa, 0x5b, 0x88, - 0xb5, 0x71, 0xab, 0xbf, 0x16, 0xe1, 0xa2, 0xc8, 0x8b, 0xbf, 0x41, 0x50, 0x48, 0xc1, 0xc6, 0x6f, - 0xe8, 0xb8, 0x1e, 0xf2, 0xa1, 0x61, 0xac, 0xe5, 0x33, 0x96, 0x45, 0x98, 0x77, 0x9e, 0xfe, 0xf6, - 0xf7, 0x57, 0x93, 0x04, 0xaf, 0x93, 0xa1, 0x9f, 0x4a, 0x6a, 0x23, 0x91, 0x27, 0xdd, 0x51, 0x3c, - 0xc6, 0x5f, 0x23, 0x28, 0xa6, 0x8f, 0x25, 0xce, 0x95, 0x35, 0x99, 0x34, 0x63, 0x3d, 0xa7, 0xb5, - 0x02, 0x79, 0x4b, 0x80, 0x5c, 0xc1, 0xcb, 0x23, 0x41, 0xe2, 0x17, 0x08, 0x66, 0xb2, 0xbc, 0x62, - 0x6b, 0x78, 0x32, 0x5d, 0xfb, 0x0d, 0x92, 0xdb, 0x5e, 0xc1, 0xab, 0x0b, 0x78, 0x07, 0xb8, 0xa6, - 0x85, 0xd7, 0xb7, 0xd8, 0xd3, 0x34, 0x92, 0xe4, 0x18, 0x93, 0x27, 0x7d, 0x67, 0xfd, 0x98, 0xc8, - 0x35, 0x95, 0x52, 0x48, 0xc1, 0x31, 0x7e, 0x86, 0x60, 0xb6, 0xef, 0x90, 0xe0, 0xbc, 0x90, 0xbb, - 0x0d, 0xd8, 0xc8, 0xef, 0xa0, 0x8a, 0xdc, 0x15, 0x45, 0x56, 0xf1, 0xc6, 0xb8, 0x45, 0xe2, 0x13, - 0x04, 0xf3, 0xda, 0x2d, 0x8d, 0xef, 0xe4, 0x44, 0x91, 0x3d, 0x30, 0xc6, 0xf6, 0xb8, 0x6e, 0xaa, - 0x84, 0x77, 0x44, 0x09, 0x6f, 0xe1, 0xdd, 0xb1, 0xfb, 0xa4, 0x6e, 0x06, 0xfe, 0x36, 0x33, 0xf6, - 0x71, 0xbe, 0xb1, 0x8f, 0xc7, 0x1a, 0xfb, 0xde, 0x0e, 0xcf, 0xfd, 0xdb, 0x8c, 0xb3, 0x7c, 0x7f, - 0xd1, 0x05, 0x29, 0xd7, 0xf1, 0x48, 0x90, 0x99, 0x2b, 0x30, 0x12, 0x64, 0xf6, 0x2e, 0x98, 0xaf, - 0x0a, 0x90, 0x8b, 0x78, 0x5e, 0x82, 0xec, 0xe2, 0x93, 0x27, 0x00, 0xff, 0x80, 0xe0, 0xaa, 0x66, - 0xb7, 0xe3, 0xad, 0xa1, 0x59, 0x86, 0x1f, 0x0b, 0xe3, 0xcd, 0xf1, 0x9c, 0x14, 0xc2, 0xaa, 0x40, - 0xb8, 0x86, 0x6f, 0xeb, 0x68, 0xd4, 0x1e, 0x16, 0x8e, 0x7f, 0x42, 0xb0, 0xa0, 0x5f, 0xff, 0x78, - 0x7b, 0x34, 0x08, 0xed, 0x5a, 0xd9, 0x19, 0xdb, 0x2f, 0xcf, 0x18, 0x0c, 0xbb, 0x40, 0x7c, 0xcf, - 0x3e, 0x39, 0x2d, 0xa3, 0xe7, 0xa7, 0x65, 0xf4, 0xd7, 0x69, 0x19, 0x7d, 0x79, 0x56, 0x9e, 0x78, - 0x7e, 0x56, 0x9e, 0xf8, 0xe3, 0xac, 0x3c, 0xf1, 0xe9, 0xae, 0x1f, 0x44, 0x87, 0xb1, 0x6b, 0x79, - 0xac, 0x41, 0xd4, 0x9f, 0xe9, 0xc0, 0xf5, 0xd6, 0x7d, 0x46, 0xda, 0x5b, 0xa4, 0xc1, 0x6a, 0x71, - 0x9d, 0x72, 0x99, 0x67, 0xa3, 0xba, 0xae, 0x52, 0x45, 0x47, 0x4d, 0xca, 0xdd, 0x69, 0x71, 0xc8, - 0xb6, 0xfe, 0x09, 0x00, 0x00, 0xff, 0xff, 0x42, 0x17, 0xfc, 0x54, 0xb8, 0x0f, 0x00, 0x00, + 0x9a, 0x96, 0x64, 0x27, 0x71, 0xda, 0x24, 0x42, 0x42, 0x82, 0x54, 0x2a, 0xed, 0xa5, 0x94, 0x45, + 0x08, 0x84, 0x84, 0xa2, 0xdd, 0xf5, 0x64, 0xb3, 0x92, 0xbd, 0xe3, 0x7a, 0x76, 0x2d, 0x45, 0x55, + 0x2e, 0x3d, 0x21, 0x4e, 0x48, 0x48, 0x5c, 0x91, 0x38, 0x72, 0xa8, 0x38, 0x20, 0x71, 0xe5, 0x04, + 0x39, 0x70, 0xa8, 0x04, 0x07, 0x4e, 0x14, 0x25, 0xfc, 0x21, 0xc8, 0x33, 0xb3, 0xf6, 0xae, 0x3d, + 0xae, 0xd7, 0xa8, 0xf4, 0xb6, 0xfb, 0x3e, 0x7f, 0xef, 0xf7, 0x9e, 0xdf, 0x5b, 0x43, 0x39, 0x70, + 0x3d, 0xe2, 0xb1, 0x16, 0x25, 0x5e, 0x3d, 0xa0, 0x61, 0x44, 0xda, 0x9b, 0xe4, 0x51, 0x4c, 0x5b, + 0x47, 0x56, 0xb3, 0xc5, 0x22, 0x86, 0x71, 0xe0, 0x7a, 0x56, 0x47, 0x6f, 0x49, 0xbd, 0xd5, 0xde, + 0x34, 0x6e, 0x7a, 0x8c, 0x37, 0x18, 0x27, 0xae, 0xc3, 0xa9, 0x34, 0x26, 0xed, 0x4d, 0x97, 0x46, + 0xce, 0x26, 0x69, 0x3a, 0x7e, 0x10, 0x3a, 0x51, 0xc0, 0x42, 0xe9, 0x6f, 0x2c, 0x69, 0xe2, 0xab, + 0x48, 0xd2, 0xe0, 0x8a, 0xcf, 0x98, 0x5f, 0xa7, 0x44, 0xbc, 0xb9, 0xf1, 0x01, 0x71, 0x42, 0x95, + 0xdb, 0xb8, 0xa6, 0x54, 0x4e, 0x33, 0x20, 0x4e, 0x18, 0xb2, 0x48, 0x04, 0xe6, 0x4a, 0x3b, 0xe7, + 0x33, 0x9f, 0x89, 0x47, 0xd2, 0x79, 0x92, 0x52, 0x73, 0x1b, 0x16, 0x3f, 0xec, 0x20, 0xba, 0x23, + 0x72, 0x7c, 0x14, 0x39, 0x11, 0xb5, 0xe9, 0xa3, 0x98, 0xf2, 0x08, 0x5f, 0x85, 0x8b, 0x32, 0xf3, + 0x7e, 0x50, 0x2b, 0xa1, 0x0a, 0x5a, 0xbd, 0x68, 0x5f, 0x90, 0x82, 0xfb, 0x35, 0xf3, 0x29, 0x82, + 0xd2, 0xa0, 0x23, 0x6f, 0xb2, 0x90, 0x53, 0xbc, 0x03, 0x45, 0xe5, 0xc9, 0x3b, 0x72, 0xe1, 0x5c, + 0xa8, 0xce, 0x59, 0x12, 0x9f, 0x95, 0x40, 0xb7, 0xde, 0x0b, 0x8f, 0xec, 0x82, 0xd7, 0x0b, 0x80, + 0xe7, 0xe0, 0x7c, 0xb3, 0xc5, 0xd8, 0x41, 0x69, 0xb2, 0x82, 0x56, 0x8b, 0xb6, 0x7c, 0xc1, 0x77, + 0xa0, 0x28, 0x1e, 0xf6, 0x0f, 0x69, 0xe0, 0x1f, 0x46, 0xa5, 0x73, 0x22, 0x9c, 0x61, 0x0d, 0x52, + 0x6d, 0xdd, 0x13, 0x16, 0x7b, 0x53, 0x27, 0x7f, 0x2d, 0x4d, 0xd8, 0x05, 0xe1, 0x25, 0x45, 0xa6, + 0x3b, 0x88, 0x97, 0x27, 0x95, 0xde, 0x05, 0xe8, 0x35, 0x42, 0xa1, 0x7d, 0xd3, 0x92, 0x5d, 0xb3, + 0x3a, 0x5d, 0xb3, 0x64, 0x8b, 0x55, 0xd7, 0xac, 0x87, 0x8e, 0x9f, 0xb0, 0x64, 0xa7, 0x3c, 0xcd, + 0x3f, 0x10, 0x5c, 0xd1, 0x24, 0x51, 0xac, 0x84, 0x70, 0x29, 0xcd, 0x0a, 0x2f, 0xa1, 0xca, 0xb9, + 0xd5, 0x42, 0xf5, 0x86, 0xae, 0x8e, 0xfb, 0x35, 0x1a, 0x46, 0xc1, 0x41, 0x40, 0x6b, 0xa9, 0x50, + 0x7b, 0xe5, 0x4e, 0x59, 0xdf, 0x3f, 0x5f, 0x5a, 0xd0, 0xaa, 0xb9, 0x5d, 0x4c, 0x71, 0xc9, 0xf1, + 0xfb, 0x99, 0xaa, 0x26, 0x45, 0x55, 0xd7, 0x47, 0x56, 0x25, 0xc1, 0x66, 0xca, 0xfa, 0x01, 0x81, + 0x21, 0xcb, 0xea, 0xa8, 0x42, 0x1e, 0xf3, 0xdc, 0x73, 0x82, 0xaf, 0xc3, 0x6c, 0x8b, 0xb6, 0x03, + 0x1e, 0xb0, 0x70, 0x3f, 0x8c, 0x1b, 0x2e, 0x6d, 0x09, 0x24, 0x53, 0xf6, 0x4c, 0x22, 0x7e, 0x20, + 0xa4, 0x19, 0xc3, 0x54, 0x9f, 0x53, 0x86, 0xb2, 0x91, 0x78, 0x05, 0x2e, 0xd5, 0x3b, 0xf5, 0x45, + 0x89, 0xd9, 0x54, 0x05, 0xad, 0x5e, 0xb0, 0x8b, 0x52, 0xa8, 0xba, 0xfd, 0x13, 0x82, 0xab, 0x5a, + 0xc8, 0xaa, 0x17, 0xef, 0xc0, 0xac, 0x97, 0x68, 0x72, 0x0c, 0xe9, 0x8c, 0x97, 0x09, 0xf3, 0x7f, + 0xce, 0xe9, 0x13, 0x3d, 0x72, 0x9e, 0x8b, 0xed, 0xbb, 0x9a, 0x96, 0xff, 0x97, 0x41, 0xfe, 0x05, + 0xc1, 0x35, 0x3d, 0x08, 0xc5, 0xdf, 0xe7, 0xf0, 0x5a, 0x1f, 0x7f, 0xc9, 0x38, 0xaf, 0xe9, 0xca, + 0xcd, 0x86, 0xf9, 0x24, 0x88, 0x0e, 0x33, 0x04, 0xcc, 0x66, 0xe9, 0x7d, 0x89, 0xa3, 0xfb, 0x05, + 0x82, 0x65, 0x4d, 0x21, 0x32, 0xfb, 0xab, 0xe5, 0xf4, 0x57, 0x04, 0xe6, 0x8b, 0xa0, 0x28, 0x66, + 0x3f, 0x85, 0xc5, 0x3e, 0x66, 0xd5, 0x38, 0x25, 0x04, 0x8f, 0x9e, 0xa7, 0x79, 0x4f, 0x97, 0xe1, + 0xe5, 0x91, 0xba, 0x33, 0xb0, 0x4a, 0xe3, 0x5c, 0x54, 0x9a, 0x5b, 0x03, 0xeb, 0x31, 0xee, 0x15, + 0xbe, 0x00, 0xd3, 0x5c, 0x48, 0x94, 0x9b, 0x7a, 0x33, 0x8d, 0x4c, 0xb6, 0x87, 0x4e, 0xcb, 0x69, + 0x24, 0xd9, 0xcc, 0x0f, 0x32, 0x01, 0x13, 0x9d, 0x0a, 0x58, 0x85, 0xe9, 0xa6, 0x90, 0xa8, 0x9f, + 0xb6, 0x96, 0x38, 0xe5, 0xa3, 0x2c, 0xcd, 0x65, 0x58, 0x12, 0x01, 0x3f, 0x6e, 0xfa, 0x2d, 0xa7, + 0x96, 0x59, 0xaf, 0x49, 0xce, 0x3a, 0x54, 0x86, 0x9b, 0xa8, 0xd4, 0xf7, 0x60, 0x3e, 0x56, 0xea, + 0xfd, 0xdc, 0x97, 0xf0, 0x72, 0x3c, 0x18, 0xd1, 0x7c, 0x43, 0x0d, 0x4d, 0x37, 0x9b, 0x6e, 0x05, + 0x9b, 0x31, 0xac, 0xbc, 0xd0, 0x4a, 0xc1, 0x7a, 0x00, 0xa5, 0x1e, 0xac, 0x31, 0xd6, 0xdf, 0x42, + 0xac, 0x8d, 0x5b, 0xfd, 0xad, 0x08, 0xe7, 0x45, 0x5e, 0xfc, 0x2d, 0x82, 0x42, 0x0a, 0x36, 0x7e, + 0x4b, 0xc7, 0xf5, 0x90, 0x0f, 0x0d, 0x63, 0x2d, 0x9f, 0xb1, 0x2c, 0xc2, 0xbc, 0xfd, 0xe4, 0xf7, + 0x7f, 0xbe, 0x9e, 0x24, 0x78, 0x9d, 0x0c, 0xfd, 0x54, 0x52, 0x1b, 0x89, 0x3c, 0xee, 0x8e, 0xe2, + 0x31, 0xfe, 0x06, 0x41, 0x31, 0x7d, 0x2c, 0x71, 0xae, 0xac, 0xc9, 0xa4, 0x19, 0xeb, 0x39, 0xad, + 0x15, 0xc8, 0x1b, 0x02, 0xe4, 0x0a, 0x5e, 0x1e, 0x09, 0x12, 0x3f, 0x47, 0x30, 0x93, 0xe5, 0x15, + 0x5b, 0xc3, 0x93, 0xe9, 0xda, 0x6f, 0x90, 0xdc, 0xf6, 0x0a, 0x5e, 0x5d, 0xc0, 0x3b, 0xc0, 0x35, + 0x2d, 0xbc, 0xbe, 0xc5, 0x9e, 0xa6, 0x91, 0x24, 0xc7, 0x98, 0x3c, 0xee, 0x3b, 0xeb, 0xc7, 0x44, + 0xae, 0xa9, 0x94, 0x42, 0x0a, 0x8e, 0xf1, 0x53, 0x04, 0xb3, 0x7d, 0x87, 0x04, 0xe7, 0x85, 0xdc, + 0x6d, 0xc0, 0x46, 0x7e, 0x07, 0x55, 0xe4, 0xae, 0x28, 0xb2, 0x8a, 0x37, 0xc6, 0x2d, 0x12, 0x9f, + 0x20, 0x98, 0xd7, 0x6e, 0x69, 0x7c, 0x3b, 0x27, 0x8a, 0xec, 0x81, 0x31, 0xb6, 0xc7, 0x75, 0x53, + 0x25, 0xbc, 0x2b, 0x4a, 0x78, 0x1b, 0xef, 0x8e, 0xdd, 0x27, 0x75, 0x33, 0xf0, 0x77, 0x99, 0xb1, + 0x8f, 0xf3, 0x8d, 0x7d, 0x3c, 0xd6, 0xd8, 0xf7, 0x76, 0x78, 0xee, 0xdf, 0x66, 0x9c, 0xe5, 0xfb, + 0xcb, 0x2e, 0x48, 0xb9, 0x8e, 0x47, 0x82, 0xcc, 0x5c, 0x81, 0x91, 0x20, 0xb3, 0x77, 0xc1, 0x7c, + 0x5d, 0x80, 0x5c, 0xc4, 0xf3, 0x12, 0x64, 0x17, 0x9f, 0x3c, 0x01, 0xf8, 0x47, 0x04, 0x97, 0x35, + 0xbb, 0x1d, 0x6f, 0x0d, 0xcd, 0x32, 0xfc, 0x58, 0x18, 0xb7, 0xc6, 0x73, 0x52, 0x08, 0xab, 0x02, + 0xe1, 0x1a, 0xbe, 0xa9, 0xa3, 0x51, 0x7b, 0x58, 0x38, 0xfe, 0x19, 0xc1, 0x82, 0x7e, 0xfd, 0xe3, + 0xed, 0xd1, 0x20, 0xb4, 0x6b, 0x65, 0x67, 0x6c, 0xbf, 0x3c, 0x63, 0x30, 0xec, 0x02, 0xf1, 0x3d, + 0xfb, 0xe4, 0xb4, 0x8c, 0x9e, 0x9d, 0x96, 0xd1, 0xdf, 0xa7, 0x65, 0xf4, 0xd5, 0x59, 0x79, 0xe2, + 0xd9, 0x59, 0x79, 0xe2, 0xcf, 0xb3, 0xf2, 0xc4, 0x67, 0xbb, 0x7e, 0x10, 0x1d, 0xc6, 0xae, 0xe5, + 0xb1, 0x06, 0x51, 0x7f, 0xa6, 0x03, 0xd7, 0x5b, 0xf7, 0x19, 0x69, 0xdf, 0x22, 0x0d, 0x56, 0x8b, + 0xeb, 0x94, 0xcb, 0x3c, 0x1b, 0xd5, 0x75, 0x95, 0x2a, 0x3a, 0x6a, 0x52, 0xee, 0x4e, 0x8b, 0x43, + 0xb6, 0xf5, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6e, 0xea, 0xa4, 0x42, 0xb8, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/02-client/types/tx.pb.go b/modules/core/02-client/types/tx.pb.go index a9eec55a353..1ed94c0c49b 100644 --- a/modules/core/02-client/types/tx.pb.go +++ b/modules/core/02-client/types/tx.pb.go @@ -375,45 +375,45 @@ func init() { func init() { proto.RegisterFile("ibc/core/client/v1/tx.proto", fileDescriptor_cb5dc4651eb49a04) } var fileDescriptor_cb5dc4651eb49a04 = []byte{ - // 601 bytes of a gzipped FileDescriptorProto + // 602 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x3f, 0x6f, 0xd3, 0x4e, 0x18, 0x8e, 0x9b, 0xdf, 0x2f, 0x6a, 0xae, 0x81, 0x56, 0x26, 0xb4, 0xa9, 0xab, 0xda, 0x91, 0xe9, - 0x10, 0x44, 0x7b, 0x47, 0xd2, 0xa5, 0xea, 0x46, 0x3a, 0x31, 0x44, 0x02, 0x57, 0x0c, 0xb0, 0x04, - 0xff, 0xb9, 0x5e, 0x4e, 0xc4, 0xbe, 0xc8, 0x67, 0x47, 0xe4, 0x1b, 0x30, 0x32, 0xf0, 0x01, 0x2a, - 0x06, 0x3e, 0x0b, 0x63, 0x07, 0x06, 0xa6, 0xa8, 0x4a, 0x16, 0xe6, 0x7c, 0x02, 0x14, 0x9f, 0x13, - 0x62, 0x37, 0x8e, 0x22, 0xfe, 0x6c, 0x3e, 0xbf, 0xcf, 0x3d, 0xcf, 0xfb, 0xf8, 0x79, 0xcf, 0x07, - 0x0e, 0xa8, 0x65, 0x23, 0x9b, 0xf9, 0x18, 0xd9, 0x5d, 0x8a, 0xbd, 0x00, 0xf5, 0xeb, 0x28, 0x78, - 0x0f, 0x7b, 0x3e, 0x0b, 0x98, 0x2c, 0x53, 0xcb, 0x86, 0xd3, 0x22, 0x14, 0x45, 0xd8, 0xaf, 0x2b, - 0x65, 0xc2, 0x08, 0x8b, 0xca, 0x68, 0xfa, 0x24, 0x90, 0xca, 0x3e, 0x61, 0x8c, 0x74, 0x31, 0x8a, - 0x56, 0x56, 0x78, 0x85, 0x4c, 0x6f, 0x20, 0x4a, 0xfa, 0xad, 0x04, 0xb6, 0x5b, 0x9c, 0x5c, 0xf8, - 0xd8, 0x0c, 0xf0, 0x45, 0xc4, 0x23, 0xbf, 0x00, 0x25, 0xc1, 0xd8, 0xe6, 0x81, 0x19, 0xe0, 0x8a, - 0x54, 0x95, 0x6a, 0x5b, 0x8d, 0x32, 0x14, 0x2c, 0x70, 0xc6, 0x02, 0x9f, 0x79, 0x83, 0xe6, 0xde, - 0x64, 0xa8, 0x3d, 0x18, 0x98, 0x6e, 0xf7, 0x5c, 0x5f, 0xdc, 0xa3, 0x1b, 0x5b, 0x62, 0x79, 0x39, - 0x5d, 0xc9, 0xaf, 0xc1, 0xb6, 0xcd, 0x3c, 0x8e, 0x3d, 0x1e, 0xf2, 0x98, 0x74, 0x63, 0x05, 0xa9, - 0x32, 0x19, 0x6a, 0xbb, 0x31, 0x69, 0x72, 0x9b, 0x6e, 0xdc, 0x9f, 0xbf, 0x11, 0xd4, 0xbb, 0xa0, - 0xc0, 0x29, 0xf1, 0xb0, 0x5f, 0xc9, 0x57, 0xa5, 0x5a, 0xd1, 0x88, 0x57, 0xe7, 0x9b, 0x1f, 0xae, - 0xb5, 0xdc, 0x8f, 0x6b, 0x2d, 0xa7, 0xef, 0x83, 0xbd, 0x94, 0x43, 0x03, 0xf3, 0xde, 0x94, 0x45, - 0xff, 0x24, 0xdc, 0xbf, 0xea, 0x39, 0xbf, 0xdc, 0xd7, 0x41, 0x31, 0x76, 0x42, 0x9d, 0xc8, 0x7a, - 0xb1, 0x59, 0x9e, 0x0c, 0xb5, 0x9d, 0x84, 0x49, 0xea, 0xe8, 0xc6, 0xa6, 0x78, 0x7e, 0xee, 0xc8, - 0xc7, 0xa0, 0xd0, 0xc1, 0xa6, 0x83, 0xfd, 0x55, 0xae, 0x8c, 0x18, 0xb3, 0x76, 0xc7, 0x8b, 0x5d, - 0xcd, 0x3b, 0xfe, 0x96, 0x07, 0x3b, 0x51, 0x8d, 0xf8, 0xa6, 0xf3, 0x07, 0x2d, 0xa7, 0x33, 0xde, - 0xf8, 0x17, 0x19, 0xe7, 0xff, 0x52, 0xc6, 0x2f, 0x41, 0xb9, 0xe7, 0x33, 0x76, 0xd5, 0x0e, 0x85, - 0xed, 0xb6, 0xd0, 0xad, 0xfc, 0x57, 0x95, 0x6a, 0xa5, 0xa6, 0x36, 0x19, 0x6a, 0x07, 0x82, 0x69, - 0x19, 0x4a, 0x37, 0xe4, 0xe8, 0x75, 0xf2, 0x93, 0xbd, 0x03, 0x87, 0x29, 0x70, 0xaa, 0xf7, 0xff, - 0x23, 0xee, 0xda, 0x64, 0xa8, 0x1d, 0x2d, 0xe5, 0x4e, 0xf7, 0xac, 0x24, 0x44, 0xb2, 0x66, 0xb4, - 0x90, 0x91, 0xb8, 0x02, 0x2a, 0xe9, 0x54, 0xe7, 0x91, 0x7f, 0x91, 0xc0, 0xc3, 0x16, 0x27, 0x97, - 0xa1, 0xe5, 0xd2, 0xa0, 0x45, 0xb9, 0x85, 0x3b, 0x66, 0x9f, 0xb2, 0xd0, 0xff, 0x9d, 0xdc, 0xcf, - 0x40, 0xc9, 0x5d, 0xa0, 0x58, 0x39, 0xb0, 0x09, 0xe4, 0x1a, 0x63, 0xab, 0x81, 0xc3, 0xa5, 0x7d, - 0xce, 0x9c, 0x34, 0x3e, 0xe7, 0x41, 0xbe, 0xc5, 0x89, 0xfc, 0x16, 0x94, 0x12, 0x3f, 0x9c, 0x47, - 0xf0, 0xee, 0xaf, 0x0c, 0xa6, 0xce, 0xac, 0xf2, 0x64, 0x0d, 0xd0, 0x4c, 0x69, 0xaa, 0x90, 0x38, - 0xd4, 0x59, 0x0a, 0x8b, 0xa0, 0x4c, 0x85, 0x65, 0x07, 0x51, 0xb6, 0xc1, 0xbd, 0xe4, 0x44, 0x1d, - 0x65, 0xee, 0x5e, 0x40, 0x29, 0xc7, 0xeb, 0xa0, 0xe6, 0x22, 0x3e, 0x90, 0x97, 0xc4, 0xfe, 0x38, - 0x83, 0xe3, 0x2e, 0x54, 0xa9, 0xaf, 0x0d, 0x9d, 0x69, 0x36, 0x8d, 0xaf, 0x23, 0x55, 0xba, 0x19, - 0xa9, 0xd2, 0xed, 0x48, 0x95, 0x3e, 0x8e, 0xd5, 0xdc, 0xcd, 0x58, 0xcd, 0x7d, 0x1f, 0xab, 0xb9, - 0x37, 0x67, 0x84, 0x06, 0x9d, 0xd0, 0x82, 0x36, 0x73, 0x91, 0xcd, 0xb8, 0xcb, 0x38, 0xa2, 0x96, - 0x7d, 0x42, 0x18, 0xea, 0x9f, 0x22, 0x97, 0x39, 0x61, 0x17, 0x73, 0x71, 0x5b, 0x3d, 0x6d, 0x9c, - 0xc4, 0x17, 0x56, 0x30, 0xe8, 0x61, 0x6e, 0x15, 0xa2, 0xb9, 0x3a, 0xfd, 0x19, 0x00, 0x00, 0xff, - 0xff, 0x64, 0xe7, 0xce, 0xe6, 0xd0, 0x06, 0x00, 0x00, + 0x10, 0x44, 0x7b, 0x47, 0x02, 0x43, 0xd5, 0x8d, 0x74, 0x62, 0x88, 0x04, 0xae, 0x18, 0x60, 0x09, + 0xfe, 0x73, 0xbd, 0x9c, 0x88, 0x7d, 0x91, 0xcf, 0x8e, 0xc8, 0x37, 0x60, 0x64, 0xe0, 0x03, 0x54, + 0x0c, 0x7c, 0x16, 0xc6, 0x0e, 0x0c, 0x4c, 0x51, 0x95, 0x2c, 0xcc, 0xf9, 0x04, 0x28, 0x3e, 0x27, + 0xc4, 0x6e, 0x1c, 0x45, 0xfc, 0xd9, 0x7c, 0x7e, 0x9f, 0x7b, 0x9e, 0xf7, 0xf1, 0xf3, 0x9e, 0x0f, + 0x1c, 0x50, 0xcb, 0x46, 0x36, 0xf3, 0x31, 0xb2, 0xbb, 0x14, 0x7b, 0x01, 0xea, 0xd7, 0x51, 0xf0, + 0x1e, 0xf6, 0x7c, 0x16, 0x30, 0x59, 0xa6, 0x96, 0x0d, 0xa7, 0x45, 0x28, 0x8a, 0xb0, 0x5f, 0x57, + 0xca, 0x84, 0x11, 0x16, 0x95, 0xd1, 0xf4, 0x49, 0x20, 0x95, 0x7d, 0xc2, 0x18, 0xe9, 0x62, 0x14, + 0xad, 0xac, 0xf0, 0x12, 0x99, 0xde, 0x40, 0x94, 0xf4, 0x1b, 0x09, 0x6c, 0xb7, 0x38, 0x39, 0xf7, + 0xb1, 0x19, 0xe0, 0xf3, 0x88, 0x47, 0x7e, 0x01, 0x4a, 0x82, 0xb1, 0xcd, 0x03, 0x33, 0xc0, 0x15, + 0xa9, 0x2a, 0xd5, 0xb6, 0x1a, 0x65, 0x28, 0x58, 0xe0, 0x8c, 0x05, 0x3e, 0xf3, 0x06, 0xcd, 0xbd, + 0xc9, 0x50, 0xbb, 0x37, 0x30, 0xdd, 0xee, 0x99, 0xbe, 0xb8, 0x47, 0x37, 0xb6, 0xc4, 0xf2, 0x62, + 0xba, 0x92, 0x5f, 0x83, 0x6d, 0x9b, 0x79, 0x1c, 0x7b, 0x3c, 0xe4, 0x31, 0xe9, 0xc6, 0x0a, 0x52, + 0x65, 0x32, 0xd4, 0x76, 0x63, 0xd2, 0xe4, 0x36, 0xdd, 0xb8, 0x3b, 0x7f, 0x23, 0xa8, 0x77, 0x41, + 0x81, 0x53, 0xe2, 0x61, 0xbf, 0x92, 0xaf, 0x4a, 0xb5, 0xa2, 0x11, 0xaf, 0xce, 0x36, 0x3f, 0x5c, + 0x69, 0xb9, 0x1f, 0x57, 0x5a, 0x4e, 0xdf, 0x07, 0x7b, 0x29, 0x87, 0x06, 0xe6, 0xbd, 0x29, 0x8b, + 0xfe, 0x49, 0xb8, 0x7f, 0xd5, 0x73, 0x7e, 0xb9, 0xaf, 0x83, 0x62, 0xec, 0x84, 0x3a, 0x91, 0xf5, + 0x62, 0xb3, 0x3c, 0x19, 0x6a, 0x3b, 0x09, 0x93, 0xd4, 0xd1, 0x8d, 0x4d, 0xf1, 0xfc, 0xdc, 0x91, + 0x8f, 0x41, 0xa1, 0x83, 0x4d, 0x07, 0xfb, 0xab, 0x5c, 0x19, 0x31, 0x66, 0xed, 0x8e, 0x17, 0xbb, + 0x9a, 0x77, 0xfc, 0x2d, 0x0f, 0x76, 0xa2, 0x1a, 0xf1, 0x4d, 0xe7, 0x0f, 0x5a, 0x4e, 0x67, 0xbc, + 0xf1, 0x2f, 0x32, 0xce, 0xff, 0xa5, 0x8c, 0x5f, 0x82, 0x72, 0xcf, 0x67, 0xec, 0xb2, 0x1d, 0x0a, + 0xdb, 0x6d, 0xa1, 0x5b, 0xf9, 0xaf, 0x2a, 0xd5, 0x4a, 0x4d, 0x6d, 0x32, 0xd4, 0x0e, 0x04, 0xd3, + 0x32, 0x94, 0x6e, 0xc8, 0xd1, 0xeb, 0xe4, 0x27, 0x7b, 0x07, 0x0e, 0x53, 0xe0, 0x54, 0xef, 0xff, + 0x47, 0xdc, 0xb5, 0xc9, 0x50, 0x3b, 0x5a, 0xca, 0x9d, 0xee, 0x59, 0x49, 0x88, 0x64, 0xcd, 0x68, + 0x21, 0x23, 0x71, 0x05, 0x54, 0xd2, 0xa9, 0xce, 0x23, 0xff, 0x22, 0x81, 0xfb, 0x2d, 0x4e, 0x2e, + 0x42, 0xcb, 0xa5, 0x41, 0x8b, 0x72, 0x0b, 0x77, 0xcc, 0x3e, 0x65, 0xa1, 0xff, 0x3b, 0xb9, 0x9f, + 0x82, 0x92, 0xbb, 0x40, 0xb1, 0x72, 0x60, 0x13, 0xc8, 0x35, 0xc6, 0x56, 0x03, 0x87, 0x4b, 0xfb, + 0x9c, 0x39, 0x69, 0x7c, 0xce, 0x83, 0x7c, 0x8b, 0x13, 0xf9, 0x2d, 0x28, 0x25, 0x7e, 0x38, 0x0f, + 0xe0, 0xed, 0x5f, 0x19, 0x4c, 0x9d, 0x59, 0xe5, 0xd1, 0x1a, 0xa0, 0x99, 0xd2, 0x54, 0x21, 0x71, + 0xa8, 0xb3, 0x14, 0x16, 0x41, 0x99, 0x0a, 0xcb, 0x0e, 0xa2, 0x6c, 0x83, 0x3b, 0xc9, 0x89, 0x3a, + 0xca, 0xdc, 0xbd, 0x80, 0x52, 0x8e, 0xd7, 0x41, 0xcd, 0x45, 0x7c, 0x20, 0x2f, 0x89, 0xfd, 0x61, + 0x06, 0xc7, 0x6d, 0xa8, 0x52, 0x5f, 0x1b, 0x3a, 0xd3, 0x6c, 0x1a, 0x5f, 0x47, 0xaa, 0x74, 0x3d, + 0x52, 0xa5, 0x9b, 0x91, 0x2a, 0x7d, 0x1c, 0xab, 0xb9, 0xeb, 0xb1, 0x9a, 0xfb, 0x3e, 0x56, 0x73, + 0x6f, 0x4e, 0x09, 0x0d, 0x3a, 0xa1, 0x05, 0x6d, 0xe6, 0x22, 0x9b, 0x71, 0x97, 0x71, 0x44, 0x2d, + 0xfb, 0x84, 0x30, 0xd4, 0x7f, 0x8a, 0x5c, 0xe6, 0x84, 0x5d, 0xcc, 0xc5, 0x6d, 0xf5, 0xb8, 0x71, + 0x12, 0x5f, 0x58, 0xc1, 0xa0, 0x87, 0xb9, 0x55, 0x88, 0xe6, 0xea, 0xc9, 0xcf, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x48, 0x1a, 0x96, 0xf0, 0xd0, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/03-connection/client/cli/cli.go b/modules/core/03-connection/client/cli/cli.go index d31649cf8ef..d4972654569 100644 --- a/modules/core/03-connection/client/cli/cli.go +++ b/modules/core/03-connection/client/cli/cli.go @@ -3,7 +3,7 @@ package cli import ( "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) // GetQueryCmd returns the query commands for IBC connections diff --git a/modules/core/03-connection/client/cli/query.go b/modules/core/03-connection/client/cli/query.go index 6ef8fca5b1a..310e21bef82 100644 --- a/modules/core/03-connection/client/cli/query.go +++ b/modules/core/03-connection/client/cli/query.go @@ -8,9 +8,9 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/client/utils" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/client/utils" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // GetCmdQueryConnections defines the command to query all the connection ends diff --git a/modules/core/03-connection/client/utils/utils.go b/modules/core/03-connection/client/utils/utils.go index aaadcf9feae..bb1b8f7f1c5 100644 --- a/modules/core/03-connection/client/utils/utils.go +++ b/modules/core/03-connection/client/utils/utils.go @@ -10,13 +10,13 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clientutils "github.com/cosmos/ibc-go/v3/modules/core/02-client/client/utils" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/client" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clientutils "github.com/cosmos/ibc-go/v4/modules/core/02-client/client/utils" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/client" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // QueryConnection returns a connection end. diff --git a/modules/core/03-connection/genesis.go b/modules/core/03-connection/genesis.go index dca212469c3..b0070d79197 100644 --- a/modules/core/03-connection/genesis.go +++ b/modules/core/03-connection/genesis.go @@ -3,8 +3,8 @@ package connection import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/keeper" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/keeper" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) // InitGenesis initializes the ibc connection submodule's state from a provided genesis diff --git a/modules/core/03-connection/keeper/events.go b/modules/core/03-connection/keeper/events.go index a8dcd1251a7..ac6cae539e3 100644 --- a/modules/core/03-connection/keeper/events.go +++ b/modules/core/03-connection/keeper/events.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) // EmitConnectionOpenInitEvent emits a connection open init event diff --git a/modules/core/03-connection/keeper/grpc_query.go b/modules/core/03-connection/keeper/grpc_query.go index 89e9b978e0b..d07616163f6 100644 --- a/modules/core/03-connection/keeper/grpc_query.go +++ b/modules/core/03-connection/keeper/grpc_query.go @@ -10,9 +10,9 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) var _ types.QueryServer = Keeper{} diff --git a/modules/core/03-connection/keeper/grpc_query_test.go b/modules/core/03-connection/keeper/grpc_query_test.go index fe97dd09b85..b1ffb50b910 100644 --- a/modules/core/03-connection/keeper/grpc_query_test.go +++ b/modules/core/03-connection/keeper/grpc_query_test.go @@ -6,10 +6,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestQueryConnection() { diff --git a/modules/core/03-connection/keeper/handshake.go b/modules/core/03-connection/keeper/handshake.go index 177324e3e17..9f809a47a25 100644 --- a/modules/core/03-connection/keeper/handshake.go +++ b/modules/core/03-connection/keeper/handshake.go @@ -8,10 +8,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/gogo/protobuf/proto" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // ConnOpenInit initialises a connection attempt on chain A. The generated connection identifier diff --git a/modules/core/03-connection/keeper/handshake_test.go b/modules/core/03-connection/keeper/handshake_test.go index 8707b72d401..5f322e4e213 100644 --- a/modules/core/03-connection/keeper/handshake_test.go +++ b/modules/core/03-connection/keeper/handshake_test.go @@ -3,12 +3,12 @@ package keeper_test import ( "time" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) // TestConnOpenInit - chainA initializes (INIT state) a connection with diff --git a/modules/core/03-connection/keeper/keeper.go b/modules/core/03-connection/keeper/keeper.go index 22954ca7943..e6370da8d26 100644 --- a/modules/core/03-connection/keeper/keeper.go +++ b/modules/core/03-connection/keeper/keeper.go @@ -8,11 +8,11 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // Keeper defines the IBC connection keeper diff --git a/modules/core/03-connection/keeper/keeper_test.go b/modules/core/03-connection/keeper/keeper_test.go index 3d63ed468ba..dd72a9cc620 100644 --- a/modules/core/03-connection/keeper/keeper_test.go +++ b/modules/core/03-connection/keeper/keeper_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type KeeperTestSuite struct { diff --git a/modules/core/03-connection/keeper/params.go b/modules/core/03-connection/keeper/params.go index 3d7c145ac77..26d2d4e843f 100644 --- a/modules/core/03-connection/keeper/params.go +++ b/modules/core/03-connection/keeper/params.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) // GetMaxExpectedTimePerBlock retrieves the maximum expected time per block from the paramstore diff --git a/modules/core/03-connection/keeper/params_test.go b/modules/core/03-connection/keeper/params_test.go index 21d628fa6fc..7e6ea66bbca 100644 --- a/modules/core/03-connection/keeper/params_test.go +++ b/modules/core/03-connection/keeper/params_test.go @@ -1,7 +1,7 @@ package keeper_test import ( - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) func (suite *KeeperTestSuite) TestParams() { diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index 1059cf3444e..e0cdbfcad03 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // VerifyClientState verifies a proof of a client state of the running machine diff --git a/modules/core/03-connection/keeper/verify_test.go b/modules/core/03-connection/keeper/verify_test.go index df9e6a5d69d..6641bf790bd 100644 --- a/modules/core/03-connection/keeper/verify_test.go +++ b/modules/core/03-connection/keeper/verify_test.go @@ -4,14 +4,14 @@ import ( "fmt" "time" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" ) var defaultTimeoutHeight = clienttypes.NewHeight(0, 100000) diff --git a/modules/core/03-connection/module.go b/modules/core/03-connection/module.go index 8bfa8ed6017..17132c269a9 100644 --- a/modules/core/03-connection/module.go +++ b/modules/core/03-connection/module.go @@ -4,8 +4,8 @@ import ( "github.com/gogo/protobuf/grpc" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/client/cli" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/client/cli" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) // Name returns the IBC connection ICS name. diff --git a/modules/core/03-connection/simulation/decoder.go b/modules/core/03-connection/simulation/decoder.go index e01d2787e32..803bdda728e 100644 --- a/modules/core/03-connection/simulation/decoder.go +++ b/modules/core/03-connection/simulation/decoder.go @@ -7,8 +7,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's diff --git a/modules/core/03-connection/simulation/decoder_test.go b/modules/core/03-connection/simulation/decoder_test.go index 94de9fae92a..77ac0f7e630 100644 --- a/modules/core/03-connection/simulation/decoder_test.go +++ b/modules/core/03-connection/simulation/decoder_test.go @@ -7,10 +7,10 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/simulation" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/simulation" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) func TestDecodeStore(t *testing.T) { diff --git a/modules/core/03-connection/simulation/genesis.go b/modules/core/03-connection/simulation/genesis.go index 746daec042f..d60803babe0 100644 --- a/modules/core/03-connection/simulation/genesis.go +++ b/modules/core/03-connection/simulation/genesis.go @@ -5,7 +5,7 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) // GenConnectionGenesis returns the default connection genesis state. diff --git a/modules/core/03-connection/types/codec.go b/modules/core/03-connection/types/codec.go index 96ae3cba865..f09a14f283c 100644 --- a/modules/core/03-connection/types/codec.go +++ b/modules/core/03-connection/types/codec.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // RegisterInterfaces register the ibc interfaces submodule implementations to protobuf diff --git a/modules/core/03-connection/types/connection.go b/modules/core/03-connection/types/connection.go index 3fa86a6a30f..508140a2de3 100644 --- a/modules/core/03-connection/types/connection.go +++ b/modules/core/03-connection/types/connection.go @@ -3,9 +3,9 @@ package types import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.ConnectionI = (*ConnectionEnd)(nil) diff --git a/modules/core/03-connection/types/connection.pb.go b/modules/core/03-connection/types/connection.pb.go index d198ef2d8fe..893debbba18 100644 --- a/modules/core/03-connection/types/connection.pb.go +++ b/modules/core/03-connection/types/connection.pb.go @@ -5,7 +5,7 @@ package types import ( fmt "fmt" - types "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" + types "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -418,52 +418,53 @@ func init() { } var fileDescriptor_90572467c054e43a = []byte{ - // 716 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x4f, 0x6f, 0xd2, 0x60, - 0x18, 0xa7, 0xa5, 0x30, 0x78, 0x19, 0x8a, 0x95, 0xb8, 0x06, 0xb3, 0xb6, 0xa9, 0x46, 0x89, 0xc9, - 0xa8, 0x8c, 0xc4, 0xc3, 0xd4, 0xc3, 0x60, 0x98, 0x34, 0x2a, 0x92, 0x8e, 0x2d, 0x71, 0x17, 0x52, - 0xda, 0x77, 0xec, 0xcd, 0x68, 0x5f, 0xd2, 0xbe, 0x10, 0xf8, 0x06, 0xcb, 0x4e, 0x5e, 0x3d, 0x2c, - 0x31, 0xf1, 0xbb, 0x98, 0xc5, 0xd3, 0x8e, 0x9e, 0x88, 0xd9, 0xae, 0x9e, 0xf8, 0x04, 0xa6, 0x7d, - 0x0b, 0x74, 0x8b, 0x33, 0xd9, 0xf4, 0xf6, 0x3c, 0xfd, 0xfd, 0xe1, 0x79, 0x7e, 0x3c, 0x14, 0xf0, - 0x14, 0x75, 0x4c, 0xd5, 0xc4, 0x2e, 0x54, 0x4d, 0xec, 0x38, 0xd0, 0x24, 0x08, 0x3b, 0xea, 0xb0, - 0x1c, 0xe9, 0x4a, 0x7d, 0x17, 0x13, 0xcc, 0x3f, 0x40, 0x1d, 0xb3, 0xe4, 0x13, 0x4b, 0x11, 0x68, - 0x58, 0x2e, 0xe4, 0xbb, 0xb8, 0x8b, 0x03, 0x8a, 0xea, 0x57, 0x94, 0x5d, 0x88, 0xda, 0xda, 0x36, - 0x22, 0x36, 0x74, 0x08, 0xb5, 0x9d, 0x75, 0x94, 0xa8, 0x7c, 0x63, 0x41, 0xb6, 0x36, 0x37, 0xac, - 0x3b, 0x16, 0x5f, 0x06, 0x69, 0xb3, 0x87, 0xa0, 0x43, 0xda, 0xc8, 0x12, 0x18, 0x99, 0x29, 0xa6, - 0xab, 0xf9, 0xe9, 0x44, 0xca, 0x8d, 0x0d, 0xbb, 0xb7, 0xa1, 0xcc, 0x21, 0x45, 0x4f, 0xd1, 0x5a, - 0xb3, 0xf8, 0x97, 0x20, 0x35, 0x84, 0xae, 0x87, 0xb0, 0xe3, 0x09, 0xac, 0x1c, 0x2f, 0x66, 0xd6, - 0xa5, 0xd2, 0x9f, 0xc7, 0x2d, 0xed, 0x52, 0x9e, 0x3e, 0x17, 0xf0, 0x15, 0x90, 0xf0, 0x88, 0x41, - 0xa0, 0x10, 0x97, 0x99, 0xe2, 0x9d, 0xf5, 0xd5, 0xeb, 0x94, 0xdb, 0x3e, 0x49, 0xa7, 0x5c, 0xbe, - 0x01, 0x96, 0x4d, 0x3c, 0x70, 0x08, 0x74, 0xfb, 0x86, 0x4b, 0xc6, 0x02, 0x27, 0x33, 0xc5, 0xcc, - 0xfa, 0xe3, 0xeb, 0xb4, 0xb5, 0x08, 0xb7, 0xca, 0x9d, 0x4e, 0xa4, 0x98, 0x7e, 0x49, 0xcf, 0x6f, - 0x80, 0x65, 0x0b, 0xf6, 0x8c, 0x71, 0xbb, 0x0f, 0x5d, 0x84, 0x2d, 0x21, 0x21, 0x33, 0x45, 0xae, - 0xba, 0x32, 0x9d, 0x48, 0xf7, 0xe9, 0xde, 0x51, 0x54, 0xd1, 0x33, 0x41, 0xdb, 0x0c, 0xba, 0x0d, - 0xee, 0xe8, 0x8b, 0x14, 0x53, 0x7e, 0xb1, 0x20, 0xaf, 0x59, 0xd0, 0x21, 0x68, 0x1f, 0x41, 0x6b, - 0x11, 0x29, 0xbf, 0x0a, 0xd8, 0x79, 0x90, 0xd9, 0xe9, 0x44, 0x4a, 0x53, 0x43, 0x3f, 0x41, 0x16, - 0x5d, 0x89, 0x9b, 0xbd, 0x71, 0xdc, 0xf1, 0x5b, 0xc7, 0xcd, 0xfd, 0x43, 0xdc, 0x89, 0xff, 0x1c, - 0x77, 0xf2, 0xc6, 0x71, 0x7f, 0x67, 0xc0, 0x72, 0xf4, 0x63, 0x6e, 0x73, 0xb6, 0xaf, 0x41, 0x76, - 0x31, 0xf7, 0x22, 0x7e, 0x61, 0x3a, 0x91, 0xf2, 0xa1, 0x2c, 0x0a, 0x2b, 0xfe, 0x12, 0xb3, 0x5e, - 0xb3, 0xf8, 0x2a, 0x48, 0xf6, 0x5d, 0xb8, 0x8f, 0x46, 0xc1, 0xe5, 0x5e, 0x89, 0x63, 0xfe, 0x33, - 0x1b, 0x96, 0x4b, 0xef, 0xa1, 0x7b, 0xd8, 0x83, 0xcd, 0x80, 0x1b, 0xc6, 0x11, 0x2a, 0xc3, 0x65, - 0x1e, 0x81, 0x4c, 0x2d, 0x18, 0xaa, 0x69, 0x90, 0x03, 0x8f, 0xcf, 0x83, 0x44, 0xdf, 0x2f, 0x04, - 0x46, 0x8e, 0x17, 0xd3, 0x3a, 0x6d, 0x94, 0x3d, 0x70, 0x77, 0x71, 0x55, 0x94, 0x78, 0x8b, 0x9d, - 0xe7, 0xde, 0x6c, 0xd4, 0xfb, 0x2d, 0x58, 0x0a, 0x2f, 0x85, 0x17, 0x01, 0x40, 0xb3, 0x33, 0x76, - 0xa9, 0xa9, 0x1e, 0x79, 0xc2, 0x17, 0x40, 0x6a, 0x1f, 0x1a, 0x64, 0xe0, 0xc2, 0x99, 0xc7, 0xbc, - 0x0f, 0xb7, 0x71, 0x40, 0xb2, 0x69, 0xb8, 0x86, 0xed, 0xf1, 0x16, 0x78, 0x68, 0x1b, 0xa3, 0x36, - 0x1c, 0xf5, 0xa1, 0x49, 0xa0, 0xd5, 0x26, 0xc8, 0x86, 0xfe, 0x97, 0xda, 0xee, 0xf4, 0xb0, 0x79, - 0x18, 0x98, 0x73, 0xd5, 0x27, 0xd3, 0x89, 0xa4, 0xd0, 0x89, 0xff, 0x42, 0x56, 0xf4, 0x15, 0xdb, - 0x18, 0xd5, 0x43, 0xb0, 0x85, 0x6c, 0xd8, 0x84, 0x6e, 0xd5, 0x47, 0x9e, 0x7d, 0x66, 0x40, 0x22, - 0xb8, 0x56, 0xfe, 0x05, 0x90, 0xb6, 0x5b, 0x9b, 0xad, 0x7a, 0x7b, 0xa7, 0xa1, 0x35, 0xb4, 0x96, - 0xb6, 0xf9, 0x4e, 0xdb, 0xab, 0x6f, 0xb5, 0x77, 0x1a, 0xdb, 0xcd, 0x7a, 0x4d, 0x7b, 0xa3, 0xd5, - 0xb7, 0x72, 0xb1, 0xc2, 0xbd, 0xe3, 0x13, 0x39, 0x7b, 0x89, 0xc0, 0x0b, 0x00, 0x50, 0x9d, 0xff, - 0x30, 0xc7, 0x14, 0x52, 0xc7, 0x27, 0x32, 0xe7, 0xd7, 0xbc, 0x08, 0xb2, 0x14, 0x69, 0xe9, 0x1f, - 0x3f, 0x34, 0xeb, 0x8d, 0x1c, 0x5b, 0xc8, 0x1c, 0x9f, 0xc8, 0x4b, 0x61, 0xbb, 0x50, 0x06, 0x60, - 0x9c, 0x2a, 0xfd, 0xba, 0xc0, 0x1d, 0x7d, 0x15, 0x63, 0xd5, 0xdd, 0xd3, 0x73, 0x91, 0x39, 0x3b, - 0x17, 0x99, 0x9f, 0xe7, 0x22, 0xf3, 0xe9, 0x42, 0x8c, 0x9d, 0x5d, 0x88, 0xb1, 0x1f, 0x17, 0x62, - 0x6c, 0xef, 0x55, 0x17, 0x91, 0x83, 0x41, 0xc7, 0x3f, 0x15, 0xd5, 0xc4, 0x9e, 0x8d, 0x3d, 0x15, - 0x75, 0xcc, 0xb5, 0x2e, 0x56, 0x87, 0x15, 0xd5, 0xc6, 0xd6, 0xa0, 0x07, 0x3d, 0xfa, 0x06, 0x7f, - 0x5e, 0x59, 0x8b, 0xfc, 0x37, 0x90, 0x71, 0x1f, 0x7a, 0x9d, 0x64, 0xf0, 0xf6, 0xae, 0xfc, 0x0e, - 0x00, 0x00, 0xff, 0xff, 0xf4, 0xbe, 0xf1, 0xb5, 0x3f, 0x06, 0x00, 0x00, + // 721 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x4f, 0x6f, 0xda, 0x48, + 0x14, 0xc7, 0xc6, 0x10, 0x18, 0xc2, 0x2e, 0x3b, 0x8b, 0x36, 0x16, 0xab, 0xd8, 0x96, 0x77, 0xb5, + 0x8b, 0x56, 0x0a, 0x5e, 0x92, 0xd5, 0x1e, 0xd2, 0xf6, 0x10, 0x08, 0x95, 0xac, 0xb6, 0x14, 0x39, + 0x24, 0x52, 0x73, 0x41, 0xc6, 0x9e, 0x90, 0x51, 0xb0, 0x07, 0xd9, 0x03, 0x82, 0x6f, 0x10, 0xe5, + 0xd4, 0x6b, 0x0f, 0x91, 0x2a, 0xf5, 0xbb, 0x54, 0x51, 0x4f, 0x39, 0xf6, 0x84, 0xaa, 0xe4, 0xda, + 0x13, 0x9f, 0xa0, 0xb2, 0xc7, 0x80, 0x13, 0x35, 0x95, 0x92, 0xf6, 0xf6, 0x9e, 0x7f, 0x7f, 0x78, + 0xef, 0xc7, 0xc3, 0x80, 0xbf, 0x71, 0xd7, 0xd2, 0x2c, 0xe2, 0x21, 0xcd, 0x22, 0xae, 0x8b, 0x2c, + 0x8a, 0x89, 0xab, 0x8d, 0xaa, 0xb1, 0xae, 0x32, 0xf0, 0x08, 0x25, 0xf0, 0x37, 0xdc, 0xb5, 0x2a, + 0x01, 0xb1, 0x12, 0x83, 0x46, 0xd5, 0x52, 0xb1, 0x47, 0x7a, 0x24, 0xa4, 0x68, 0x41, 0xc5, 0xd8, + 0xa5, 0xb8, 0xad, 0xe3, 0x60, 0xea, 0x20, 0x97, 0x32, 0xdb, 0x79, 0xc7, 0x88, 0xea, 0x7b, 0x1e, + 0xe4, 0xeb, 0x0b, 0xc3, 0x86, 0x6b, 0xc3, 0x2a, 0xc8, 0x5a, 0x7d, 0x8c, 0x5c, 0xda, 0xc1, 0xb6, + 0xc8, 0x29, 0x5c, 0x39, 0x5b, 0x2b, 0xce, 0xa6, 0x72, 0x61, 0x62, 0x3a, 0xfd, 0x6d, 0x75, 0x01, + 0xa9, 0x46, 0x86, 0xd5, 0xba, 0x0d, 0x1f, 0x81, 0xcc, 0x08, 0x79, 0x3e, 0x26, 0xae, 0x2f, 0xf2, + 0x4a, 0xb2, 0x9c, 0xdb, 0x94, 0x2b, 0x5f, 0x1f, 0xb7, 0x72, 0xc0, 0x78, 0xc6, 0x42, 0x00, 0xb7, + 0x40, 0xca, 0xa7, 0x26, 0x45, 0x62, 0x52, 0xe1, 0xca, 0x3f, 0x6d, 0xae, 0xdf, 0xa5, 0xdc, 0x0b, + 0x48, 0x06, 0xe3, 0xc2, 0x26, 0x58, 0xb5, 0xc8, 0xd0, 0xa5, 0xc8, 0x1b, 0x98, 0x1e, 0x9d, 0x88, + 0x82, 0xc2, 0x95, 0x73, 0x9b, 0x7f, 0xde, 0xa5, 0xad, 0xc7, 0xb8, 0x35, 0xe1, 0x62, 0x2a, 0x27, + 0x8c, 0x1b, 0x7a, 0xb8, 0x0d, 0x56, 0x6d, 0xd4, 0x37, 0x27, 0x9d, 0x01, 0xf2, 0x30, 0xb1, 0xc5, + 0x94, 0xc2, 0x95, 0x85, 0xda, 0xda, 0x6c, 0x2a, 0xff, 0xca, 0xf6, 0x8e, 0xa3, 0xaa, 0x91, 0x0b, + 0xdb, 0x56, 0xd8, 0x6d, 0x0b, 0xa7, 0x6f, 0xe5, 0x84, 0xfa, 0x99, 0x07, 0x45, 0xdd, 0x46, 0x2e, + 0xc5, 0x47, 0x18, 0xd9, 0xcb, 0x48, 0xe1, 0x3a, 0xe0, 0x17, 0x41, 0xe6, 0x67, 0x53, 0x39, 0xcb, + 0x0c, 0x83, 0x04, 0x79, 0x7c, 0x2b, 0x6e, 0xfe, 0xde, 0x71, 0x27, 0x1f, 0x1c, 0xb7, 0xf0, 0x1d, + 0x71, 0xa7, 0x7e, 0x70, 0xdc, 0xe9, 0x7b, 0xc7, 0xfd, 0x81, 0x03, 0xab, 0xf1, 0x8f, 0x79, 0xc8, + 0xd9, 0x3e, 0x01, 0xf9, 0xe5, 0xdc, 0xcb, 0xf8, 0xc5, 0xd9, 0x54, 0x2e, 0x46, 0xb2, 0x38, 0xac, + 0x06, 0x4b, 0xcc, 0x7b, 0xdd, 0x86, 0x35, 0x90, 0x1e, 0x78, 0xe8, 0x08, 0x8f, 0xc3, 0xcb, 0xbd, + 0x15, 0xc7, 0xe2, 0x67, 0x36, 0xaa, 0x56, 0x5e, 0x20, 0xef, 0xa4, 0x8f, 0x5a, 0x21, 0x37, 0x8a, + 0x23, 0x52, 0x46, 0xcb, 0xfc, 0x01, 0x72, 0xf5, 0x70, 0xa8, 0x96, 0x49, 0x8f, 0x7d, 0x58, 0x04, + 0xa9, 0x41, 0x50, 0x88, 0x9c, 0x92, 0x2c, 0x67, 0x0d, 0xd6, 0xa8, 0x87, 0xe0, 0xe7, 0xe5, 0x55, + 0x31, 0xe2, 0x03, 0x76, 0x5e, 0x78, 0xf3, 0x71, 0xef, 0x67, 0x60, 0x25, 0xba, 0x14, 0x28, 0x01, + 0x80, 0xe7, 0x67, 0xec, 0x31, 0x53, 0x23, 0xf6, 0x04, 0x96, 0x40, 0xe6, 0x08, 0x99, 0x74, 0xe8, + 0xa1, 0xb9, 0xc7, 0xa2, 0x8f, 0xb6, 0x71, 0x41, 0xba, 0x65, 0x7a, 0xa6, 0xe3, 0x43, 0x1b, 0xfc, + 0xee, 0x98, 0xe3, 0x0e, 0x1a, 0x0f, 0x90, 0x45, 0x91, 0xdd, 0xa1, 0xd8, 0x41, 0xc1, 0x97, 0xda, + 0xe9, 0xf6, 0x89, 0x75, 0x12, 0x9a, 0x0b, 0xb5, 0xbf, 0x66, 0x53, 0x59, 0x65, 0x13, 0x7f, 0x83, + 0xac, 0x1a, 0x6b, 0x8e, 0x39, 0x6e, 0x44, 0x60, 0x1b, 0x3b, 0xa8, 0x85, 0xbc, 0x5a, 0x80, 0xfc, + 0xf3, 0x86, 0x03, 0xa9, 0xf0, 0x5a, 0xe1, 0xff, 0x40, 0xde, 0x6b, 0xef, 0xb4, 0x1b, 0x9d, 0xfd, + 0xa6, 0xde, 0xd4, 0xdb, 0xfa, 0xce, 0x73, 0xfd, 0xb0, 0xb1, 0xdb, 0xd9, 0x6f, 0xee, 0xb5, 0x1a, + 0x75, 0xfd, 0xa9, 0xde, 0xd8, 0x2d, 0x24, 0x4a, 0xbf, 0x9c, 0x9d, 0x2b, 0xf9, 0x1b, 0x04, 0x28, + 0x02, 0xc0, 0x74, 0xc1, 0xc3, 0x02, 0x57, 0xca, 0x9c, 0x9d, 0x2b, 0x42, 0x50, 0x43, 0x09, 0xe4, + 0x19, 0xd2, 0x36, 0x5e, 0xbd, 0x6c, 0x35, 0x9a, 0x05, 0xbe, 0x94, 0x3b, 0x3b, 0x57, 0x56, 0xa2, + 0x76, 0xa9, 0x0c, 0xc1, 0x24, 0x53, 0x06, 0x75, 0x49, 0x38, 0x7d, 0x27, 0x25, 0x6a, 0x07, 0x17, + 0x57, 0x12, 0x77, 0x79, 0x25, 0x71, 0x9f, 0xae, 0x24, 0xee, 0xf5, 0xb5, 0x94, 0xb8, 0xbc, 0x96, + 0x12, 0x1f, 0xaf, 0xa5, 0xc4, 0xe1, 0xe3, 0x1e, 0xa6, 0xc7, 0xc3, 0x6e, 0x70, 0x2a, 0x9a, 0x45, + 0x7c, 0x87, 0xf8, 0x1a, 0xee, 0x5a, 0x1b, 0x3d, 0xa2, 0x8d, 0xfe, 0xd3, 0x1c, 0x62, 0x0f, 0xfb, + 0xc8, 0x67, 0x6f, 0xf0, 0x7f, 0xb7, 0x36, 0x62, 0xff, 0x0d, 0x74, 0x32, 0x40, 0x7e, 0x37, 0x1d, + 0xbe, 0xbd, 0xb7, 0xbe, 0x04, 0x00, 0x00, 0xff, 0xff, 0xfc, 0x2c, 0xbf, 0x64, 0x3f, 0x06, 0x00, + 0x00, } func (m *ConnectionEnd) Marshal() (dAtA []byte, err error) { diff --git a/modules/core/03-connection/types/connection_test.go b/modules/core/03-connection/types/connection_test.go index 08c90be9951..f844052f5c8 100644 --- a/modules/core/03-connection/types/connection_test.go +++ b/modules/core/03-connection/types/connection_test.go @@ -5,10 +5,10 @@ import ( "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var ( diff --git a/modules/core/03-connection/types/events.go b/modules/core/03-connection/types/events.go index 10fdbeff391..5afbb5fb904 100644 --- a/modules/core/03-connection/types/events.go +++ b/modules/core/03-connection/types/events.go @@ -3,7 +3,7 @@ package types import ( "fmt" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // IBC connection events diff --git a/modules/core/03-connection/types/expected_keepers.go b/modules/core/03-connection/types/expected_keepers.go index 05495181222..fdb248423b5 100644 --- a/modules/core/03-connection/types/expected_keepers.go +++ b/modules/core/03-connection/types/expected_keepers.go @@ -3,7 +3,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // ClientKeeper expected account IBC client keeper diff --git a/modules/core/03-connection/types/genesis.go b/modules/core/03-connection/types/genesis.go index 3502c13eb59..9f6bab811e3 100644 --- a/modules/core/03-connection/types/genesis.go +++ b/modules/core/03-connection/types/genesis.go @@ -3,7 +3,7 @@ package types import ( "fmt" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // NewConnectionPaths creates a ConnectionPaths instance. diff --git a/modules/core/03-connection/types/genesis.pb.go b/modules/core/03-connection/types/genesis.pb.go index 777d8e50e7d..98fd5a14f67 100644 --- a/modules/core/03-connection/types/genesis.pb.go +++ b/modules/core/03-connection/types/genesis.pb.go @@ -102,30 +102,30 @@ func init() { } var fileDescriptor_1879d34bc6ac3cd7 = []byte{ - // 356 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x31, 0x4f, 0xf2, 0x40, - 0x18, 0xc7, 0xdb, 0x17, 0xc2, 0x50, 0xde, 0xa9, 0x51, 0x6c, 0x18, 0xae, 0xa4, 0x1a, 0x61, 0x90, - 0x3b, 0x81, 0xcd, 0x30, 0xd5, 0xc1, 0xb8, 0x11, 0x30, 0x0e, 0x26, 0x86, 0xb4, 0xc7, 0x63, 0xb9, - 0x84, 0xde, 0x55, 0xee, 0x20, 0xf2, 0x09, 0x1c, 0x5c, 0xfc, 0x58, 0x8c, 0x8c, 0x4e, 0xc4, 0xc0, - 0x37, 0xe0, 0x13, 0x98, 0xb6, 0xc4, 0xa2, 0xb1, 0x5b, 0xf3, 0x3c, 0xbf, 0xff, 0xef, 0x9f, 0xde, - 0x63, 0x9c, 0x31, 0x9f, 0x12, 0x2a, 0xa6, 0x40, 0xa8, 0xe0, 0x1c, 0xa8, 0x62, 0x82, 0x93, 0x79, - 0x8b, 0x04, 0xc0, 0x41, 0x32, 0x89, 0xa3, 0xa9, 0x50, 0xc2, 0xac, 0x30, 0x9f, 0xe2, 0x98, 0xc2, - 0x19, 0x85, 0xe7, 0xad, 0xea, 0x51, 0x20, 0x02, 0x91, 0x20, 0x24, 0xfe, 0x4a, 0xe9, 0x6a, 0x3d, - 0xc7, 0x79, 0x90, 0x4d, 0x40, 0xe7, 0xad, 0x60, 0xfc, 0xbf, 0x49, 0x8b, 0x06, 0xca, 0x53, 0x60, - 0xde, 0x19, 0xe5, 0x0c, 0x92, 0x96, 0x5e, 0x2b, 0x34, 0xca, 0xed, 0x0b, 0xfc, 0x77, 0x3b, 0xbe, - 0x1d, 0x01, 0x57, 0xec, 0x89, 0xc1, 0xe8, 0xfa, 0x7b, 0xee, 0x16, 0x97, 0x6b, 0x5b, 0xeb, 0x1f, - 0x6a, 0xcc, 0x57, 0xdd, 0x38, 0xa1, 0x13, 0x06, 0x5c, 0x0d, 0xb3, 0xf1, 0x30, 0xf2, 0xd4, 0x58, - 0x5a, 0xff, 0x92, 0x8a, 0x7a, 0x5e, 0x45, 0x26, 0xee, 0xc5, 0xb8, 0x7b, 0x1e, 0xdb, 0x77, 0x6b, - 0x1b, 0x2d, 0xbc, 0x70, 0x72, 0xe5, 0xe4, 0x58, 0x9d, 0xfe, 0x71, 0xba, 0xf9, 0x15, 0x37, 0x1f, - 0x0d, 0x8b, 0xc3, 0xcb, 0x8f, 0x80, 0x84, 0xe7, 0x19, 0x70, 0x0a, 0x56, 0xa1, 0xa6, 0x37, 0x8a, - 0xee, 0xe9, 0x6e, 0x6d, 0xdb, 0xa9, 0x3c, 0x8f, 0x74, 0xfa, 0x95, 0x78, 0x95, 0xb9, 0x07, 0xfb, - 0x85, 0xd9, 0x35, 0x4a, 0x91, 0x37, 0xf5, 0x42, 0x69, 0x15, 0x6b, 0x7a, 0xa3, 0xdc, 0x46, 0x79, - 0xbf, 0xd5, 0x4b, 0xa8, 0xfd, 0x5b, 0xed, 0x33, 0xee, 0xfd, 0x72, 0x83, 0xf4, 0xd5, 0x06, 0xe9, - 0x9f, 0x1b, 0xa4, 0xbf, 0x6f, 0x91, 0xb6, 0xda, 0x22, 0xed, 0x63, 0x8b, 0xb4, 0x87, 0x6e, 0xc0, - 0xd4, 0x78, 0xe6, 0x63, 0x2a, 0x42, 0x42, 0x85, 0x0c, 0x85, 0x24, 0xcc, 0xa7, 0xcd, 0x40, 0x90, - 0x79, 0x87, 0x84, 0x62, 0x34, 0x9b, 0x80, 0x4c, 0x0f, 0x7e, 0xd9, 0x69, 0x1e, 0xdc, 0x5c, 0x2d, - 0x22, 0x90, 0x7e, 0x29, 0x39, 0x76, 0xe7, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x2d, 0x04, 0xad, 0xb7, - 0x6b, 0x02, 0x00, 0x00, + // 358 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xc1, 0x4e, 0xea, 0x40, + 0x14, 0x86, 0xdb, 0x0b, 0x61, 0x51, 0xee, 0xaa, 0xb9, 0x17, 0x1b, 0x16, 0x53, 0x52, 0x8d, 0xb0, + 0x90, 0x19, 0x01, 0x57, 0x86, 0x55, 0x5d, 0x18, 0x77, 0x04, 0x8c, 0x0b, 0x13, 0x43, 0xda, 0xe1, + 0x58, 0x26, 0xa1, 0x33, 0x95, 0x19, 0x88, 0x3c, 0x81, 0x0b, 0x37, 0x3e, 0x16, 0x4b, 0x96, 0xae, + 0x88, 0x81, 0x37, 0xe0, 0x09, 0x4c, 0x5b, 0x62, 0xd1, 0xd8, 0x5d, 0x73, 0xce, 0xf7, 0x7f, 0x7f, + 0x3a, 0xc7, 0x38, 0x61, 0x3e, 0x25, 0x54, 0x4c, 0x81, 0x50, 0xc1, 0x39, 0x50, 0xc5, 0x04, 0x27, + 0xf3, 0x16, 0x09, 0x80, 0x83, 0x64, 0x12, 0x47, 0x53, 0xa1, 0x84, 0x59, 0x61, 0x3e, 0xc5, 0x31, + 0x85, 0x33, 0x0a, 0xcf, 0x5b, 0xd5, 0x7f, 0x81, 0x08, 0x44, 0x82, 0x90, 0xf8, 0x2b, 0xa5, 0xab, + 0xf5, 0x1c, 0xe7, 0x41, 0x36, 0x01, 0x9d, 0xd7, 0x82, 0xf1, 0xf7, 0x3a, 0x2d, 0x1a, 0x28, 0x4f, + 0x81, 0x79, 0x6b, 0x94, 0x33, 0x48, 0x5a, 0x7a, 0xad, 0xd0, 0x28, 0xb7, 0xcf, 0xf0, 0xef, 0xed, + 0xf8, 0x66, 0x04, 0x5c, 0xb1, 0x47, 0x06, 0xa3, 0xab, 0xaf, 0xb9, 0x5b, 0x5c, 0xae, 0x6d, 0xad, + 0x7f, 0xa8, 0x31, 0x5f, 0x74, 0xe3, 0x88, 0x4e, 0x18, 0x70, 0x35, 0xcc, 0xc6, 0xc3, 0xc8, 0x53, + 0x63, 0x69, 0xfd, 0x49, 0x2a, 0xea, 0x79, 0x15, 0x99, 0xb8, 0x17, 0xe3, 0xee, 0x69, 0x6c, 0xdf, + 0xad, 0x6d, 0xb4, 0xf0, 0xc2, 0xc9, 0xa5, 0x93, 0x63, 0x75, 0xfa, 0xff, 0xd3, 0xcd, 0x8f, 0xb8, + 0xf9, 0x60, 0x58, 0x1c, 0x9e, 0xbf, 0x05, 0x24, 0x3c, 0xcd, 0x80, 0x53, 0xb0, 0x0a, 0x35, 0xbd, + 0x51, 0x74, 0x8f, 0x77, 0x6b, 0xdb, 0x4e, 0xe5, 0x79, 0xa4, 0xd3, 0xaf, 0xc4, 0xab, 0xcc, 0x3d, + 0xd8, 0x2f, 0xcc, 0xae, 0x51, 0x8a, 0xbc, 0xa9, 0x17, 0x4a, 0xab, 0x58, 0xd3, 0x1b, 0xe5, 0x36, + 0xca, 0xfb, 0xad, 0x5e, 0x42, 0xed, 0xdf, 0x6a, 0x9f, 0x71, 0xef, 0x96, 0x1b, 0xa4, 0xaf, 0x36, + 0x48, 0xff, 0xd8, 0x20, 0xfd, 0x6d, 0x8b, 0xb4, 0xd5, 0x16, 0x69, 0xef, 0x5b, 0xa4, 0xdd, 0x77, + 0x03, 0xa6, 0xc6, 0x33, 0x1f, 0x53, 0x11, 0x12, 0x2a, 0x64, 0x28, 0x24, 0x61, 0x3e, 0x6d, 0x06, + 0x82, 0xcc, 0x2f, 0x48, 0x28, 0x46, 0xb3, 0x09, 0xc8, 0xf4, 0xe0, 0xe7, 0x9d, 0xe6, 0xc1, 0xcd, + 0xd5, 0x22, 0x02, 0xe9, 0x97, 0x92, 0x63, 0x77, 0x3e, 0x03, 0x00, 0x00, 0xff, 0xff, 0x25, 0x96, + 0xe3, 0x66, 0x6b, 0x02, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/modules/core/03-connection/types/genesis_test.go b/modules/core/03-connection/types/genesis_test.go index 31906350531..eec0a61c9af 100644 --- a/modules/core/03-connection/types/genesis_test.go +++ b/modules/core/03-connection/types/genesis_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func TestValidateGenesis(t *testing.T) { diff --git a/modules/core/03-connection/types/keys.go b/modules/core/03-connection/types/keys.go index e7ed7a943f3..eaf6eb18e97 100644 --- a/modules/core/03-connection/types/keys.go +++ b/modules/core/03-connection/types/keys.go @@ -6,7 +6,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) const ( diff --git a/modules/core/03-connection/types/keys_test.go b/modules/core/03-connection/types/keys_test.go index b0478d00703..1df435836da 100644 --- a/modules/core/03-connection/types/keys_test.go +++ b/modules/core/03-connection/types/keys_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) // tests ParseConnectionSequence and IsValidConnectionID diff --git a/modules/core/03-connection/types/msgs.go b/modules/core/03-connection/types/msgs.go index 3ea63c84d37..fb410d095b2 100644 --- a/modules/core/03-connection/types/msgs.go +++ b/modules/core/03-connection/types/msgs.go @@ -5,10 +5,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( diff --git a/modules/core/03-connection/types/msgs_test.go b/modules/core/03-connection/types/msgs_test.go index b6f4544b98f..8c4945973bf 100644 --- a/modules/core/03-connection/types/msgs_test.go +++ b/modules/core/03-connection/types/msgs_test.go @@ -12,12 +12,12 @@ import ( abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tm-db" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - "github.com/cosmos/ibc-go/v3/testing/simapp" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) var ( diff --git a/modules/core/03-connection/types/params_test.go b/modules/core/03-connection/types/params_test.go index 28c4311ff94..fa8e61a7556 100644 --- a/modules/core/03-connection/types/params_test.go +++ b/modules/core/03-connection/types/params_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" ) func TestValidateParams(t *testing.T) { diff --git a/modules/core/03-connection/types/query.go b/modules/core/03-connection/types/query.go index 2cae95934b6..095995cec63 100644 --- a/modules/core/03-connection/types/query.go +++ b/modules/core/03-connection/types/query.go @@ -3,8 +3,8 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( diff --git a/modules/core/03-connection/types/query.pb.go b/modules/core/03-connection/types/query.pb.go index a3d5cf40410..b180904f9c5 100644 --- a/modules/core/03-connection/types/query.pb.go +++ b/modules/core/03-connection/types/query.pb.go @@ -8,7 +8,7 @@ import ( fmt "fmt" types1 "github.com/cosmos/cosmos-sdk/codec/types" query "github.com/cosmos/cosmos-sdk/types/query" - types "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + types "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -638,60 +638,60 @@ var fileDescriptor_cd8d529f8c7cd06b = []byte{ // 895 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x31, 0x6f, 0x23, 0x45, 0x14, 0xf6, 0x38, 0xb9, 0xd3, 0x65, 0x1c, 0xee, 0x60, 0xe4, 0xbb, 0x33, 0x0b, 0x38, 0x61, 0x8f, - 0x90, 0x1c, 0x70, 0x33, 0xe7, 0x58, 0x77, 0x3a, 0x8e, 0x18, 0x81, 0xa3, 0x40, 0xd2, 0x44, 0x61, - 0x91, 0x28, 0x68, 0xa2, 0xdd, 0xf5, 0x64, 0xbd, 0x92, 0xbd, 0xe3, 0x78, 0xd6, 0x46, 0x56, 0x64, - 0x21, 0xf1, 0x07, 0x40, 0xa2, 0xa1, 0xa1, 0xa5, 0xe0, 0x0f, 0x50, 0xd0, 0x51, 0xa5, 0x8c, 0x44, - 0x93, 0x2a, 0x42, 0x0e, 0x2d, 0x0d, 0xbf, 0x00, 0xed, 0xcc, 0x38, 0x3b, 0x6b, 0xaf, 0x13, 0xc7, - 0x22, 0xdd, 0xe6, 0xcd, 0x7b, 0xf3, 0xbe, 0xef, 0x7b, 0x6f, 0x3e, 0x07, 0x9a, 0xbe, 0xe3, 0x12, - 0x97, 0xb5, 0x29, 0x71, 0x59, 0x10, 0x50, 0x37, 0xf4, 0x59, 0x40, 0xba, 0x25, 0x72, 0xd8, 0xa1, - 0xed, 0x1e, 0x6e, 0xb5, 0x59, 0xc8, 0xd0, 0x03, 0xdf, 0x71, 0x71, 0x94, 0x83, 0xe3, 0x1c, 0xdc, - 0x2d, 0x19, 0x79, 0x8f, 0x79, 0x4c, 0xa4, 0x90, 0xe8, 0x4b, 0x66, 0x1b, 0xef, 0xb9, 0x8c, 0x37, - 0x19, 0x27, 0x8e, 0xcd, 0xa9, 0xbc, 0x86, 0x74, 0x4b, 0x0e, 0x0d, 0xed, 0x12, 0x69, 0xd9, 0x9e, - 0x1f, 0xd8, 0xa2, 0x5c, 0xe6, 0x2e, 0xc5, 0xdd, 0x1b, 0x3e, 0x0d, 0xc2, 0xa8, 0xb3, 0xfc, 0x52, - 0x09, 0xab, 0x13, 0xe0, 0x69, 0x40, 0x64, 0xe2, 0x9b, 0x1e, 0x63, 0x5e, 0x83, 0x12, 0xbb, 0xe5, - 0x13, 0x3b, 0x08, 0x58, 0x28, 0xda, 0x70, 0x75, 0xfa, 0xba, 0x3a, 0x15, 0x7f, 0x39, 0x9d, 0x03, - 0x62, 0x07, 0x8a, 0x9c, 0x59, 0x81, 0x0f, 0xbe, 0x88, 0x40, 0x6e, 0x5e, 0xdc, 0x68, 0xd1, 0xc3, - 0x0e, 0xe5, 0x21, 0x7a, 0x04, 0x5f, 0x89, 0xdb, 0xec, 0xfb, 0xb5, 0x02, 0x58, 0x06, 0x6b, 0x0b, - 0xd6, 0x62, 0x1c, 0xdc, 0xa9, 0x99, 0xbf, 0x03, 0xf8, 0x70, 0xac, 0x9e, 0xb7, 0x58, 0xc0, 0x29, - 0xda, 0x82, 0x30, 0xce, 0x15, 0xd5, 0xb9, 0xf5, 0x15, 0x9c, 0x2e, 0x26, 0x8e, 0xeb, 0xb7, 0x82, - 0x9a, 0xa5, 0x15, 0xa2, 0x3c, 0xbc, 0xd5, 0x6a, 0x33, 0x76, 0x50, 0xc8, 0x2e, 0x83, 0xb5, 0x45, - 0x4b, 0xfe, 0x81, 0x36, 0xe1, 0xa2, 0xf8, 0xd8, 0xaf, 0x53, 0xdf, 0xab, 0x87, 0x85, 0x39, 0x71, - 0xbd, 0xa1, 0x5d, 0x2f, 0x75, 0xec, 0x96, 0xf0, 0xb6, 0xc8, 0xa8, 0xce, 0x1f, 0x9f, 0x2d, 0x65, - 0xac, 0x9c, 0xa8, 0x92, 0x21, 0xd3, 0x1e, 0x03, 0xcf, 0x87, 0xec, 0x3f, 0x83, 0x30, 0x1e, 0x97, + 0x90, 0x1c, 0x70, 0x33, 0xe7, 0x84, 0x3b, 0x1d, 0x21, 0x46, 0xe0, 0x28, 0x90, 0x34, 0x51, 0x58, + 0x24, 0x0a, 0x9a, 0x68, 0x77, 0x3d, 0x59, 0xaf, 0x64, 0xef, 0x38, 0x9e, 0xb5, 0x91, 0x15, 0x59, + 0x48, 0xfc, 0x01, 0x90, 0x68, 0x68, 0x68, 0x29, 0xf8, 0x03, 0x14, 0x74, 0x54, 0x29, 0x23, 0xd1, + 0xa4, 0x8a, 0x90, 0x43, 0x4b, 0xc3, 0x2f, 0x40, 0x3b, 0x33, 0xce, 0xce, 0xda, 0xeb, 0xc4, 0xb1, + 0x2e, 0xdd, 0xe6, 0xcd, 0x7b, 0xf3, 0xbe, 0xef, 0x7b, 0x6f, 0x3e, 0x07, 0x9a, 0xbe, 0xe3, 0x12, + 0x97, 0xb5, 0x28, 0x71, 0x59, 0x10, 0x50, 0x37, 0xf4, 0x59, 0x40, 0x3a, 0x25, 0x72, 0xd8, 0xa6, + 0xad, 0x2e, 0x6e, 0xb6, 0x58, 0xc8, 0xd0, 0x03, 0xdf, 0x71, 0x71, 0x94, 0x83, 0xe3, 0x1c, 0xdc, + 0x29, 0x19, 0x79, 0x8f, 0x79, 0x4c, 0xa4, 0x90, 0xe8, 0x4b, 0x66, 0x1b, 0xef, 0xb9, 0x8c, 0x37, + 0x18, 0x27, 0x8e, 0xcd, 0xa9, 0xbc, 0x86, 0x74, 0x4a, 0x0e, 0x0d, 0xed, 0x12, 0x69, 0xda, 0x9e, + 0x1f, 0xd8, 0xa2, 0x5c, 0xe6, 0x2e, 0xc4, 0xdd, 0xeb, 0x3e, 0x0d, 0xc2, 0xa8, 0xb3, 0xfc, 0x52, + 0x09, 0xcb, 0x63, 0xe0, 0x69, 0x40, 0x64, 0xe2, 0x9b, 0x1e, 0x63, 0x5e, 0x9d, 0x12, 0xbb, 0xe9, + 0x13, 0x3b, 0x08, 0x58, 0x28, 0xda, 0x70, 0x75, 0xfa, 0xba, 0x3a, 0x15, 0x7f, 0x39, 0xed, 0x03, + 0x62, 0x07, 0x8a, 0x9c, 0x59, 0x86, 0x0f, 0xbe, 0x8c, 0x40, 0x6e, 0x5e, 0xdc, 0x68, 0xd1, 0xc3, + 0x36, 0xe5, 0x21, 0x7a, 0x04, 0x5f, 0x89, 0xdb, 0xec, 0xfb, 0xd5, 0x02, 0x58, 0x04, 0x2b, 0x73, + 0xd6, 0x7c, 0x1c, 0xdc, 0xa9, 0x9a, 0x7f, 0x00, 0xf8, 0x70, 0xa4, 0x9e, 0x37, 0x59, 0xc0, 0x29, + 0xda, 0x82, 0x30, 0xce, 0x15, 0xd5, 0xb9, 0xd5, 0x25, 0x9c, 0x2e, 0x26, 0x8e, 0xeb, 0xb7, 0x82, + 0xaa, 0xa5, 0x15, 0xa2, 0x3c, 0xbc, 0xd5, 0x6c, 0x31, 0x76, 0x50, 0xc8, 0x2e, 0x82, 0x95, 0x79, + 0x4b, 0xfe, 0x81, 0x36, 0xe1, 0xbc, 0xf8, 0xd8, 0xaf, 0x51, 0xdf, 0xab, 0x85, 0x85, 0x19, 0x71, + 0xbd, 0xa1, 0x5d, 0x2f, 0x75, 0xec, 0x94, 0xf0, 0xb6, 0xc8, 0xa8, 0xcc, 0x1e, 0x9f, 0x2d, 0x64, + 0xac, 0x9c, 0xa8, 0x92, 0x21, 0xd3, 0x1e, 0x01, 0xcf, 0x07, 0xec, 0x3f, 0x87, 0x30, 0x1e, 0x97, 0x02, 0xff, 0x2e, 0x96, 0xb3, 0xc5, 0xd1, 0x6c, 0xb1, 0x5c, 0x11, 0x35, 0x5b, 0xbc, 0x67, 0x7b, - 0x54, 0xd5, 0x5a, 0x5a, 0xa5, 0xf9, 0x0f, 0x80, 0x85, 0xf1, 0x1e, 0x4a, 0xa1, 0x5d, 0x98, 0x8b, - 0x89, 0xf2, 0x02, 0x58, 0x9e, 0x5b, 0xcb, 0xad, 0x7f, 0x30, 0x49, 0xa2, 0x9d, 0x1a, 0x0d, 0x42, - 0xff, 0xc0, 0xa7, 0x35, 0x4d, 0x6c, 0xfd, 0x02, 0xf4, 0x79, 0x02, 0x74, 0x56, 0x80, 0x5e, 0xbd, + 0x54, 0xd5, 0x5a, 0x5a, 0xa5, 0xf9, 0x2f, 0x80, 0x85, 0xd1, 0x1e, 0x4a, 0xa1, 0x5d, 0x98, 0x8b, + 0x89, 0xf2, 0x02, 0x58, 0x9c, 0x59, 0xc9, 0xad, 0x7e, 0x30, 0x4e, 0xa2, 0x9d, 0x2a, 0x0d, 0x42, + 0xff, 0xc0, 0xa7, 0x55, 0x4d, 0x6c, 0xfd, 0x02, 0xf4, 0x45, 0x02, 0x74, 0x56, 0x80, 0x5e, 0xbe, 0x12, 0xb4, 0x04, 0xa3, 0xa3, 0x46, 0x2f, 0xe0, 0xed, 0x6b, 0xea, 0xaa, 0xf2, 0xcd, 0x0d, 0xf8, - 0x96, 0xa4, 0x2b, 0xd2, 0x52, 0x84, 0x7d, 0x03, 0x2e, 0xc8, 0x2b, 0xe2, 0x95, 0xba, 0x23, 0x03, - 0x3b, 0x35, 0xf3, 0x17, 0x00, 0x8b, 0x93, 0xca, 0x95, 0x66, 0x8f, 0xe1, 0xab, 0xda, 0x5a, 0xb6, - 0xec, 0xb0, 0x2e, 0x85, 0x5b, 0xb0, 0xee, 0xc5, 0xf1, 0xbd, 0x28, 0x7c, 0x93, 0x9b, 0xe3, 0xc0, - 0xb7, 0x47, 0xa6, 0x2a, 0x11, 0x7f, 0x19, 0xda, 0xe1, 0x70, 0x0f, 0x50, 0x25, 0xf5, 0x05, 0x55, - 0x0b, 0xff, 0x9e, 0x2d, 0xe5, 0x7b, 0x76, 0xb3, 0xf1, 0xd2, 0x4c, 0x1c, 0x9b, 0x23, 0x6f, 0x6b, - 0x00, 0xa0, 0x79, 0x59, 0x13, 0x25, 0x88, 0x0d, 0x1f, 0xfa, 0x17, 0x9b, 0xb1, 0xaf, 0xb4, 0xe5, - 0x51, 0x8a, 0x5a, 0xdb, 0xc7, 0x69, 0xd4, 0xb4, 0x65, 0xd2, 0xee, 0xbc, 0xef, 0xa7, 0x85, 0x6f, - 0x52, 0xc8, 0xdf, 0x00, 0x7c, 0x67, 0x94, 0x64, 0x44, 0x2b, 0xe0, 0x1d, 0xfe, 0x3f, 0x8a, 0x89, - 0x56, 0xe1, 0xbd, 0x36, 0xed, 0xfa, 0x3c, 0x3a, 0x0d, 0x3a, 0x4d, 0x87, 0xb6, 0x05, 0x99, 0x79, - 0xeb, 0xee, 0x30, 0xbc, 0x2b, 0xa2, 0x89, 0x44, 0x8d, 0x98, 0x96, 0xa8, 0x90, 0x9f, 0x01, 0xb8, - 0x72, 0x05, 0x72, 0x35, 0xa1, 0x0a, 0x8c, 0x56, 0x53, 0x9e, 0x24, 0x26, 0x93, 0xc7, 0xd2, 0x98, - 0xf1, 0xd0, 0x98, 0xf1, 0xa7, 0x41, 0xcf, 0xba, 0xeb, 0x26, 0xae, 0x49, 0xbe, 0x98, 0x6c, 0xf2, - 0xc5, 0xc4, 0xa3, 0x99, 0xbb, 0x6c, 0x34, 0xf3, 0x33, 0x8c, 0x66, 0xfd, 0xfb, 0x3b, 0xf0, 0x96, - 0x20, 0x88, 0x7e, 0x05, 0x10, 0xc6, 0x2c, 0x11, 0x9e, 0xe4, 0x50, 0xe9, 0xbf, 0x24, 0x06, 0x99, - 0x3a, 0x5f, 0x0a, 0x66, 0x7e, 0xf4, 0xdd, 0x9f, 0x7f, 0xff, 0x98, 0x7d, 0x86, 0xca, 0xe4, 0xca, - 0xdf, 0x3f, 0x4e, 0x8e, 0x12, 0x73, 0xef, 0xa3, 0x9f, 0x01, 0xcc, 0x69, 0xc6, 0x81, 0xa6, 0xed, - 0x3e, 0x74, 0x28, 0xe3, 0xe9, 0xf4, 0x05, 0x0a, 0xef, 0xfb, 0x02, 0xef, 0x0a, 0x7a, 0x34, 0x05, - 0x5e, 0xf4, 0x07, 0x80, 0xaf, 0x8d, 0xd9, 0x1b, 0x7a, 0x76, 0x79, 0xd3, 0x09, 0x6e, 0x6a, 0x3c, - 0xbf, 0x6e, 0x99, 0x42, 0xfc, 0xb1, 0x40, 0xfc, 0x02, 0x3d, 0x9f, 0x88, 0x58, 0x6e, 0x5c, 0x52, - 0xe8, 0xe1, 0x16, 0xf6, 0xd1, 0x29, 0x80, 0xf7, 0x53, 0x6d, 0x09, 0x7d, 0x38, 0xa5, 0x7a, 0xe3, - 0x7e, 0x69, 0xbc, 0x9c, 0xa5, 0x54, 0x11, 0xda, 0x16, 0x84, 0xaa, 0xe8, 0x93, 0x19, 0x56, 0x86, - 0xe8, 0xa6, 0x89, 0x7e, 0xca, 0xc2, 0xc2, 0xa4, 0x27, 0x8d, 0x36, 0xa6, 0x85, 0x98, 0xe6, 0x61, - 0x46, 0x65, 0xc6, 0x6a, 0xc5, 0xf1, 0x5b, 0xc1, 0xb1, 0x87, 0xbe, 0x99, 0x89, 0x63, 0xd2, 0x81, - 0xc8, 0xd0, 0xcd, 0xc8, 0xd1, 0x88, 0x2f, 0xf6, 0x89, 0x34, 0x0d, 0xed, 0x40, 0x06, 0xfa, 0xd5, - 0xaf, 0x8e, 0x07, 0x45, 0x70, 0x32, 0x28, 0x82, 0xbf, 0x06, 0x45, 0xf0, 0xc3, 0x79, 0x31, 0x73, - 0x72, 0x5e, 0xcc, 0x9c, 0x9e, 0x17, 0x33, 0x5f, 0x6f, 0x78, 0x7e, 0x58, 0xef, 0x38, 0xd8, 0x65, - 0x4d, 0xa2, 0xfe, 0x01, 0xf6, 0x1d, 0xf7, 0x89, 0xc7, 0x48, 0xb7, 0x4c, 0x9a, 0xac, 0xd6, 0x69, - 0x50, 0x2e, 0x11, 0x3f, 0x2d, 0x3f, 0xd1, 0x40, 0x87, 0xbd, 0x16, 0xe5, 0xce, 0x6d, 0xe1, 0x7f, - 0xe5, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xd7, 0xeb, 0x28, 0x8e, 0x0b, 0x00, 0x00, + 0x96, 0xa4, 0x2b, 0xd2, 0x52, 0x84, 0x7d, 0x03, 0xce, 0xc9, 0x2b, 0xe2, 0x95, 0xba, 0x23, 0x03, + 0x3b, 0x55, 0xf3, 0x57, 0x00, 0x8b, 0xe3, 0xca, 0x95, 0x66, 0x8f, 0xe1, 0xab, 0xda, 0x5a, 0x36, + 0xed, 0xb0, 0x26, 0x85, 0x9b, 0xb3, 0xee, 0xc5, 0xf1, 0xbd, 0x28, 0x7c, 0x93, 0x9b, 0xe3, 0xc0, + 0xb7, 0x87, 0xa6, 0x2a, 0x11, 0x7f, 0x15, 0xda, 0xe1, 0x60, 0x0f, 0x50, 0x39, 0xf5, 0x05, 0x55, + 0x0a, 0xff, 0x9d, 0x2d, 0xe4, 0xbb, 0x76, 0xa3, 0xbe, 0x6e, 0x26, 0x8e, 0xcd, 0xa1, 0xb7, 0xd5, + 0x07, 0xd0, 0xbc, 0xac, 0x89, 0x12, 0xc4, 0x86, 0x0f, 0xfd, 0x8b, 0xcd, 0xd8, 0x57, 0xda, 0xf2, + 0x28, 0x45, 0xad, 0xed, 0xe3, 0x34, 0x6a, 0xda, 0x32, 0x69, 0x77, 0xde, 0xf7, 0xd3, 0xc2, 0x37, + 0x29, 0xe4, 0xef, 0x00, 0xbe, 0x33, 0x4c, 0x32, 0xa2, 0x15, 0xf0, 0x36, 0x7f, 0x89, 0x62, 0xa2, + 0x65, 0x78, 0xaf, 0x45, 0x3b, 0x3e, 0x8f, 0x4e, 0x83, 0x76, 0xc3, 0xa1, 0x2d, 0x41, 0x66, 0xd6, + 0xba, 0x3b, 0x08, 0xef, 0x8a, 0x68, 0x22, 0x51, 0x23, 0xa6, 0x25, 0x2a, 0xe4, 0x67, 0x00, 0x2e, + 0x5d, 0x81, 0x5c, 0x4d, 0xa8, 0x0c, 0xa3, 0xd5, 0x94, 0x27, 0x89, 0xc9, 0xe4, 0xb1, 0x34, 0x66, + 0x3c, 0x30, 0x66, 0xfc, 0x59, 0xd0, 0xb5, 0xee, 0xba, 0x89, 0x6b, 0x92, 0x2f, 0x26, 0x9b, 0x7c, + 0x31, 0xf1, 0x68, 0x66, 0x2e, 0x1b, 0xcd, 0xec, 0x14, 0xa3, 0x59, 0xfd, 0xe1, 0x0e, 0xbc, 0x25, + 0x08, 0xa2, 0xdf, 0x00, 0x84, 0x31, 0x4b, 0x84, 0xc7, 0x39, 0x54, 0xfa, 0x2f, 0x89, 0x41, 0x26, + 0xce, 0x97, 0x82, 0x99, 0x1f, 0x7f, 0xff, 0xd7, 0x3f, 0x3f, 0x65, 0x9f, 0xa1, 0x35, 0x72, 0xe5, + 0xef, 0x1f, 0x27, 0x47, 0x89, 0xb9, 0xf7, 0xd0, 0x2f, 0x00, 0xe6, 0x34, 0xe3, 0x40, 0x93, 0x76, + 0x1f, 0x38, 0x94, 0xf1, 0x74, 0xf2, 0x02, 0x85, 0xf7, 0x7d, 0x81, 0x77, 0x09, 0x3d, 0x9a, 0x00, + 0x2f, 0xfa, 0x13, 0xc0, 0xd7, 0x46, 0xec, 0x0d, 0x3d, 0xbb, 0xbc, 0xe9, 0x18, 0x37, 0x35, 0x9e, + 0x5f, 0xb7, 0x4c, 0x21, 0xfe, 0x44, 0x20, 0x7e, 0x81, 0x9e, 0x8f, 0x45, 0x2c, 0x37, 0x2e, 0x29, + 0xf4, 0x60, 0x0b, 0x7b, 0xe8, 0x14, 0xc0, 0xfb, 0xa9, 0xb6, 0x84, 0x3e, 0x9a, 0x50, 0xbd, 0x51, + 0xbf, 0x34, 0xd6, 0xa7, 0x29, 0x55, 0x84, 0xb6, 0x05, 0xa1, 0x0a, 0xfa, 0x74, 0x8a, 0x95, 0x21, + 0xba, 0x69, 0xa2, 0x9f, 0xb3, 0xb0, 0x30, 0xee, 0x49, 0xa3, 0x8d, 0x49, 0x21, 0xa6, 0x79, 0x98, + 0x51, 0x9e, 0xb2, 0x5a, 0x71, 0xfc, 0x4e, 0x70, 0xec, 0xa2, 0x6f, 0xa7, 0xe2, 0x98, 0x74, 0x20, + 0x32, 0x70, 0x33, 0x72, 0x34, 0xe4, 0x8b, 0x3d, 0x22, 0x4d, 0x43, 0x3b, 0x90, 0x81, 0x5e, 0xe5, + 0xeb, 0xe3, 0x7e, 0x11, 0x9c, 0xf4, 0x8b, 0xe0, 0xef, 0x7e, 0x11, 0xfc, 0x78, 0x5e, 0xcc, 0x9c, + 0x9c, 0x17, 0x33, 0xa7, 0xe7, 0xc5, 0xcc, 0x37, 0x1b, 0x9e, 0x1f, 0xd6, 0xda, 0x0e, 0x76, 0x59, + 0x83, 0xa8, 0x7f, 0x80, 0x7d, 0xc7, 0x7d, 0xe2, 0x31, 0xd2, 0xf9, 0x90, 0x34, 0x58, 0xb5, 0x5d, + 0xa7, 0x5c, 0x22, 0x7e, 0xba, 0xf6, 0x44, 0x03, 0x1d, 0x76, 0x9b, 0x94, 0x3b, 0xb7, 0x85, 0xff, + 0xad, 0xfd, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x76, 0x45, 0xa5, 0xf9, 0x8e, 0x0b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/03-connection/types/tx.pb.go b/modules/core/03-connection/types/tx.pb.go index 3e332e51c4b..a37505743fb 100644 --- a/modules/core/03-connection/types/tx.pb.go +++ b/modules/core/03-connection/types/tx.pb.go @@ -7,7 +7,7 @@ import ( context "context" fmt "fmt" types "github.com/cosmos/cosmos-sdk/codec/types" - types1 "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + types1 "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -391,7 +391,7 @@ var fileDescriptor_5d00fde5fc97399e = []byte{ // 927 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x31, 0x73, 0xe3, 0x44, 0x14, 0xb6, 0x62, 0x27, 0xb1, 0xd7, 0x86, 0xbb, 0x5b, 0x9c, 0x44, 0x98, 0x3b, 0xcb, 0xa7, 0x81, - 0x21, 0x05, 0x91, 0xce, 0x97, 0x63, 0x06, 0x32, 0x50, 0xc4, 0x6e, 0x48, 0x71, 0x70, 0x23, 0x6e, + 0x21, 0x05, 0x91, 0xce, 0x77, 0x61, 0x06, 0x32, 0x50, 0xc4, 0x6e, 0x48, 0x71, 0x70, 0x23, 0x6e, 0x8e, 0x99, 0x6b, 0x3c, 0xf6, 0x7a, 0xa3, 0xec, 0xd8, 0xd6, 0x6a, 0xb4, 0xb2, 0x41, 0xb4, 0x34, 0x0c, 0x15, 0x0d, 0xfd, 0xfd, 0x07, 0xfe, 0xc4, 0x95, 0x57, 0x52, 0x69, 0x20, 0x69, 0xa8, 0xd5, 0xd1, 0x31, 0xda, 0x95, 0xe4, 0xb5, 0x23, 0x0f, 0x31, 0xce, 0x75, 0xfb, 0xf6, 0x7d, 0xef, 0xbd, @@ -420,33 +420,33 @@ var fileDescriptor_5d00fde5fc97399e = []byte{ 0x75, 0x5a, 0x51, 0xa8, 0xdd, 0x4f, 0x6e, 0x9c, 0x97, 0x47, 0xb7, 0xea, 0xf2, 0x7e, 0x12, 0xc6, 0xe0, 0x4b, 0x50, 0x73, 0x3d, 0x4a, 0xcf, 0x7b, 0x17, 0x98, 0xd8, 0x17, 0xbe, 0xba, 0xcb, 0x7b, 0xd0, 0x90, 0xca, 0x09, 0xa1, 0xce, 0xda, 0xc6, 0x57, 0x1c, 0xd1, 0xf9, 0x20, 0xbe, 0xf9, 0xfc, - 0x4e, 0x72, 0xb4, 0x6e, 0x55, 0xb9, 0x29, 0x90, 0xf0, 0x09, 0x00, 0xc2, 0x4b, 0x1c, 0xe2, 0xab, - 0xe5, 0x96, 0x72, 0x58, 0xeb, 0xec, 0x45, 0xa1, 0x76, 0x4f, 0x8e, 0x8c, 0x7d, 0xba, 0x55, 0xe1, - 0x06, 0x57, 0xf2, 0x49, 0x7a, 0x22, 0x51, 0x59, 0xad, 0xf0, 0xb8, 0x83, 0xe5, 0x8a, 0xc2, 0x9b, - 0x56, 0xec, 0x72, 0x0b, 0x76, 0xc1, 0x9d, 0xc4, 0x1b, 0xf3, 0xda, 0x61, 0x53, 0xa6, 0x02, 0x1e, - 0xde, 0x88, 0x42, 0x6d, 0x7f, 0x21, 0x3c, 0x05, 0xe8, 0xd6, 0xbb, 0x22, 0x43, 0xba, 0x01, 0xcf, - 0xc1, 0xdd, 0xcc, 0x9b, 0xb6, 0xa5, 0xfa, 0x9f, 0x6d, 0xd1, 0x92, 0xb6, 0x1c, 0xa4, 0x43, 0x58, - 0xcc, 0xa0, 0x5b, 0x77, 0xb2, 0xad, 0xa4, 0x3d, 0x73, 0xe1, 0xd6, 0x56, 0x08, 0xb7, 0x09, 0xee, - 0xe7, 0xc9, 0x32, 0xd3, 0xed, 0x5f, 0xdb, 0x39, 0xba, 0x3d, 0x45, 0x23, 0xf8, 0x25, 0x78, 0x67, - 0x51, 0x7b, 0x42, 0xbb, 0x6a, 0x14, 0x6a, 0xf5, 0xec, 0x7c, 0xb2, 0xe4, 0x6a, 0x48, 0x96, 0x1a, - 0x02, 0x8d, 0x05, 0x12, 0xe5, 0xe9, 0xf8, 0xa3, 0x28, 0xd4, 0x1e, 0xe6, 0x10, 0x6e, 0x29, 0xb1, - 0x2a, 0x3b, 0x17, 0xf4, 0xbc, 0xc1, 0x73, 0xb9, 0xfc, 0x14, 0x94, 0x36, 0x7e, 0x0a, 0x96, 0x65, - 0xb0, 0x7d, 0x8b, 0x32, 0x68, 0x03, 0xc1, 0xee, 0x9e, 0xef, 0x05, 0xea, 0x0e, 0xa7, 0xa3, 0xf4, - 0x88, 0x66, 0x2e, 0xdd, 0x2a, 0xf3, 0x75, 0xfc, 0xee, 0x2e, 0x6b, 0x60, 0x77, 0x33, 0x0d, 0x94, - 0x6f, 0x45, 0x03, 0x95, 0xb7, 0xaa, 0x01, 0xb0, 0x86, 0x06, 0x4e, 0xd1, 0x28, 0xd3, 0xc0, 0x2f, - 0x5b, 0x40, 0xbd, 0x06, 0xe8, 0x52, 0xe7, 0x9c, 0x78, 0x93, 0x4d, 0x75, 0x90, 0x4d, 0xae, 0x8f, - 0x46, 0x9c, 0xf6, 0x39, 0x93, 0xeb, 0xa3, 0x51, 0x3a, 0xb9, 0x58, 0x79, 0xcb, 0x44, 0x2a, 0xde, - 0x22, 0x91, 0xe6, 0xcd, 0x2a, 0xad, 0x68, 0x96, 0x0e, 0x5a, 0xab, 0x7a, 0x91, 0x36, 0xec, 0xf1, - 0x3f, 0x45, 0x50, 0x7c, 0xca, 0x6c, 0xf8, 0x23, 0x80, 0x39, 0xff, 0xa8, 0xa3, 0x55, 0x22, 0xcc, - 0xfd, 0x41, 0x34, 0x3e, 0x5d, 0x0b, 0x9e, 0x9e, 0x01, 0x7e, 0x0f, 0xee, 0x5d, 0xff, 0x6c, 0x7c, - 0x72, 0xe3, 0x5c, 0xcf, 0xbd, 0xa0, 0xf1, 0x64, 0x1d, 0xf4, 0xea, 0xc2, 0xf1, 0xcc, 0x6e, 0x5e, - 0xf8, 0x14, 0x8d, 0xd6, 0x28, 0x2c, 0xd1, 0x14, 0xfe, 0xa4, 0x80, 0xbd, 0x7c, 0x8e, 0x3e, 0xba, - 0x71, 0xbe, 0x24, 0xa2, 0xf1, 0xd9, 0xba, 0x11, 0xe9, 0x29, 0x3a, 0x2f, 0x5e, 0x5f, 0x36, 0x95, - 0x37, 0x97, 0x4d, 0xe5, 0xcf, 0xcb, 0xa6, 0xf2, 0xeb, 0x55, 0xb3, 0xf0, 0xe6, 0xaa, 0x59, 0xf8, - 0xe3, 0xaa, 0x59, 0x78, 0xf9, 0x85, 0x4d, 0xfc, 0x8b, 0xe9, 0xc0, 0x40, 0x74, 0x62, 0x22, 0xca, - 0x26, 0x94, 0x99, 0x64, 0x80, 0x8e, 0x6c, 0x6a, 0xce, 0x8e, 0xcd, 0x09, 0x1d, 0x4e, 0xc7, 0x98, - 0x89, 0x2f, 0xfa, 0xa3, 0xe3, 0x23, 0xe9, 0x97, 0xee, 0x07, 0x2e, 0x66, 0x83, 0x1d, 0xfe, 0xe4, - 0x1e, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xef, 0xf1, 0x60, 0x63, 0x54, 0x0c, 0x00, 0x00, + 0x4e, 0x72, 0xb4, 0x6e, 0x55, 0xb9, 0x29, 0x90, 0xf0, 0x18, 0x00, 0xe1, 0x25, 0x0e, 0xf1, 0xd5, + 0x72, 0x4b, 0x39, 0xac, 0x75, 0xf6, 0xa2, 0x50, 0xbb, 0x27, 0x47, 0xc6, 0x3e, 0xdd, 0xaa, 0x70, + 0x83, 0x2b, 0xf9, 0x24, 0x3d, 0x91, 0xa8, 0xac, 0x56, 0x78, 0xdc, 0xc1, 0x72, 0x45, 0xe1, 0x4d, + 0x2b, 0x76, 0xb9, 0x05, 0xbb, 0xe0, 0x4e, 0xe2, 0x8d, 0x79, 0xed, 0xb0, 0x29, 0x53, 0x01, 0x0f, + 0x6f, 0x44, 0xa1, 0xb6, 0xbf, 0x10, 0x9e, 0x02, 0x74, 0xeb, 0x5d, 0x91, 0x21, 0xdd, 0x80, 0xe7, + 0xe0, 0x6e, 0xe6, 0x4d, 0xdb, 0x52, 0xfd, 0xcf, 0xb6, 0x68, 0x49, 0x5b, 0x0e, 0xd2, 0x21, 0x2c, + 0x66, 0xd0, 0xad, 0x3b, 0xd9, 0x56, 0xd2, 0x9e, 0xb9, 0x70, 0x6b, 0x2b, 0x84, 0xdb, 0x04, 0xf7, + 0xf3, 0x64, 0x99, 0xe9, 0xf6, 0xaf, 0xed, 0x1c, 0xdd, 0x9e, 0xa2, 0x11, 0xfc, 0x12, 0xbc, 0xb3, + 0xa8, 0x3d, 0xa1, 0x5d, 0x35, 0x0a, 0xb5, 0x7a, 0x76, 0x3e, 0x59, 0x72, 0x35, 0x24, 0x4b, 0x0d, + 0x81, 0xc6, 0x02, 0x89, 0xf2, 0x74, 0xfc, 0x51, 0x14, 0x6a, 0x0f, 0x73, 0x08, 0xb7, 0x94, 0x58, + 0x95, 0x9d, 0x0b, 0x7a, 0xde, 0xe0, 0xb9, 0x5c, 0x7e, 0x0a, 0x4a, 0x1b, 0x3f, 0x05, 0xcb, 0x32, + 0xd8, 0xbe, 0x45, 0x19, 0xb4, 0x81, 0x60, 0x77, 0xcf, 0xf7, 0x02, 0x75, 0x87, 0xd3, 0x51, 0x7a, + 0x44, 0x33, 0x97, 0x6e, 0x95, 0xf9, 0x3a, 0x7e, 0x77, 0x97, 0x35, 0xb0, 0xbb, 0x99, 0x06, 0xca, + 0xb7, 0xa2, 0x81, 0xca, 0x5b, 0xd5, 0x00, 0x58, 0x43, 0x03, 0xa7, 0x68, 0x94, 0x69, 0xe0, 0x97, + 0x2d, 0xa0, 0x5e, 0x03, 0x74, 0xa9, 0x73, 0x4e, 0xbc, 0xc9, 0xa6, 0x3a, 0xc8, 0x26, 0xd7, 0x47, + 0x23, 0x4e, 0xfb, 0x9c, 0xc9, 0xf5, 0xd1, 0x28, 0x9d, 0x5c, 0xac, 0xbc, 0x65, 0x22, 0x15, 0x6f, + 0x91, 0x48, 0xf3, 0x66, 0x95, 0x56, 0x34, 0x4b, 0x07, 0xad, 0x55, 0xbd, 0x48, 0x1b, 0xf6, 0xf8, + 0x9f, 0x22, 0x28, 0x3e, 0x65, 0x36, 0xfc, 0x11, 0xc0, 0x9c, 0x7f, 0xd4, 0xd1, 0x2a, 0x11, 0xe6, + 0xfe, 0x20, 0x1a, 0x9f, 0xae, 0x05, 0x4f, 0xcf, 0x00, 0xbf, 0x07, 0xf7, 0xae, 0x7f, 0x36, 0x3e, + 0xb9, 0x71, 0xae, 0xe7, 0x5e, 0xd0, 0x38, 0x5e, 0x07, 0xbd, 0xba, 0x70, 0x3c, 0xb3, 0x9b, 0x17, + 0x3e, 0x45, 0xa3, 0x35, 0x0a, 0x4b, 0x34, 0x85, 0x3f, 0x29, 0x60, 0x2f, 0x9f, 0xa3, 0x8f, 0x6e, + 0x9c, 0x2f, 0x89, 0x68, 0x7c, 0xb6, 0x6e, 0x44, 0x7a, 0x8a, 0xce, 0x8b, 0xd7, 0x97, 0x4d, 0xe5, + 0xcd, 0x65, 0x53, 0xf9, 0xf3, 0xb2, 0xa9, 0xfc, 0x7a, 0xd5, 0x2c, 0xbc, 0xb9, 0x6a, 0x16, 0xfe, + 0xb8, 0x6a, 0x16, 0x5e, 0x7e, 0x61, 0x13, 0xff, 0x62, 0x3a, 0x30, 0x10, 0x9d, 0x98, 0x88, 0xb2, + 0x09, 0x65, 0x26, 0x19, 0xa0, 0x23, 0x9b, 0x9a, 0xb3, 0x63, 0x73, 0x42, 0x87, 0xd3, 0x31, 0x66, + 0xe2, 0x8b, 0xfe, 0xe8, 0xc9, 0x91, 0xf4, 0x4b, 0xf7, 0x03, 0x17, 0xb3, 0xc1, 0x0e, 0x7f, 0x72, + 0x9f, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x63, 0x2e, 0xb2, 0x54, 0x0c, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/03-connection/types/version.go b/modules/core/03-connection/types/version.go index f88164aff69..7ae9e0b98b6 100644 --- a/modules/core/03-connection/types/version.go +++ b/modules/core/03-connection/types/version.go @@ -5,7 +5,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( diff --git a/modules/core/03-connection/types/version_test.go b/modules/core/03-connection/types/version_test.go index 404f4f8ca56..29838291dd8 100644 --- a/modules/core/03-connection/types/version_test.go +++ b/modules/core/03-connection/types/version_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func TestValidateVersion(t *testing.T) { diff --git a/modules/core/04-channel/client/cli/cli.go b/modules/core/04-channel/client/cli/cli.go index d2dc4e661f8..34259b09146 100644 --- a/modules/core/04-channel/client/cli/cli.go +++ b/modules/core/04-channel/client/cli/cli.go @@ -4,7 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // GetQueryCmd returns the query commands for IBC channels diff --git a/modules/core/04-channel/client/cli/query.go b/modules/core/04-channel/client/cli/query.go index a92ea327d6d..8fe1937e055 100644 --- a/modules/core/04-channel/client/cli/query.go +++ b/modules/core/04-channel/client/cli/query.go @@ -9,9 +9,9 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/client/utils" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/client/utils" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) const ( diff --git a/modules/core/04-channel/client/utils/utils.go b/modules/core/04-channel/client/utils/utils.go index 4124fe9b2b4..577172b598c 100644 --- a/modules/core/04-channel/client/utils/utils.go +++ b/modules/core/04-channel/client/utils/utils.go @@ -8,12 +8,12 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clientutils "github.com/cosmos/ibc-go/v3/modules/core/02-client/client/utils" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/client" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clientutils "github.com/cosmos/ibc-go/v4/modules/core/02-client/client/utils" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/client" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // QueryChannel returns a channel end. diff --git a/modules/core/04-channel/genesis.go b/modules/core/04-channel/genesis.go index 56f81ca9f72..0d402fd8f39 100644 --- a/modules/core/04-channel/genesis.go +++ b/modules/core/04-channel/genesis.go @@ -3,8 +3,8 @@ package channel import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/keeper" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/keeper" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // InitGenesis initializes the ibc channel submodule's state from a provided genesis diff --git a/modules/core/04-channel/keeper/events.go b/modules/core/04-channel/keeper/events.go index 66b47467216..bd014a67979 100644 --- a/modules/core/04-channel/keeper/events.go +++ b/modules/core/04-channel/keeper/events.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // EmitChannelOpenInitEvent emits a channel open init event diff --git a/modules/core/04-channel/keeper/grpc_query.go b/modules/core/04-channel/keeper/grpc_query.go index 6d4b150ada9..6936fec0596 100644 --- a/modules/core/04-channel/keeper/grpc_query.go +++ b/modules/core/04-channel/keeper/grpc_query.go @@ -12,10 +12,10 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) var _ types.QueryServer = (*Keeper)(nil) diff --git a/modules/core/04-channel/keeper/grpc_query_test.go b/modules/core/04-channel/keeper/grpc_query_test.go index 64c81f2105d..8e7ac77a57a 100644 --- a/modules/core/04-channel/keeper/grpc_query_test.go +++ b/modules/core/04-channel/keeper/grpc_query_test.go @@ -6,11 +6,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *KeeperTestSuite) TestQueryChannel() { diff --git a/modules/core/04-channel/keeper/handshake.go b/modules/core/04-channel/keeper/handshake.go index 1d650bb4d7b..25937c78d6e 100644 --- a/modules/core/04-channel/keeper/handshake.go +++ b/modules/core/04-channel/keeper/handshake.go @@ -8,11 +8,11 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "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" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // ChanOpenInit is called by a module to initiate a channel opening handshake with diff --git a/modules/core/04-channel/keeper/handshake_test.go b/modules/core/04-channel/keeper/handshake_test.go index aa554fe9fd8..498b46d119b 100644 --- a/modules/core/04-channel/keeper/handshake_test.go +++ b/modules/core/04-channel/keeper/handshake_test.go @@ -5,12 +5,12 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type testCase = struct { diff --git a/modules/core/04-channel/keeper/keeper.go b/modules/core/04-channel/keeper/keeper.go index ca2f824ad48..8d82129425f 100644 --- a/modules/core/04-channel/keeper/keeper.go +++ b/modules/core/04-channel/keeper/keeper.go @@ -12,12 +12,12 @@ import ( "github.com/tendermint/tendermint/libs/log" db "github.com/tendermint/tm-db" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "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" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ porttypes.ICS4Wrapper = Keeper{} diff --git a/modules/core/04-channel/keeper/keeper_test.go b/modules/core/04-channel/keeper/keeper_test.go index f04664d71f4..f202d8bce78 100644 --- a/modules/core/04-channel/keeper/keeper_test.go +++ b/modules/core/04-channel/keeper/keeper_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" ) // KeeperTestSuite is a testing suite to test keeper functions. diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index c3e8e45b89c..551e02e8b78 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -9,11 +9,11 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // SendPacket is called by a module in order to send an IBC packet on a channel diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index 4d05df46533..0000edda0e7 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -7,14 +7,14 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" ) var ( diff --git a/modules/core/04-channel/keeper/timeout.go b/modules/core/04-channel/keeper/timeout.go index f29f1cca671..1076f333185 100644 --- a/modules/core/04-channel/keeper/timeout.go +++ b/modules/core/04-channel/keeper/timeout.go @@ -8,10 +8,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // TimeoutPacket is called by a module which originally attempted to send a diff --git a/modules/core/04-channel/keeper/timeout_test.go b/modules/core/04-channel/keeper/timeout_test.go index ae3a816ef16..5dab582e947 100644 --- a/modules/core/04-channel/keeper/timeout_test.go +++ b/modules/core/04-channel/keeper/timeout_test.go @@ -7,12 +7,12 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) // TestTimeoutPacket test the TimeoutPacket call on chainA by ensuring the timeout has passed diff --git a/modules/core/04-channel/module.go b/modules/core/04-channel/module.go index 00dfc6a808b..867f8bd0351 100644 --- a/modules/core/04-channel/module.go +++ b/modules/core/04-channel/module.go @@ -4,8 +4,8 @@ import ( "github.com/gogo/protobuf/grpc" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/client/cli" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/client/cli" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // Name returns the IBC channel ICS name. diff --git a/modules/core/04-channel/simulation/decoder.go b/modules/core/04-channel/simulation/decoder.go index d09834551e8..5cec8179b84 100644 --- a/modules/core/04-channel/simulation/decoder.go +++ b/modules/core/04-channel/simulation/decoder.go @@ -8,8 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's diff --git a/modules/core/04-channel/simulation/decoder_test.go b/modules/core/04-channel/simulation/decoder_test.go index 5a78c03be56..4649df72b7f 100644 --- a/modules/core/04-channel/simulation/decoder_test.go +++ b/modules/core/04-channel/simulation/decoder_test.go @@ -8,10 +8,10 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/simulation" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/simulation" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) func TestDecodeStore(t *testing.T) { diff --git a/modules/core/04-channel/simulation/genesis.go b/modules/core/04-channel/simulation/genesis.go index 7c11dd6cb55..7bc7ad6415d 100644 --- a/modules/core/04-channel/simulation/genesis.go +++ b/modules/core/04-channel/simulation/genesis.go @@ -5,7 +5,7 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // GenChannelGenesis returns the default channel genesis state. diff --git a/modules/core/04-channel/types/acknowledgement_test.go b/modules/core/04-channel/types/acknowledgement_test.go index 530d288bb32..9552fadf996 100644 --- a/modules/core/04-channel/types/acknowledgement_test.go +++ b/modules/core/04-channel/types/acknowledgement_test.go @@ -8,7 +8,7 @@ import ( tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" tmstate "github.com/tendermint/tendermint/state" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) const ( diff --git a/modules/core/04-channel/types/channel.go b/modules/core/04-channel/types/channel.go index 4671000ab70..6b02b19f381 100644 --- a/modules/core/04-channel/types/channel.go +++ b/modules/core/04-channel/types/channel.go @@ -3,8 +3,8 @@ package types import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( diff --git a/modules/core/04-channel/types/channel.pb.go b/modules/core/04-channel/types/channel.pb.go index 3ce5ce3a2e1..d36ce20be88 100644 --- a/modules/core/04-channel/types/channel.pb.go +++ b/modules/core/04-channel/types/channel.pb.go @@ -5,7 +5,7 @@ package types import ( fmt "fmt" - types "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + types "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -504,62 +504,62 @@ var fileDescriptor_c3a07336710636a0 = []byte{ // 925 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xcd, 0x8e, 0x1a, 0x47, 0x10, 0x66, 0x60, 0xf8, 0x2b, 0x16, 0x96, 0x6d, 0x67, 0xf1, 0x64, 0x62, 0x33, 0x78, 0x94, 0xc3, - 0xca, 0x91, 0xc1, 0x6b, 0x5b, 0x89, 0xe2, 0x53, 0x96, 0x1f, 0x6b, 0x47, 0xb1, 0x60, 0x35, 0xb0, - 0x87, 0xf8, 0x42, 0x60, 0xa6, 0x03, 0x23, 0xc3, 0x34, 0x99, 0x69, 0x58, 0xed, 0x1b, 0x58, 0x5c, - 0x92, 0x17, 0x40, 0x8a, 0x14, 0x25, 0xaf, 0x90, 0x57, 0xf0, 0xd1, 0xc7, 0x9c, 0x50, 0xb4, 0x7b, - 0xc8, 0x9d, 0x17, 0x48, 0x34, 0xdd, 0x3d, 0xfc, 0xac, 0xad, 0x3d, 0x26, 0x17, 0x9f, 0xe8, 0xaa, - 0xef, 0xab, 0xaa, 0x6f, 0xaa, 0x8a, 0x56, 0xc3, 0x03, 0xa7, 0x6f, 0x55, 0x2c, 0xe2, 0xe1, 0x8a, - 0x35, 0xec, 0xb9, 0x2e, 0x1e, 0x55, 0x66, 0xc7, 0xe1, 0xb1, 0x3c, 0xf1, 0x08, 0x25, 0xe8, 0x8e, - 0xd3, 0xb7, 0xca, 0x01, 0xa5, 0x1c, 0xfa, 0x67, 0xc7, 0xea, 0x27, 0x03, 0x32, 0x20, 0x0c, 0xaf, - 0x04, 0x27, 0x4e, 0x55, 0xb5, 0x4d, 0xb6, 0x91, 0x83, 0x5d, 0xca, 0x92, 0xb1, 0x13, 0x27, 0xe8, - 0xbf, 0x45, 0x21, 0x59, 0xe3, 0x59, 0xd0, 0x63, 0x88, 0xfb, 0xb4, 0x47, 0xb1, 0x22, 0x95, 0xa4, - 0xa3, 0xdc, 0x13, 0xb5, 0xfc, 0x81, 0x3a, 0xe5, 0x76, 0xc0, 0x30, 0x39, 0x11, 0x7d, 0x09, 0x29, - 0xe2, 0xd9, 0xd8, 0x73, 0xdc, 0x81, 0x12, 0xbd, 0x25, 0xa8, 0x15, 0x90, 0xcc, 0x35, 0x17, 0x7d, - 0x0b, 0x7b, 0x16, 0x99, 0xba, 0x14, 0x7b, 0x93, 0x9e, 0x47, 0x2f, 0x95, 0x58, 0x49, 0x3a, 0xca, - 0x3c, 0x79, 0xf0, 0xc1, 0xd8, 0xda, 0x16, 0xb1, 0x2a, 0xbf, 0x5d, 0x6a, 0x11, 0x73, 0x27, 0x18, - 0xd5, 0x60, 0xdf, 0x22, 0xae, 0x8b, 0x2d, 0xea, 0x10, 0xb7, 0x3b, 0x24, 0x13, 0x5f, 0x91, 0x4b, - 0xb1, 0xa3, 0x74, 0x55, 0x5d, 0x2d, 0xb5, 0xc2, 0x65, 0x6f, 0x3c, 0x7a, 0xae, 0xdf, 0x20, 0xe8, - 0x66, 0x6e, 0xe3, 0x39, 0x25, 0x13, 0x1f, 0x29, 0x90, 0x9c, 0x61, 0xcf, 0x77, 0x88, 0xab, 0xc4, - 0x4b, 0xd2, 0x51, 0xda, 0x0c, 0xcd, 0xe7, 0xf2, 0x9b, 0x5f, 0xb4, 0x88, 0xfe, 0x77, 0x14, 0x0e, - 0x0c, 0x1b, 0xbb, 0xd4, 0xf9, 0xc1, 0xc1, 0xf6, 0xc7, 0x8e, 0xdd, 0xd2, 0x31, 0x74, 0x17, 0x92, - 0x13, 0xe2, 0xd1, 0xae, 0x63, 0x2b, 0x09, 0x86, 0x24, 0x02, 0xd3, 0xb0, 0xd1, 0x7d, 0x00, 0x21, - 0x33, 0xc0, 0x92, 0x0c, 0x4b, 0x0b, 0x8f, 0x61, 0x8b, 0x4e, 0x5f, 0xc0, 0xde, 0xf6, 0x07, 0xa0, - 0x2f, 0x36, 0xd9, 0x82, 0x2e, 0xa7, 0xab, 0x68, 0xb5, 0xd4, 0x72, 0x5c, 0xa4, 0x00, 0xf4, 0x75, - 0x85, 0x67, 0x3b, 0x15, 0xa2, 0x8c, 0x7f, 0xb8, 0x5a, 0x6a, 0x07, 0xe2, 0xa3, 0xd6, 0x98, 0xfe, - 0x7e, 0xe1, 0x7f, 0x62, 0x90, 0x38, 0xeb, 0x59, 0xaf, 0x31, 0x45, 0x2a, 0xa4, 0x7c, 0xfc, 0xe3, - 0x14, 0xbb, 0x16, 0x1f, 0xad, 0x6c, 0xae, 0x6d, 0xf4, 0x15, 0x64, 0x7c, 0x32, 0xf5, 0x2c, 0xdc, - 0x0d, 0x6a, 0x8a, 0x1a, 0x85, 0xd5, 0x52, 0x43, 0xbc, 0xc6, 0x16, 0xa8, 0x9b, 0xc0, 0xad, 0x33, - 0xe2, 0x51, 0xf4, 0x0d, 0xe4, 0x04, 0x26, 0x2a, 0xb3, 0x21, 0xa6, 0xab, 0x9f, 0xae, 0x96, 0xda, - 0xe1, 0x4e, 0xac, 0xc0, 0x75, 0x33, 0xcb, 0x1d, 0xe1, 0xba, 0xbd, 0x80, 0xbc, 0x8d, 0x7d, 0xea, - 0xb8, 0x3d, 0x36, 0x17, 0x56, 0x5f, 0x66, 0x39, 0x3e, 0x5b, 0x2d, 0xb5, 0xbb, 0x3c, 0xc7, 0x4d, - 0x86, 0x6e, 0xee, 0x6f, 0xb9, 0x98, 0x92, 0x16, 0xdc, 0xd9, 0x66, 0x85, 0x72, 0xd8, 0x18, 0xab, - 0xc5, 0xd5, 0x52, 0x53, 0xdf, 0x4f, 0xb5, 0xd6, 0x84, 0xb6, 0xbc, 0xa1, 0x30, 0x04, 0xb2, 0xdd, - 0xa3, 0x3d, 0x36, 0xee, 0x3d, 0x93, 0x9d, 0xd1, 0xf7, 0x90, 0xa3, 0xce, 0x18, 0x93, 0x29, 0xed, - 0x0e, 0xb1, 0x33, 0x18, 0x52, 0x36, 0xf0, 0xcc, 0xce, 0xbe, 0xf3, 0x9b, 0x68, 0x76, 0x5c, 0x3e, - 0x65, 0x8c, 0xea, 0xfd, 0x60, 0x59, 0x37, 0xed, 0xd8, 0x8d, 0xd7, 0xcd, 0xac, 0x70, 0x70, 0x36, - 0x32, 0xe0, 0x20, 0x64, 0x04, 0xbf, 0x3e, 0xed, 0x8d, 0x27, 0x4a, 0x2a, 0x18, 0x57, 0xf5, 0xde, - 0x6a, 0xa9, 0x29, 0xbb, 0x49, 0xd6, 0x14, 0xdd, 0xcc, 0x0b, 0x5f, 0x27, 0x74, 0x89, 0x0d, 0xf8, - 0x5d, 0x82, 0x0c, 0xdf, 0x00, 0xf6, 0x9f, 0xfd, 0x0f, 0x56, 0x6f, 0x67, 0xd3, 0x62, 0x37, 0x36, - 0x2d, 0xec, 0xaa, 0xbc, 0xe9, 0xaa, 0x10, 0xfa, 0x93, 0x04, 0x29, 0x2e, 0xd4, 0xb0, 0xff, 0x67, - 0x95, 0x42, 0x51, 0x0b, 0xf6, 0x4f, 0xac, 0xd7, 0x2e, 0xb9, 0x18, 0x61, 0x7b, 0x80, 0xc7, 0xd8, - 0xa5, 0x48, 0x81, 0x84, 0x87, 0xfd, 0xe9, 0x88, 0x2a, 0x87, 0xc1, 0x07, 0x9c, 0x46, 0x4c, 0x61, - 0xa3, 0x02, 0xc4, 0xb1, 0xe7, 0x11, 0x4f, 0x29, 0x04, 0xf5, 0x4f, 0x23, 0x26, 0x37, 0xab, 0x00, - 0x29, 0x0f, 0xfb, 0x13, 0xe2, 0xfa, 0xf8, 0xe1, 0x1f, 0x12, 0xc4, 0xdb, 0xe2, 0xca, 0xd4, 0xda, - 0x9d, 0x93, 0x4e, 0xa3, 0x7b, 0xde, 0x34, 0x9a, 0x46, 0xc7, 0x38, 0x79, 0x69, 0xbc, 0x6a, 0xd4, - 0xbb, 0xe7, 0xcd, 0xf6, 0x59, 0xa3, 0x66, 0xbc, 0x30, 0x1a, 0xf5, 0x7c, 0x44, 0x3d, 0x98, 0x2f, - 0x4a, 0xd9, 0x1d, 0x02, 0x52, 0x00, 0x78, 0x5c, 0xe0, 0xcc, 0x4b, 0x6a, 0x6a, 0xbe, 0x28, 0xc9, - 0xc1, 0x19, 0x15, 0x21, 0xcb, 0x91, 0x8e, 0xf9, 0x5d, 0xeb, 0xac, 0xd1, 0xcc, 0x47, 0xd5, 0xcc, - 0x7c, 0x51, 0x4a, 0x0a, 0x73, 0x13, 0xc9, 0xc0, 0x18, 0x8f, 0x64, 0xc8, 0x3d, 0xd8, 0xe3, 0x48, - 0xed, 0x65, 0xab, 0xdd, 0xa8, 0xe7, 0x65, 0x15, 0xe6, 0x8b, 0x52, 0x82, 0x5b, 0xaa, 0xfc, 0xe6, - 0xd7, 0x62, 0xe4, 0xe1, 0x05, 0xc4, 0xd9, 0xed, 0x8d, 0x3e, 0x87, 0x42, 0xcb, 0xac, 0x37, 0xcc, - 0x6e, 0xb3, 0xd5, 0x6c, 0xdc, 0xd0, 0xcb, 0x52, 0x06, 0x7e, 0xa4, 0xc3, 0x3e, 0x67, 0x9d, 0x37, - 0xd9, 0x6f, 0xa3, 0x9e, 0x97, 0xd4, 0xec, 0x7c, 0x51, 0x4a, 0xaf, 0x1d, 0x81, 0x60, 0xce, 0x09, - 0x19, 0x42, 0xb0, 0x30, 0x79, 0xe1, 0x6a, 0xfb, 0xed, 0x55, 0x51, 0x7a, 0x77, 0x55, 0x94, 0xfe, - 0xba, 0x2a, 0x4a, 0x3f, 0x5f, 0x17, 0x23, 0xef, 0xae, 0x8b, 0x91, 0x3f, 0xaf, 0x8b, 0x91, 0x57, - 0x5f, 0x0f, 0x1c, 0x3a, 0x9c, 0xf6, 0xcb, 0x16, 0x19, 0x57, 0x2c, 0xe2, 0x8f, 0x89, 0x5f, 0x71, - 0xfa, 0xd6, 0xa3, 0x01, 0xa9, 0xcc, 0x9e, 0x56, 0xc6, 0xc4, 0x9e, 0x8e, 0xb0, 0xcf, 0x9f, 0x09, - 0x8f, 0x9f, 0x3d, 0x0a, 0xdf, 0x1d, 0xf4, 0x72, 0x82, 0xfd, 0x7e, 0x82, 0xbd, 0x13, 0x9e, 0xfe, - 0x1b, 0x00, 0x00, 0xff, 0xff, 0x47, 0xf5, 0x82, 0xa6, 0x98, 0x08, 0x00, 0x00, + 0xca, 0x91, 0xc1, 0xeb, 0xac, 0x12, 0xc5, 0xa7, 0x2c, 0x3f, 0xd6, 0x8e, 0x62, 0xc1, 0x6a, 0x60, + 0x0f, 0xf1, 0x85, 0xc0, 0x4c, 0x07, 0x46, 0x86, 0x69, 0x32, 0xd3, 0xb0, 0xda, 0x37, 0xb0, 0xb8, + 0x24, 0x2f, 0x80, 0x14, 0x29, 0x4a, 0x5e, 0x21, 0xaf, 0xe0, 0xa3, 0x8f, 0x39, 0xa1, 0x68, 0xf7, + 0x90, 0x3b, 0x2f, 0x90, 0x68, 0xba, 0x7b, 0xf8, 0x59, 0x5b, 0x7b, 0x4c, 0x2e, 0x39, 0xd1, 0x55, + 0xdf, 0x57, 0x55, 0xdf, 0x54, 0x15, 0xad, 0x86, 0x47, 0x4e, 0xdf, 0xaa, 0x58, 0xc4, 0xc3, 0x15, + 0x6b, 0xd8, 0x73, 0x5d, 0x3c, 0xaa, 0xcc, 0x8e, 0xc3, 0x63, 0x79, 0xe2, 0x11, 0x4a, 0xd0, 0x3d, + 0xa7, 0x6f, 0x95, 0x03, 0x4a, 0x39, 0xf4, 0xcf, 0x8e, 0xd5, 0x8f, 0x06, 0x64, 0x40, 0x18, 0x5e, + 0x09, 0x4e, 0x9c, 0xaa, 0x6a, 0x9b, 0x6c, 0x23, 0x07, 0xbb, 0x94, 0x25, 0x63, 0x27, 0x4e, 0xd0, + 0x7f, 0x8d, 0x42, 0xb2, 0xc6, 0xb3, 0xa0, 0xa7, 0x10, 0xf7, 0x69, 0x8f, 0x62, 0x45, 0x2a, 0x49, + 0x47, 0xb9, 0x67, 0x6a, 0xf9, 0x03, 0x75, 0xca, 0xed, 0x80, 0x61, 0x72, 0x22, 0xfa, 0x02, 0x52, + 0xc4, 0xb3, 0xb1, 0xe7, 0xb8, 0x03, 0x25, 0x7a, 0x47, 0x50, 0x2b, 0x20, 0x99, 0x6b, 0x2e, 0xfa, + 0x06, 0xf6, 0x2c, 0x32, 0x75, 0x29, 0xf6, 0x26, 0x3d, 0x8f, 0x5e, 0x29, 0xb1, 0x92, 0x74, 0x94, + 0x79, 0xf6, 0xe8, 0x83, 0xb1, 0xb5, 0x2d, 0x62, 0x55, 0x7e, 0xbb, 0xd4, 0x22, 0xe6, 0x4e, 0x30, + 0xaa, 0xc1, 0xbe, 0x45, 0x5c, 0x17, 0x5b, 0xd4, 0x21, 0x6e, 0x77, 0x48, 0x26, 0xbe, 0x22, 0x97, + 0x62, 0x47, 0xe9, 0xaa, 0xba, 0x5a, 0x6a, 0x85, 0xab, 0xde, 0x78, 0xf4, 0x5c, 0xbf, 0x45, 0xd0, + 0xcd, 0xdc, 0xc6, 0x73, 0x46, 0x26, 0x3e, 0x52, 0x20, 0x39, 0xc3, 0x9e, 0xef, 0x10, 0x57, 0x89, + 0x97, 0xa4, 0xa3, 0xb4, 0x19, 0x9a, 0xcf, 0xe5, 0x37, 0x3f, 0x6b, 0x11, 0xfd, 0xaf, 0x28, 0x1c, + 0x18, 0x36, 0x76, 0xa9, 0xf3, 0xbd, 0x83, 0xed, 0xff, 0x3b, 0x76, 0x47, 0xc7, 0xd0, 0x7d, 0x48, + 0x4e, 0x88, 0x47, 0xbb, 0x8e, 0xad, 0x24, 0x18, 0x92, 0x08, 0x4c, 0xc3, 0x46, 0x0f, 0x01, 0x84, + 0xcc, 0x00, 0x4b, 0x32, 0x2c, 0x2d, 0x3c, 0x86, 0x2d, 0x3a, 0x7d, 0x09, 0x7b, 0xdb, 0x1f, 0x80, + 0x3e, 0xdb, 0x64, 0x0b, 0xba, 0x9c, 0xae, 0xa2, 0xd5, 0x52, 0xcb, 0x71, 0x91, 0x02, 0xd0, 0xd7, + 0x15, 0x4e, 0x76, 0x2a, 0x44, 0x19, 0xff, 0x70, 0xb5, 0xd4, 0x0e, 0xc4, 0x47, 0xad, 0x31, 0xfd, + 0xfd, 0xc2, 0x7f, 0xc7, 0x20, 0x71, 0xde, 0xb3, 0x5e, 0x63, 0x8a, 0x54, 0x48, 0xf9, 0xf8, 0x87, + 0x29, 0x76, 0x2d, 0x3e, 0x5a, 0xd9, 0x5c, 0xdb, 0xe8, 0x4b, 0xc8, 0xf8, 0x64, 0xea, 0x59, 0xb8, + 0x1b, 0xd4, 0x14, 0x35, 0x0a, 0xab, 0xa5, 0x86, 0x78, 0x8d, 0x2d, 0x50, 0x37, 0x81, 0x5b, 0xe7, + 0xc4, 0xa3, 0xe8, 0x6b, 0xc8, 0x09, 0x4c, 0x54, 0x66, 0x43, 0x4c, 0x57, 0x3f, 0x5e, 0x2d, 0xb5, + 0xc3, 0x9d, 0x58, 0x81, 0xeb, 0x66, 0x96, 0x3b, 0xc2, 0x75, 0x7b, 0x01, 0x79, 0x1b, 0xfb, 0xd4, + 0x71, 0x7b, 0x6c, 0x2e, 0xac, 0xbe, 0xcc, 0x72, 0x7c, 0xb2, 0x5a, 0x6a, 0xf7, 0x79, 0x8e, 0xdb, + 0x0c, 0xdd, 0xdc, 0xdf, 0x72, 0x31, 0x25, 0x2d, 0xb8, 0xb7, 0xcd, 0x0a, 0xe5, 0xb0, 0x31, 0x56, + 0x8b, 0xab, 0xa5, 0xa6, 0xbe, 0x9f, 0x6a, 0xad, 0x09, 0x6d, 0x79, 0x43, 0x61, 0x08, 0x64, 0xbb, + 0x47, 0x7b, 0x6c, 0xdc, 0x7b, 0x26, 0x3b, 0xa3, 0xef, 0x20, 0x47, 0x9d, 0x31, 0x26, 0x53, 0xda, + 0x1d, 0x62, 0x67, 0x30, 0xa4, 0x6c, 0xe0, 0x99, 0x9d, 0x7d, 0xe7, 0x37, 0xd1, 0xec, 0xb8, 0x7c, + 0xc6, 0x18, 0xd5, 0x87, 0xc1, 0xb2, 0x6e, 0xda, 0xb1, 0x1b, 0xaf, 0x9b, 0x59, 0xe1, 0xe0, 0x6c, + 0x64, 0xc0, 0x41, 0xc8, 0x08, 0x7e, 0x7d, 0xda, 0x1b, 0x4f, 0x94, 0x54, 0x30, 0xae, 0xea, 0x83, + 0xd5, 0x52, 0x53, 0x76, 0x93, 0xac, 0x29, 0xba, 0x99, 0x17, 0xbe, 0x4e, 0xe8, 0x12, 0x1b, 0xf0, + 0x9b, 0x04, 0x19, 0xbe, 0x01, 0xec, 0x3f, 0xfb, 0x2f, 0xac, 0xde, 0xce, 0xa6, 0xc5, 0x6e, 0x6d, + 0x5a, 0xd8, 0x55, 0x79, 0xd3, 0x55, 0x21, 0xf4, 0x47, 0x09, 0x52, 0x5c, 0xa8, 0x61, 0xff, 0xc7, + 0x2a, 0x85, 0xa2, 0x16, 0xec, 0x9f, 0x5a, 0xaf, 0x5d, 0x72, 0x39, 0xc2, 0xf6, 0x00, 0x8f, 0xb1, + 0x4b, 0x91, 0x02, 0x09, 0x0f, 0xfb, 0xd3, 0x11, 0x55, 0x0e, 0x83, 0x0f, 0x38, 0x8b, 0x98, 0xc2, + 0x46, 0x05, 0x88, 0x63, 0xcf, 0x23, 0x9e, 0x52, 0x08, 0xea, 0x9f, 0x45, 0x4c, 0x6e, 0x56, 0x01, + 0x52, 0x1e, 0xf6, 0x27, 0xc4, 0xf5, 0xf1, 0xe3, 0xdf, 0x25, 0x88, 0xb7, 0xc5, 0x95, 0xa9, 0xb5, + 0x3b, 0xa7, 0x9d, 0x46, 0xf7, 0xa2, 0x69, 0x34, 0x8d, 0x8e, 0x71, 0xfa, 0xd2, 0x78, 0xd5, 0xa8, + 0x77, 0x2f, 0x9a, 0xed, 0xf3, 0x46, 0xcd, 0x78, 0x61, 0x34, 0xea, 0xf9, 0x88, 0x7a, 0x30, 0x5f, + 0x94, 0xb2, 0x3b, 0x04, 0xa4, 0x00, 0xf0, 0xb8, 0xc0, 0x99, 0x97, 0xd4, 0xd4, 0x7c, 0x51, 0x92, + 0x83, 0x33, 0x2a, 0x42, 0x96, 0x23, 0x1d, 0xf3, 0xdb, 0xd6, 0x79, 0xa3, 0x99, 0x8f, 0xaa, 0x99, + 0xf9, 0xa2, 0x94, 0x14, 0xe6, 0x26, 0x92, 0x81, 0x31, 0x1e, 0xc9, 0x90, 0x07, 0xb0, 0xc7, 0x91, + 0xda, 0xcb, 0x56, 0xbb, 0x51, 0xcf, 0xcb, 0x2a, 0xcc, 0x17, 0xa5, 0x04, 0xb7, 0x54, 0xf9, 0xcd, + 0x2f, 0xc5, 0xc8, 0xe3, 0x4b, 0x88, 0xb3, 0xdb, 0x1b, 0x7d, 0x0a, 0x85, 0x96, 0x59, 0x6f, 0x98, + 0xdd, 0x66, 0xab, 0xd9, 0xb8, 0xa5, 0x97, 0xa5, 0x0c, 0xfc, 0x48, 0x87, 0x7d, 0xce, 0xba, 0x68, + 0xb2, 0xdf, 0x46, 0x3d, 0x2f, 0xa9, 0xd9, 0xf9, 0xa2, 0x94, 0x5e, 0x3b, 0x02, 0xc1, 0x9c, 0x13, + 0x32, 0x84, 0x60, 0x61, 0xf2, 0xc2, 0xd5, 0xf6, 0xdb, 0xeb, 0xa2, 0xf4, 0xee, 0xba, 0x28, 0xfd, + 0x79, 0x5d, 0x94, 0x7e, 0xba, 0x29, 0x46, 0xde, 0xdd, 0x14, 0x23, 0x7f, 0xdc, 0x14, 0x23, 0xaf, + 0xbe, 0x1a, 0x38, 0x74, 0x38, 0xed, 0x97, 0x2d, 0x32, 0xae, 0x58, 0xc4, 0x1f, 0x13, 0xbf, 0xe2, + 0xf4, 0xad, 0x27, 0x03, 0x52, 0x99, 0x9d, 0x54, 0xc6, 0xc4, 0x9e, 0x8e, 0xb0, 0xcf, 0x9f, 0x09, + 0x4f, 0x4f, 0x9e, 0x84, 0xef, 0x0e, 0x7a, 0x35, 0xc1, 0x7e, 0x3f, 0xc1, 0xde, 0x09, 0x9f, 0xff, + 0x13, 0x00, 0x00, 0xff, 0xff, 0x59, 0xc1, 0x4c, 0x94, 0x98, 0x08, 0x00, 0x00, } func (m *Channel) Marshal() (dAtA []byte, err error) { diff --git a/modules/core/04-channel/types/channel_test.go b/modules/core/04-channel/types/channel_test.go index c6cc9a03a9c..95c4dea4d43 100644 --- a/modules/core/04-channel/types/channel_test.go +++ b/modules/core/04-channel/types/channel_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) func TestChannelValidateBasic(t *testing.T) { diff --git a/modules/core/04-channel/types/codec.go b/modules/core/04-channel/types/codec.go index 8981417130b..2c001666fd1 100644 --- a/modules/core/04-channel/types/codec.go +++ b/modules/core/04-channel/types/codec.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // RegisterInterfaces register the ibc channel submodule interfaces to protobuf diff --git a/modules/core/04-channel/types/events.go b/modules/core/04-channel/types/events.go index 8740c3838eb..ad9fcb922eb 100644 --- a/modules/core/04-channel/types/events.go +++ b/modules/core/04-channel/types/events.go @@ -3,7 +3,7 @@ package types import ( "fmt" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // IBC channel events diff --git a/modules/core/04-channel/types/expected_keepers.go b/modules/core/04-channel/types/expected_keepers.go index 317cefd16c1..41be5a00e24 100644 --- a/modules/core/04-channel/types/expected_keepers.go +++ b/modules/core/04-channel/types/expected_keepers.go @@ -4,8 +4,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // ClientKeeper expected account IBC client keeper diff --git a/modules/core/04-channel/types/genesis.go b/modules/core/04-channel/types/genesis.go index 5f6b9370942..78d8ae2b04a 100644 --- a/modules/core/04-channel/types/genesis.go +++ b/modules/core/04-channel/types/genesis.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // NewPacketState creates a new PacketState instance. diff --git a/modules/core/04-channel/types/genesis.pb.go b/modules/core/04-channel/types/genesis.pb.go index fa474dbb006..6dc5f5b2f4c 100644 --- a/modules/core/04-channel/types/genesis.pb.go +++ b/modules/core/04-channel/types/genesis.pb.go @@ -197,37 +197,37 @@ func init() { proto.RegisterFile("ibc/core/channel/v1/genesis.proto", fileDescri var fileDescriptor_cb06ec201f452595 = []byte{ // 506 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xcf, 0x6e, 0xd3, 0x40, - 0x10, 0x87, 0xe3, 0x36, 0x4d, 0xd3, 0x6d, 0x13, 0xd1, 0x6d, 0x23, 0x99, 0xa8, 0xd8, 0xc6, 0x48, - 0x28, 0x12, 0xaa, 0x4d, 0x69, 0x2f, 0x70, 0x34, 0x07, 0xc8, 0x0d, 0x6d, 0x39, 0x21, 0xa1, 0xc8, - 0x5e, 0x4f, 0xdd, 0x55, 0x62, 0x6f, 0xf0, 0x6e, 0x02, 0x7d, 0x0a, 0x78, 0xac, 0x1e, 0x7b, 0xe4, - 0x64, 0xa1, 0xe4, 0x0d, 0x72, 0xe4, 0x84, 0xfc, 0x37, 0x89, 0x1a, 0x21, 0xca, 0xcd, 0x3b, 0xf3, - 0x9b, 0xef, 0x9b, 0x83, 0x07, 0x3d, 0x65, 0x1e, 0xb5, 0x29, 0x8f, 0xc1, 0xa6, 0xd7, 0x6e, 0x14, - 0xc1, 0xc8, 0x9e, 0x9e, 0xd9, 0x01, 0x44, 0x20, 0x98, 0xb0, 0xc6, 0x31, 0x97, 0x1c, 0x1f, 0x31, - 0x8f, 0x5a, 0x69, 0xc4, 0x2a, 0x22, 0xd6, 0xf4, 0xac, 0x7b, 0x1c, 0xf0, 0x80, 0x67, 0x7d, 0x3b, - 0xfd, 0xca, 0xa3, 0xdd, 0x8d, 0xb4, 0x72, 0x2a, 0x8b, 0x98, 0xf3, 0x1d, 0x74, 0xf0, 0x2e, 0xe7, - 0x5f, 0x4a, 0x57, 0x02, 0xfe, 0x8c, 0x9a, 0x45, 0x42, 0xa8, 0x8a, 0xb1, 0xdd, 0xdb, 0x7f, 0xf5, - 0xdc, 0xda, 0x60, 0xb4, 0xfa, 0x3e, 0x44, 0x92, 0x5d, 0x31, 0xf0, 0xdf, 0xe6, 0x45, 0xe7, 0xf1, - 0x6d, 0xa2, 0xd7, 0x7e, 0x27, 0xfa, 0xe1, 0xbd, 0x16, 0xa9, 0x90, 0x98, 0xa0, 0x47, 0x2e, 0x1d, - 0x46, 0xfc, 0xeb, 0x08, 0xfc, 0x00, 0x42, 0x88, 0xa4, 0x50, 0xb7, 0x32, 0x8d, 0xb1, 0x51, 0xf3, - 0xc1, 0xa5, 0x43, 0x90, 0xd9, 0x6a, 0x4e, 0x3d, 0x15, 0x90, 0x7b, 0xf3, 0xf8, 0x3d, 0xda, 0xa7, - 0x3c, 0x0c, 0x99, 0xcc, 0x71, 0xdb, 0x0f, 0xc2, 0xad, 0x8e, 0x62, 0x07, 0x35, 0x63, 0xa0, 0xc0, - 0xc6, 0x52, 0xa8, 0xf5, 0x07, 0x61, 0xaa, 0x39, 0xcc, 0x50, 0x5b, 0x40, 0xe4, 0x0f, 0x04, 0x7c, - 0x99, 0x40, 0x44, 0x41, 0xa8, 0x3b, 0x19, 0xe9, 0xd9, 0xdf, 0x48, 0x45, 0xd6, 0x79, 0x92, 0xc2, - 0x16, 0x89, 0xde, 0xb9, 0x71, 0xc3, 0xd1, 0x1b, 0x73, 0x1d, 0x64, 0x92, 0x56, 0x5a, 0x28, 0xc3, - 0x99, 0x2a, 0x06, 0x3a, 0x5d, 0x51, 0x35, 0xfe, 0x5b, 0xb5, 0x0e, 0x32, 0x49, 0x2b, 0x2d, 0x2c, - 0x55, 0x57, 0xa8, 0xe5, 0xd2, 0xe1, 0x8a, 0x69, 0xf7, 0xdf, 0x4d, 0x27, 0x85, 0xe9, 0x38, 0x37, - 0xad, 0x71, 0x4c, 0x72, 0xe0, 0xd2, 0xe1, 0xd2, 0xf3, 0x11, 0x75, 0x22, 0xf8, 0x26, 0x07, 0x05, - 0xad, 0x0a, 0xaa, 0x4d, 0x43, 0xe9, 0xd5, 0x1d, 0x63, 0x91, 0xe8, 0x27, 0x39, 0x66, 0x63, 0xcc, - 0x24, 0x47, 0x69, 0xbd, 0xf8, 0xef, 0x4a, 0xac, 0xf9, 0x5d, 0x41, 0xed, 0xf5, 0xa5, 0xf0, 0x0b, - 0xb4, 0x3b, 0xe6, 0xb1, 0x1c, 0x30, 0x5f, 0x55, 0x0c, 0xa5, 0xb7, 0xe7, 0xe0, 0x45, 0xa2, 0xb7, - 0x73, 0x74, 0xd1, 0x30, 0x49, 0x23, 0xfd, 0xea, 0xfb, 0xf8, 0x02, 0xa1, 0xd2, 0xc4, 0x7c, 0x75, - 0x2b, 0xcb, 0x77, 0x16, 0x89, 0x7e, 0x98, 0xe7, 0x97, 0x3d, 0x93, 0xec, 0x15, 0x8f, 0xbe, 0x8f, - 0xbb, 0xa8, 0x59, 0xad, 0xbf, 0x9d, 0xae, 0x4f, 0xaa, 0xb7, 0x73, 0x79, 0x3b, 0xd3, 0x94, 0xbb, - 0x99, 0xa6, 0xfc, 0x9a, 0x69, 0xca, 0x8f, 0xb9, 0x56, 0xbb, 0x9b, 0x6b, 0xb5, 0x9f, 0x73, 0xad, - 0xf6, 0xe9, 0x75, 0xc0, 0xe4, 0xf5, 0xc4, 0xb3, 0x28, 0x0f, 0x6d, 0xca, 0x45, 0xc8, 0x85, 0xcd, - 0x3c, 0x7a, 0x1a, 0x70, 0x7b, 0x7a, 0x6e, 0x87, 0xdc, 0x9f, 0x8c, 0x40, 0xe4, 0x47, 0xfd, 0xf2, - 0xe2, 0xb4, 0xbc, 0x6b, 0x79, 0x33, 0x06, 0xe1, 0x35, 0xb2, 0x9b, 0x3e, 0xff, 0x13, 0x00, 0x00, - 0xff, 0xff, 0x29, 0xa1, 0xc4, 0xd2, 0x46, 0x04, 0x00, 0x00, + 0x10, 0x87, 0xe3, 0x26, 0x4d, 0xd3, 0x6d, 0x13, 0xd1, 0x6d, 0x23, 0x99, 0xa8, 0xd8, 0xc1, 0x48, + 0x28, 0x12, 0xaa, 0x4d, 0x21, 0x17, 0x38, 0x9a, 0x03, 0xe4, 0x86, 0xb6, 0x9c, 0x90, 0x50, 0x64, + 0xaf, 0xa7, 0xee, 0x2a, 0xb1, 0x37, 0x78, 0x37, 0x81, 0x3e, 0x05, 0x3c, 0x56, 0x8f, 0x3d, 0x72, + 0xb2, 0x50, 0xf2, 0x06, 0x39, 0x72, 0x42, 0xfe, 0x9b, 0x44, 0x8d, 0x10, 0xed, 0xcd, 0x3b, 0xf3, + 0x9b, 0xef, 0x9b, 0x83, 0x07, 0x3d, 0x65, 0x2e, 0xb5, 0x28, 0x8f, 0xc0, 0xa2, 0x57, 0x4e, 0x18, + 0xc2, 0xd8, 0x9a, 0x9d, 0x5b, 0x3e, 0x84, 0x20, 0x98, 0x30, 0x27, 0x11, 0x97, 0x1c, 0x1f, 0x33, + 0x97, 0x9a, 0x49, 0xc4, 0xcc, 0x23, 0xe6, 0xec, 0xbc, 0x73, 0xe2, 0x73, 0x9f, 0xa7, 0x7d, 0x2b, + 0xf9, 0xca, 0xa2, 0x9d, 0xad, 0xb4, 0x62, 0x2a, 0x8d, 0x18, 0x8b, 0x5d, 0x74, 0xf8, 0x3e, 0xe3, + 0x5f, 0x48, 0x47, 0x02, 0xfe, 0x82, 0x1a, 0x79, 0x42, 0xa8, 0x4a, 0xb7, 0xda, 0x3b, 0x78, 0xf5, + 0xdc, 0xdc, 0x62, 0x34, 0x07, 0x1e, 0x84, 0x92, 0x5d, 0x32, 0xf0, 0xde, 0x65, 0x45, 0xfb, 0xf1, + 0x4d, 0xac, 0x57, 0xfe, 0xc4, 0xfa, 0xd1, 0x9d, 0x16, 0x29, 0x91, 0x98, 0xa0, 0x47, 0x0e, 0x1d, + 0x85, 0xfc, 0xdb, 0x18, 0x3c, 0x1f, 0x02, 0x08, 0xa5, 0x50, 0x77, 0x52, 0x4d, 0x77, 0xab, 0xe6, + 0xa3, 0x43, 0x47, 0x20, 0xd3, 0xd5, 0xec, 0x5a, 0x22, 0x20, 0x77, 0xe6, 0xf1, 0x07, 0x74, 0x40, + 0x79, 0x10, 0x30, 0x99, 0xe1, 0xaa, 0xf7, 0xc2, 0xad, 0x8f, 0x62, 0x1b, 0x35, 0x22, 0xa0, 0xc0, + 0x26, 0x52, 0xa8, 0xb5, 0x7b, 0x61, 0xca, 0x39, 0xcc, 0x50, 0x4b, 0x40, 0xe8, 0x0d, 0x05, 0x7c, + 0x9d, 0x42, 0x48, 0x41, 0xa8, 0xbb, 0x29, 0xe9, 0xd9, 0xbf, 0x48, 0x79, 0xd6, 0x7e, 0x92, 0xc0, + 0x96, 0xb1, 0xde, 0xbe, 0x76, 0x82, 0xf1, 0x5b, 0x63, 0x13, 0x64, 0x90, 0x66, 0x52, 0x28, 0xc2, + 0xa9, 0x2a, 0x02, 0x3a, 0x5b, 0x53, 0xd5, 0x1f, 0xac, 0xda, 0x04, 0x19, 0xa4, 0x99, 0x14, 0x56, + 0xaa, 0x4b, 0xd4, 0x74, 0xe8, 0x68, 0xcd, 0xb4, 0xf7, 0xff, 0xa6, 0xd3, 0xdc, 0x74, 0x92, 0x99, + 0x36, 0x38, 0x06, 0x39, 0x74, 0xe8, 0x68, 0xe5, 0xf9, 0x84, 0xda, 0x21, 0x7c, 0x97, 0xc3, 0x9c, + 0x56, 0x06, 0xd5, 0x46, 0x57, 0xe9, 0xd5, 0xec, 0xee, 0x32, 0xd6, 0x4f, 0x33, 0xcc, 0xd6, 0x98, + 0x41, 0x8e, 0x93, 0x7a, 0xfe, 0xdf, 0x15, 0x58, 0xe3, 0x87, 0x82, 0x5a, 0x9b, 0x4b, 0xe1, 0x17, + 0x68, 0x6f, 0xc2, 0x23, 0x39, 0x64, 0x9e, 0xaa, 0x74, 0x95, 0xde, 0xbe, 0x8d, 0x97, 0xb1, 0xde, + 0xca, 0xd0, 0x79, 0xc3, 0x20, 0xf5, 0xe4, 0x6b, 0xe0, 0xe1, 0x3e, 0x42, 0x85, 0x89, 0x79, 0xea, + 0x4e, 0x9a, 0x6f, 0x2f, 0x63, 0xfd, 0x28, 0xcb, 0xaf, 0x7a, 0x06, 0xd9, 0xcf, 0x1f, 0x03, 0x0f, + 0x77, 0x50, 0xa3, 0x5c, 0xbf, 0x9a, 0xac, 0x4f, 0xca, 0xb7, 0x7d, 0x71, 0x33, 0xd7, 0x94, 0xdb, + 0xb9, 0xa6, 0xfc, 0x9e, 0x6b, 0xca, 0xcf, 0x85, 0x56, 0xb9, 0x5d, 0x68, 0x95, 0x5f, 0x0b, 0xad, + 0xf2, 0xf9, 0x8d, 0xcf, 0xe4, 0xd5, 0xd4, 0x35, 0x29, 0x0f, 0x2c, 0xca, 0x45, 0xc0, 0x85, 0xc5, + 0x5c, 0x7a, 0xe6, 0x73, 0x6b, 0xd6, 0xb7, 0x02, 0xee, 0x4d, 0xc7, 0x20, 0xb2, 0xa3, 0x7e, 0xd9, + 0x3f, 0x2b, 0xee, 0x5a, 0x5e, 0x4f, 0x40, 0xb8, 0xf5, 0xf4, 0xa6, 0x5f, 0xff, 0x0d, 0x00, 0x00, + 0xff, 0xff, 0x37, 0x95, 0x0a, 0xe0, 0x46, 0x04, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/modules/core/04-channel/types/genesis_test.go b/modules/core/04-channel/types/genesis_test.go index 856c0833c88..0e1a64b02b6 100644 --- a/modules/core/04-channel/types/genesis_test.go +++ b/modules/core/04-channel/types/genesis_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) const ( diff --git a/modules/core/04-channel/types/keys.go b/modules/core/04-channel/types/keys.go index 8b81da4cfbb..347fd91a677 100644 --- a/modules/core/04-channel/types/keys.go +++ b/modules/core/04-channel/types/keys.go @@ -6,7 +6,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) const ( diff --git a/modules/core/04-channel/types/keys_test.go b/modules/core/04-channel/types/keys_test.go index f5bef1eaf2d..c6c2e3fcec2 100644 --- a/modules/core/04-channel/types/keys_test.go +++ b/modules/core/04-channel/types/keys_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // tests ParseChannelSequence and IsValidChannelID diff --git a/modules/core/04-channel/types/msgs.go b/modules/core/04-channel/types/msgs.go index ea94f4b18b4..107afa08594 100644 --- a/modules/core/04-channel/types/msgs.go +++ b/modules/core/04-channel/types/msgs.go @@ -6,9 +6,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) var _ sdk.Msg = &MsgChannelOpenInit{} diff --git a/modules/core/04-channel/types/msgs_test.go b/modules/core/04-channel/types/msgs_test.go index 623ed992d22..dda7668e365 100644 --- a/modules/core/04-channel/types/msgs_test.go +++ b/modules/core/04-channel/types/msgs_test.go @@ -12,11 +12,11 @@ import ( abci "github.com/tendermint/tendermint/abci/types" dbm "github.com/tendermint/tm-db" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/testing/simapp" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) const ( diff --git a/modules/core/04-channel/types/packet.go b/modules/core/04-channel/types/packet.go index dd59c8bfde9..caba2fc2591 100644 --- a/modules/core/04-channel/types/packet.go +++ b/modules/core/04-channel/types/packet.go @@ -7,9 +7,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // CommitPacket returns the packet commitment bytes. The commitment consists of: diff --git a/modules/core/04-channel/types/packet_test.go b/modules/core/04-channel/types/packet_test.go index 1020e763e50..f1ed49b15a2 100644 --- a/modules/core/04-channel/types/packet_test.go +++ b/modules/core/04-channel/types/packet_test.go @@ -7,8 +7,8 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) func TestCommitPacket(t *testing.T) { diff --git a/modules/core/04-channel/types/query.go b/modules/core/04-channel/types/query.go index 31d58e50632..0a4662acc01 100644 --- a/modules/core/04-channel/types/query.go +++ b/modules/core/04-channel/types/query.go @@ -3,8 +3,8 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var ( diff --git a/modules/core/04-channel/types/query.pb.go b/modules/core/04-channel/types/query.pb.go index 1345b0bcdea..75970287318 100644 --- a/modules/core/04-channel/types/query.pb.go +++ b/modules/core/04-channel/types/query.pb.go @@ -8,7 +8,7 @@ import ( fmt "fmt" types1 "github.com/cosmos/cosmos-sdk/codec/types" query "github.com/cosmos/cosmos-sdk/types/query" - types "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + types "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -1709,99 +1709,99 @@ func init() { proto.RegisterFile("ibc/core/channel/v1/query.proto", fileDescript var fileDescriptor_1034a1e9abc4cca1 = []byte{ // 1490 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xcf, 0x6f, 0xd4, 0xc6, - 0x17, 0xcf, 0x6c, 0x16, 0x48, 0x1e, 0x7c, 0xf9, 0x31, 0x49, 0x20, 0x98, 0xb0, 0x09, 0xfb, 0x55, - 0x4b, 0x40, 0xc2, 0x43, 0x12, 0x4a, 0x69, 0xd5, 0x22, 0x91, 0x48, 0x85, 0x54, 0xe5, 0x97, 0x53, - 0x54, 0x40, 0x6a, 0xb7, 0x5e, 0xef, 0xb0, 0xb1, 0x92, 0xb5, 0xcd, 0xda, 0xbb, 0x80, 0xd2, 0xad, - 0xaa, 0x1e, 0x28, 0x52, 0x2f, 0x55, 0x39, 0x54, 0xea, 0xa5, 0x52, 0x6f, 0x1c, 0x7a, 0xe8, 0x5f, - 0xd0, 0x2b, 0xb7, 0x22, 0xd1, 0x43, 0x25, 0x24, 0x5a, 0x11, 0x24, 0x7a, 0xed, 0xa5, 0xe7, 0xca, - 0xf3, 0xc3, 0x6b, 0xef, 0xda, 0x4e, 0x36, 0x9b, 0x95, 0xa2, 0xde, 0xec, 0xf1, 0xbc, 0x37, 0x9f, - 0xcf, 0xe7, 0xcd, 0x7b, 0x79, 0x6f, 0x03, 0xe3, 0x66, 0xd1, 0x20, 0x86, 0x5d, 0xa5, 0xc4, 0x58, - 0xd4, 0x2d, 0x8b, 0x2e, 0x93, 0xfa, 0x14, 0xb9, 0x5d, 0xa3, 0xd5, 0x7b, 0xaa, 0x53, 0xb5, 0x3d, - 0x1b, 0x0f, 0x99, 0x45, 0x43, 0xf5, 0x37, 0xa8, 0x62, 0x83, 0x5a, 0x9f, 0x52, 0x42, 0x56, 0xcb, - 0x26, 0xb5, 0x3c, 0xdf, 0x88, 0x3f, 0x71, 0x2b, 0xe5, 0xb8, 0x61, 0xbb, 0x15, 0xdb, 0x25, 0x45, - 0xdd, 0xa5, 0xdc, 0x1d, 0xa9, 0x4f, 0x15, 0xa9, 0xa7, 0x4f, 0x11, 0x47, 0x2f, 0x9b, 0x96, 0xee, - 0x99, 0xb6, 0x25, 0xf6, 0x1e, 0x89, 0x83, 0x20, 0x0f, 0xe3, 0x5b, 0xc6, 0xca, 0xb6, 0x5d, 0x5e, - 0xa6, 0x44, 0x77, 0x4c, 0xa2, 0x5b, 0x96, 0xed, 0x31, 0x7b, 0x57, 0x7c, 0x3d, 0x28, 0xbe, 0xb2, - 0xb7, 0x62, 0xed, 0x16, 0xd1, 0x2d, 0x81, 0x5e, 0x19, 0x2e, 0xdb, 0x65, 0x9b, 0x3d, 0x12, 0xff, - 0x89, 0xaf, 0xe6, 0x2f, 0xc2, 0xd0, 0x55, 0x1f, 0xd3, 0x1c, 0x3f, 0x44, 0xa3, 0xb7, 0x6b, 0xd4, - 0xf5, 0xf0, 0x01, 0xd8, 0xe1, 0xd8, 0x55, 0xaf, 0x60, 0x96, 0x46, 0xd1, 0x04, 0x9a, 0x1c, 0xd4, - 0xb6, 0xfb, 0xaf, 0xf3, 0x25, 0x7c, 0x18, 0x40, 0xe0, 0xf1, 0xbf, 0x65, 0xd8, 0xb7, 0x41, 0xb1, - 0x32, 0x5f, 0xca, 0x3f, 0x42, 0x30, 0x1c, 0xf5, 0xe7, 0x3a, 0xb6, 0xe5, 0x52, 0x7c, 0x1a, 0x76, - 0x88, 0x5d, 0xcc, 0xe1, 0xce, 0xe9, 0x31, 0x35, 0x46, 0x4d, 0x55, 0x9a, 0xc9, 0xcd, 0x78, 0x18, - 0xb6, 0x39, 0x55, 0xdb, 0xbe, 0xc5, 0x8e, 0xda, 0xa5, 0xf1, 0x17, 0x3c, 0x07, 0xbb, 0xd8, 0x43, - 0x61, 0x91, 0x9a, 0xe5, 0x45, 0x6f, 0xb4, 0x9f, 0xb9, 0x54, 0x42, 0x2e, 0x79, 0x04, 0xea, 0x53, - 0xea, 0x05, 0xb6, 0x63, 0x36, 0xfb, 0xf8, 0xf9, 0x78, 0x9f, 0xb6, 0x93, 0x59, 0xf1, 0xa5, 0xfc, - 0x27, 0x51, 0xa8, 0xae, 0xe4, 0xfe, 0x1e, 0x40, 0x33, 0x30, 0x02, 0xed, 0xeb, 0x2a, 0x8f, 0xa2, - 0xea, 0x47, 0x51, 0xe5, 0x97, 0x42, 0x44, 0x51, 0xbd, 0xa2, 0x97, 0xa9, 0xb0, 0xd5, 0x42, 0x96, - 0xf9, 0xe7, 0x08, 0x46, 0x5a, 0x0e, 0x10, 0x62, 0xcc, 0xc2, 0x80, 0xe0, 0xe7, 0x8e, 0xa2, 0x89, - 0x7e, 0xe6, 0x3f, 0x4e, 0x8d, 0xf9, 0x12, 0xb5, 0x3c, 0xf3, 0x96, 0x49, 0x4b, 0x52, 0x97, 0xc0, - 0x0e, 0x9f, 0x8f, 0xa0, 0xcc, 0x30, 0x94, 0x47, 0xd7, 0x44, 0xc9, 0x01, 0x84, 0x61, 0xe2, 0x33, - 0xb0, 0xbd, 0x43, 0x15, 0xc5, 0xfe, 0xfc, 0x03, 0x04, 0x39, 0x4e, 0xd0, 0xb6, 0x2c, 0x6a, 0xf8, - 0xde, 0x5a, 0xb5, 0xcc, 0x01, 0x18, 0xc1, 0x47, 0x71, 0x95, 0x42, 0x2b, 0x2d, 0x5a, 0x67, 0x36, - 0xac, 0xf5, 0x5f, 0x08, 0xc6, 0x13, 0xa1, 0xfc, 0xb7, 0x54, 0xbf, 0x2e, 0x45, 0xe7, 0x98, 0xe6, - 0xd8, 0xee, 0x05, 0x4f, 0xf7, 0x68, 0xb7, 0xc9, 0xfb, 0x47, 0x20, 0x62, 0x8c, 0x6b, 0x21, 0xa2, - 0x0e, 0x07, 0xcc, 0x40, 0x9f, 0x02, 0x87, 0x5a, 0x70, 0xfd, 0x2d, 0x22, 0x53, 0x8e, 0xc5, 0x11, - 0x09, 0x49, 0x1a, 0xf2, 0x39, 0x62, 0xc6, 0x2d, 0xf7, 0x32, 0xe5, 0x7f, 0x42, 0x70, 0x24, 0xc2, - 0xd0, 0xe7, 0x64, 0xb9, 0x35, 0x77, 0x33, 0xf4, 0xc3, 0x47, 0x61, 0x4f, 0x95, 0xd6, 0x4d, 0xd7, - 0xb4, 0xad, 0x82, 0x55, 0xab, 0x14, 0x69, 0x95, 0xa1, 0xcc, 0x6a, 0xbb, 0xe5, 0xf2, 0x25, 0xb6, - 0x1a, 0xd9, 0x28, 0xe8, 0x64, 0xa3, 0x1b, 0x05, 0xde, 0x67, 0x08, 0xf2, 0x69, 0x78, 0x45, 0x50, - 0xde, 0x85, 0x3d, 0x86, 0xfc, 0x12, 0x09, 0xc6, 0xb0, 0xca, 0xff, 0x1e, 0xa8, 0xf2, 0xef, 0x81, - 0x7a, 0xce, 0xba, 0xa7, 0xed, 0x36, 0x22, 0x6e, 0xf0, 0x21, 0x18, 0x14, 0x81, 0x0c, 0x58, 0x0d, - 0xf0, 0x85, 0xf9, 0x52, 0x33, 0x1a, 0xfd, 0x69, 0xd1, 0xc8, 0x6e, 0x24, 0x1a, 0x55, 0x18, 0x63, - 0xe4, 0xae, 0xe8, 0xc6, 0x12, 0xf5, 0xe6, 0xec, 0x4a, 0xc5, 0xf4, 0x2a, 0xd4, 0xf2, 0xba, 0x8d, - 0x83, 0x02, 0x03, 0xae, 0xef, 0xc2, 0x32, 0xa8, 0x08, 0x40, 0xf0, 0x9e, 0xff, 0x1e, 0xc1, 0xe1, - 0x84, 0x43, 0x85, 0x98, 0xac, 0x64, 0xc9, 0x55, 0x76, 0xf0, 0x2e, 0x2d, 0xb4, 0xd2, 0xcb, 0xeb, - 0xf9, 0x43, 0x12, 0x38, 0xb7, 0x5b, 0x49, 0xa2, 0x75, 0xb6, 0x7f, 0xc3, 0x75, 0xf6, 0x95, 0x2c, - 0xf9, 0x31, 0x08, 0x83, 0x32, 0xbb, 0xb3, 0xa9, 0x96, 0xac, 0xb4, 0x13, 0xb1, 0x95, 0x96, 0x3b, - 0xe1, 0x77, 0x39, 0x6c, 0xb4, 0x15, 0xca, 0xac, 0x0d, 0x07, 0x43, 0x44, 0x35, 0x6a, 0x50, 0xd3, - 0xe9, 0xe9, 0xcd, 0x7c, 0x88, 0x40, 0x89, 0x3b, 0x51, 0xc8, 0xaa, 0xc0, 0x40, 0xd5, 0x5f, 0xaa, - 0x53, 0xee, 0x77, 0x40, 0x0b, 0xde, 0x7b, 0x99, 0xa3, 0x77, 0x44, 0xc1, 0xe4, 0xa0, 0xce, 0x19, - 0x4b, 0x96, 0x7d, 0x67, 0x99, 0x96, 0xca, 0xb4, 0xd7, 0x89, 0xfa, 0x48, 0x96, 0xbe, 0x84, 0x93, - 0x85, 0x2c, 0x93, 0xb0, 0x47, 0x8f, 0x7e, 0x12, 0x29, 0xdb, 0xba, 0xdc, 0xcb, 0xbc, 0x7d, 0x99, - 0x8a, 0x75, 0xab, 0x24, 0x2f, 0x3e, 0x0b, 0x87, 0x1c, 0x06, 0xb0, 0xd0, 0xcc, 0xb5, 0x82, 0x14, - 0xdc, 0x1d, 0xcd, 0x4e, 0xf4, 0x4f, 0x66, 0xb5, 0x83, 0x4e, 0x4b, 0x66, 0x2f, 0xc8, 0x0d, 0xf9, - 0x7f, 0x10, 0xfc, 0x3f, 0x95, 0xa6, 0x88, 0xc9, 0x07, 0xb0, 0xb7, 0x45, 0xfc, 0xf5, 0x97, 0x81, - 0x36, 0xcb, 0xad, 0x50, 0x0b, 0xbe, 0x93, 0x75, 0xf9, 0x9a, 0x25, 0x73, 0x8e, 0x63, 0xee, 0x3a, - 0xb4, 0x6b, 0x84, 0xa4, 0x7f, 0xad, 0x90, 0xdc, 0x15, 0xe5, 0x38, 0x06, 0x98, 0x08, 0xc6, 0x18, - 0x0c, 0x36, 0xfd, 0x21, 0xe6, 0xaf, 0xb9, 0x10, 0xd2, 0x24, 0xd3, 0xa1, 0x26, 0xf7, 0x65, 0xb9, - 0x6a, 0x1e, 0x7d, 0xce, 0x58, 0xea, 0x5a, 0x90, 0x93, 0x30, 0x2c, 0x04, 0xd1, 0x8d, 0xa5, 0x36, - 0x25, 0xb0, 0x23, 0x6f, 0x5e, 0x53, 0x82, 0x1a, 0x1c, 0x8a, 0xc5, 0xd1, 0x63, 0xfe, 0x37, 0x44, - 0xaf, 0x7c, 0x89, 0xde, 0x0d, 0xe2, 0xa1, 0x71, 0x00, 0xdd, 0xf6, 0xe1, 0x3f, 0x23, 0x98, 0x48, - 0xf6, 0x2d, 0x78, 0x4d, 0xc3, 0x88, 0x45, 0xef, 0x36, 0x2f, 0x4b, 0x41, 0xb0, 0x67, 0x47, 0x65, - 0xb5, 0x21, 0xab, 0xdd, 0xb6, 0x87, 0x25, 0x70, 0xfa, 0xeb, 0xfd, 0xb0, 0x8d, 0x61, 0xc6, 0x3f, - 0x22, 0xd8, 0x21, 0xda, 0x55, 0x3c, 0x19, 0x9b, 0xef, 0x31, 0x3f, 0x38, 0x28, 0xc7, 0xd6, 0xb1, - 0x93, 0x33, 0xcf, 0xcf, 0x7e, 0xf9, 0xf4, 0xe5, 0xc3, 0xcc, 0x3b, 0xf8, 0x6d, 0x92, 0xf2, 0x6b, - 0x89, 0x4b, 0x56, 0x9a, 0x12, 0x37, 0x88, 0x2f, 0xbc, 0x4b, 0x56, 0x44, 0x38, 0x1a, 0xf8, 0x01, - 0x82, 0x01, 0x39, 0x20, 0xe2, 0xb5, 0xcf, 0x96, 0xd7, 0x5a, 0x39, 0xbe, 0x9e, 0xad, 0x02, 0xe7, - 0x6b, 0x0c, 0xe7, 0x38, 0x3e, 0x9c, 0x8a, 0x13, 0xff, 0x82, 0x00, 0xb7, 0x4f, 0xad, 0x78, 0x26, - 0xe5, 0xa4, 0xa4, 0x71, 0x5b, 0x39, 0xd5, 0x99, 0x91, 0x00, 0x7a, 0x96, 0x01, 0x3d, 0x83, 0x4f, - 0xc7, 0x03, 0x0d, 0x0c, 0x7d, 0x4d, 0x83, 0x97, 0x46, 0x93, 0xc1, 0x13, 0x9f, 0x41, 0xdb, 0xc8, - 0x98, 0xca, 0x20, 0x69, 0x76, 0x4d, 0x65, 0x90, 0x38, 0x95, 0xe6, 0x2f, 0x33, 0x06, 0xf3, 0xf8, - 0xfc, 0xc6, 0xaf, 0x04, 0x09, 0xcf, 0xb2, 0xf8, 0xdb, 0x0c, 0x8c, 0xc4, 0xce, 0x5c, 0xf8, 0xf4, - 0xda, 0x00, 0xe3, 0x86, 0x4a, 0xe5, 0xcd, 0x8e, 0xed, 0x04, 0xb7, 0xaf, 0x10, 0x23, 0xf7, 0x05, - 0xc2, 0x9f, 0x77, 0xc3, 0x2e, 0x3a, 0x1f, 0x12, 0x39, 0x68, 0x92, 0x95, 0x96, 0x91, 0xb5, 0x41, - 0x78, 0x19, 0x08, 0x7d, 0xe0, 0x0b, 0x0d, 0xfc, 0x0c, 0xc1, 0xde, 0xd6, 0xbe, 0x1f, 0x4f, 0x25, - 0xf3, 0x4a, 0x98, 0xeb, 0x94, 0xe9, 0x4e, 0x4c, 0x84, 0x0a, 0x9f, 0x32, 0x11, 0x6e, 0xe2, 0xeb, - 0x5d, 0x68, 0xd0, 0xf6, 0x97, 0xd6, 0x25, 0x2b, 0xb2, 0x7c, 0x36, 0xf0, 0x53, 0x04, 0xfb, 0xda, - 0xa6, 0x1a, 0xdc, 0x01, 0xd6, 0x20, 0x0b, 0x67, 0x3a, 0xb2, 0x11, 0x04, 0xaf, 0x31, 0x82, 0x97, - 0xf1, 0xc5, 0x4d, 0x25, 0x88, 0x7f, 0x45, 0xf0, 0xbf, 0xc8, 0x40, 0x81, 0xd5, 0xb5, 0xd0, 0x45, - 0x67, 0x1d, 0x85, 0xac, 0x7b, 0xbf, 0x60, 0xf2, 0x31, 0x63, 0xf2, 0x11, 0xbe, 0xd6, 0x3d, 0x93, - 0x2a, 0x77, 0x1d, 0x89, 0xd3, 0x2a, 0x82, 0x91, 0xd8, 0x06, 0x34, 0x2d, 0x35, 0xd3, 0xc6, 0x97, - 0xb4, 0xd4, 0x4c, 0x1d, 0x3e, 0xf2, 0x37, 0x18, 0xd3, 0x05, 0x7c, 0xb5, 0x7b, 0xa6, 0xba, 0xb1, - 0x14, 0x61, 0xf9, 0x0a, 0xc1, 0xfe, 0xf8, 0x36, 0x1b, 0x77, 0x0a, 0x37, 0xb8, 0x97, 0x67, 0x3a, - 0x37, 0x14, 0x44, 0x6f, 0x32, 0xa2, 0x1f, 0x62, 0x6d, 0x53, 0x88, 0x46, 0xe9, 0xdc, 0xcf, 0xc0, - 0xbe, 0xb6, 0xf6, 0x35, 0x2d, 0xef, 0x92, 0x9a, 0xf0, 0xb4, 0xbc, 0x4b, 0xec, 0x8f, 0x37, 0xa9, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xcf, 0x6f, 0x13, 0xc7, + 0x17, 0xcf, 0x38, 0x06, 0x92, 0x07, 0x5f, 0x7e, 0x4c, 0x12, 0x08, 0x4b, 0x70, 0x82, 0xbf, 0x6a, + 0x09, 0x48, 0xec, 0x90, 0x40, 0x29, 0xad, 0x5a, 0x24, 0x12, 0xa9, 0x90, 0xaa, 0xfc, 0xda, 0x14, + 0x15, 0x90, 0x5a, 0x77, 0xbd, 0x1e, 0x9c, 0x55, 0xe2, 0xdd, 0xc5, 0xbb, 0x36, 0xa0, 0xd4, 0x55, + 0xd5, 0x03, 0x45, 0xea, 0xa5, 0x2a, 0x87, 0x4a, 0xbd, 0x54, 0xea, 0x8d, 0x43, 0x0f, 0xfd, 0x0b, + 0x7a, 0xe5, 0x56, 0x24, 0x7a, 0xa8, 0x84, 0x44, 0x2b, 0x82, 0x44, 0xaf, 0xbd, 0xf4, 0x5c, 0xed, + 0xfc, 0x58, 0xef, 0xda, 0xbb, 0x1b, 0x3b, 0x8e, 0x25, 0xd4, 0xdb, 0xee, 0xec, 0xbc, 0x37, 0x9f, + 0xcf, 0xe7, 0xcd, 0x7b, 0x79, 0xcf, 0x81, 0x49, 0xb3, 0x68, 0x10, 0xc3, 0xae, 0x52, 0x62, 0x2c, + 0xe9, 0x96, 0x45, 0x57, 0x48, 0x7d, 0x86, 0xdc, 0xaa, 0xd1, 0xea, 0x5d, 0xd5, 0xa9, 0xda, 0x9e, + 0x8d, 0x47, 0xcc, 0xa2, 0xa1, 0xfa, 0x1b, 0x54, 0xb1, 0x41, 0xad, 0xcf, 0x28, 0x21, 0xab, 0x15, + 0x93, 0x5a, 0x9e, 0x6f, 0xc4, 0x9f, 0xb8, 0x95, 0x72, 0xd4, 0xb0, 0xdd, 0x8a, 0xed, 0x92, 0xa2, + 0xee, 0x52, 0xee, 0x8e, 0xd4, 0x67, 0x8a, 0xd4, 0xd3, 0x67, 0x88, 0xa3, 0x97, 0x4d, 0x4b, 0xf7, + 0x4c, 0xdb, 0x12, 0x7b, 0x0f, 0xc5, 0x41, 0x90, 0x87, 0xf1, 0x2d, 0x13, 0x65, 0xdb, 0x2e, 0xaf, + 0x50, 0xa2, 0x3b, 0x26, 0xd1, 0x2d, 0xcb, 0xf6, 0x98, 0xbd, 0x2b, 0xbe, 0xee, 0x17, 0x5f, 0xd9, + 0x5b, 0xb1, 0x76, 0x93, 0xe8, 0x96, 0x40, 0xaf, 0x8c, 0x96, 0xed, 0xb2, 0xcd, 0x1e, 0x89, 0xff, + 0xc4, 0x57, 0xf3, 0x17, 0x60, 0xe4, 0x8a, 0x8f, 0x69, 0x9e, 0x1f, 0xa2, 0xd1, 0x5b, 0x35, 0xea, + 0x7a, 0x78, 0x1f, 0x6c, 0x73, 0xec, 0xaa, 0x57, 0x30, 0x4b, 0xe3, 0x68, 0x0a, 0x4d, 0x0f, 0x6b, + 0x5b, 0xfd, 0xd7, 0x85, 0x12, 0x3e, 0x08, 0x20, 0xf0, 0xf8, 0xdf, 0x32, 0xec, 0xdb, 0xb0, 0x58, + 0x59, 0x28, 0xe5, 0x1f, 0x22, 0x18, 0x8d, 0xfa, 0x73, 0x1d, 0xdb, 0x72, 0x29, 0x3e, 0x05, 0xdb, + 0xc4, 0x2e, 0xe6, 0x70, 0xfb, 0xec, 0x84, 0x1a, 0xa3, 0xa6, 0x2a, 0xcd, 0xe4, 0x66, 0x3c, 0x0a, + 0x5b, 0x9c, 0xaa, 0x6d, 0xdf, 0x64, 0x47, 0xed, 0xd0, 0xf8, 0x0b, 0x9e, 0x87, 0x1d, 0xec, 0xa1, + 0xb0, 0x44, 0xcd, 0xf2, 0x92, 0x37, 0x3e, 0xc8, 0x5c, 0x2a, 0x21, 0x97, 0x3c, 0x02, 0xf5, 0x19, + 0xf5, 0x3c, 0xdb, 0x31, 0x97, 0x7d, 0xf4, 0x6c, 0x72, 0x40, 0xdb, 0xce, 0xac, 0xf8, 0x52, 0xfe, + 0x93, 0x28, 0x54, 0x57, 0x72, 0x7f, 0x0f, 0xa0, 0x19, 0x18, 0x81, 0xf6, 0x75, 0x95, 0x47, 0x51, + 0xf5, 0xa3, 0xa8, 0xf2, 0x4b, 0x21, 0xa2, 0xa8, 0x5e, 0xd6, 0xcb, 0x54, 0xd8, 0x6a, 0x21, 0xcb, + 0xfc, 0x33, 0x04, 0x63, 0x2d, 0x07, 0x08, 0x31, 0xe6, 0x60, 0x48, 0xf0, 0x73, 0xc7, 0xd1, 0xd4, + 0x20, 0xf3, 0x1f, 0xa7, 0xc6, 0x42, 0x89, 0x5a, 0x9e, 0x79, 0xd3, 0xa4, 0x25, 0xa9, 0x4b, 0x60, + 0x87, 0xcf, 0x45, 0x50, 0x66, 0x18, 0xca, 0xc3, 0xeb, 0xa2, 0xe4, 0x00, 0xc2, 0x30, 0xf1, 0x69, + 0xd8, 0xda, 0xa5, 0x8a, 0x62, 0x7f, 0xfe, 0x3e, 0x82, 0x1c, 0x27, 0x68, 0x5b, 0x16, 0x35, 0x7c, + 0x6f, 0xad, 0x5a, 0xe6, 0x00, 0x8c, 0xe0, 0xa3, 0xb8, 0x4a, 0xa1, 0x95, 0x16, 0xad, 0x33, 0x1b, + 0xd6, 0xfa, 0x2f, 0x04, 0x93, 0x89, 0x50, 0xfe, 0x5b, 0xaa, 0x5f, 0x93, 0xa2, 0x73, 0x4c, 0xf3, + 0x6c, 0xf7, 0xa2, 0xa7, 0x7b, 0xb4, 0xd7, 0xe4, 0xfd, 0x23, 0x10, 0x31, 0xc6, 0xb5, 0x10, 0x51, + 0x87, 0x7d, 0x66, 0xa0, 0x4f, 0x81, 0x43, 0x2d, 0xb8, 0xfe, 0x16, 0x91, 0x29, 0x47, 0xe2, 0x88, + 0x84, 0x24, 0x0d, 0xf9, 0x1c, 0x33, 0xe3, 0x96, 0xfb, 0x99, 0xf2, 0x3f, 0x21, 0x38, 0x14, 0x61, + 0xe8, 0x73, 0xb2, 0xdc, 0x9a, 0xbb, 0x19, 0xfa, 0xe1, 0xc3, 0xb0, 0xab, 0x4a, 0xeb, 0xa6, 0x6b, + 0xda, 0x56, 0xc1, 0xaa, 0x55, 0x8a, 0xb4, 0xca, 0x50, 0x66, 0xb5, 0x9d, 0x72, 0xf9, 0x22, 0x5b, + 0x8d, 0x6c, 0x14, 0x74, 0xb2, 0xd1, 0x8d, 0x02, 0xef, 0x53, 0x04, 0xf9, 0x34, 0xbc, 0x22, 0x28, + 0xef, 0xc2, 0x2e, 0x43, 0x7e, 0x89, 0x04, 0x63, 0x54, 0xe5, 0x7f, 0x0f, 0x54, 0xf9, 0xf7, 0x40, + 0x3d, 0x6b, 0xdd, 0xd5, 0x76, 0x1a, 0x11, 0x37, 0xf8, 0x00, 0x0c, 0x8b, 0x40, 0x06, 0xac, 0x86, + 0xf8, 0xc2, 0x42, 0xa9, 0x19, 0x8d, 0xc1, 0xb4, 0x68, 0x64, 0x37, 0x12, 0x8d, 0x2a, 0x4c, 0x30, + 0x72, 0x97, 0x75, 0x63, 0x99, 0x7a, 0xf3, 0x76, 0xa5, 0x62, 0x7a, 0x15, 0x6a, 0x79, 0xbd, 0xc6, + 0x41, 0x81, 0x21, 0xd7, 0x77, 0x61, 0x19, 0x54, 0x04, 0x20, 0x78, 0xcf, 0x7f, 0x8f, 0xe0, 0x60, + 0xc2, 0xa1, 0x42, 0x4c, 0x56, 0xb2, 0xe4, 0x2a, 0x3b, 0x78, 0x87, 0x16, 0x5a, 0xe9, 0xe7, 0xf5, + 0xfc, 0x21, 0x09, 0x9c, 0xdb, 0xab, 0x24, 0xd1, 0x3a, 0x3b, 0xb8, 0xe1, 0x3a, 0xfb, 0x52, 0x96, + 0xfc, 0x18, 0x84, 0x41, 0x99, 0xdd, 0xde, 0x54, 0x4b, 0x56, 0xda, 0xa9, 0xd8, 0x4a, 0xcb, 0x9d, + 0xf0, 0xbb, 0x1c, 0x36, 0x7a, 0x15, 0xca, 0xac, 0x0d, 0xfb, 0x43, 0x44, 0x35, 0x6a, 0x50, 0xd3, + 0xe9, 0xeb, 0xcd, 0x7c, 0x80, 0x40, 0x89, 0x3b, 0x51, 0xc8, 0xaa, 0xc0, 0x50, 0xd5, 0x5f, 0xaa, + 0x53, 0xee, 0x77, 0x48, 0x0b, 0xde, 0xfb, 0x99, 0xa3, 0xb7, 0x45, 0xc1, 0xe4, 0xa0, 0xce, 0x1a, + 0xcb, 0x96, 0x7d, 0x7b, 0x85, 0x96, 0xca, 0xb4, 0xdf, 0x89, 0xfa, 0x50, 0x96, 0xbe, 0x84, 0x93, + 0x85, 0x2c, 0xd3, 0xb0, 0x4b, 0x8f, 0x7e, 0x12, 0x29, 0xdb, 0xba, 0xdc, 0xcf, 0xbc, 0x7d, 0x91, + 0x8a, 0xf5, 0x55, 0x49, 0x5e, 0x7c, 0x06, 0x0e, 0x38, 0x0c, 0x60, 0xa1, 0x99, 0x6b, 0x05, 0x29, + 0xb8, 0x3b, 0x9e, 0x9d, 0x1a, 0x9c, 0xce, 0x6a, 0xfb, 0x9d, 0x96, 0xcc, 0x5e, 0x94, 0x1b, 0xf2, + 0xff, 0x20, 0xf8, 0x7f, 0x2a, 0x4d, 0x11, 0x93, 0x0f, 0x60, 0x77, 0x8b, 0xf8, 0x9d, 0x97, 0x81, + 0x36, 0xcb, 0x57, 0xa1, 0x16, 0x7c, 0x27, 0xeb, 0xf2, 0x55, 0x4b, 0xe6, 0x1c, 0xc7, 0xdc, 0x73, + 0x68, 0xd7, 0x09, 0xc9, 0xe0, 0x7a, 0x21, 0xb9, 0x23, 0xca, 0x71, 0x0c, 0x30, 0x11, 0x8c, 0x09, + 0x18, 0x6e, 0xfa, 0x43, 0xcc, 0x5f, 0x73, 0x21, 0xa4, 0x49, 0xa6, 0x4b, 0x4d, 0xee, 0xc9, 0x72, + 0xd5, 0x3c, 0xfa, 0xac, 0xb1, 0xdc, 0xb3, 0x20, 0xc7, 0x61, 0x54, 0x08, 0xa2, 0x1b, 0xcb, 0x6d, + 0x4a, 0x60, 0x47, 0xde, 0xbc, 0xa6, 0x04, 0x35, 0x38, 0x10, 0x8b, 0xa3, 0xcf, 0xfc, 0xaf, 0x8b, + 0x5e, 0xf9, 0x22, 0xbd, 0x13, 0xc4, 0x43, 0xe3, 0x00, 0x7a, 0xed, 0xc3, 0x7f, 0x46, 0x30, 0x95, + 0xec, 0x5b, 0xf0, 0x9a, 0x85, 0x31, 0x8b, 0xde, 0x69, 0x5e, 0x96, 0x82, 0x60, 0xcf, 0x8e, 0xca, + 0x6a, 0x23, 0x56, 0xbb, 0x6d, 0x1f, 0x4b, 0xe0, 0xec, 0xd7, 0x7b, 0x61, 0x0b, 0xc3, 0x8c, 0x7f, + 0x44, 0xb0, 0x4d, 0xb4, 0xab, 0x78, 0x3a, 0x36, 0xdf, 0x63, 0x7e, 0x70, 0x50, 0x8e, 0x74, 0xb0, + 0x93, 0x33, 0xcf, 0xcf, 0x7d, 0xf9, 0xe4, 0xc5, 0x83, 0xcc, 0x3b, 0xf8, 0x6d, 0x92, 0xf2, 0x6b, + 0x89, 0x4b, 0x56, 0x9b, 0x12, 0x37, 0x88, 0x2f, 0xbc, 0x4b, 0x56, 0x45, 0x38, 0x1a, 0xf8, 0x3e, + 0x82, 0x21, 0x39, 0x20, 0xe2, 0xf5, 0xcf, 0x96, 0xd7, 0x5a, 0x39, 0xda, 0xc9, 0x56, 0x81, 0xf3, + 0x35, 0x86, 0x73, 0x12, 0x1f, 0x4c, 0xc5, 0x89, 0x7f, 0x41, 0x80, 0xdb, 0xa7, 0x56, 0x7c, 0x22, + 0xe5, 0xa4, 0xa4, 0x71, 0x5b, 0x39, 0xd9, 0x9d, 0x91, 0x00, 0x7a, 0x86, 0x01, 0x3d, 0x8d, 0x4f, + 0xc5, 0x03, 0x0d, 0x0c, 0x7d, 0x4d, 0x83, 0x97, 0x46, 0x93, 0xc1, 0x63, 0x9f, 0x41, 0xdb, 0xc8, + 0x98, 0xca, 0x20, 0x69, 0x76, 0x4d, 0x65, 0x90, 0x38, 0x95, 0xe6, 0x2f, 0x31, 0x06, 0x0b, 0xf8, + 0xdc, 0xc6, 0xaf, 0x04, 0x09, 0xcf, 0xb2, 0xf8, 0xdb, 0x0c, 0x8c, 0xc5, 0xce, 0x5c, 0xf8, 0xd4, + 0xfa, 0x00, 0xe3, 0x86, 0x4a, 0xe5, 0xcd, 0xae, 0xed, 0x04, 0xb7, 0xaf, 0x10, 0x23, 0xf7, 0x05, + 0xc2, 0x9f, 0xf7, 0xc2, 0x2e, 0x3a, 0x1f, 0x12, 0x39, 0x68, 0x92, 0xd5, 0x96, 0x91, 0xb5, 0x41, + 0x78, 0x19, 0x08, 0x7d, 0xe0, 0x0b, 0x0d, 0xfc, 0x14, 0xc1, 0xee, 0xd6, 0xbe, 0x1f, 0xcf, 0x24, + 0xf3, 0x4a, 0x98, 0xeb, 0x94, 0xd9, 0x6e, 0x4c, 0x84, 0x0a, 0x9f, 0x32, 0x11, 0x6e, 0xe0, 0x6b, + 0x3d, 0x68, 0xd0, 0xf6, 0x97, 0xd6, 0x25, 0xab, 0xb2, 0x7c, 0x36, 0xf0, 0x13, 0x04, 0x7b, 0xda, + 0xa6, 0x1a, 0xdc, 0x05, 0xd6, 0x20, 0x0b, 0x4f, 0x74, 0x65, 0x23, 0x08, 0x5e, 0x65, 0x04, 0x2f, + 0xe1, 0x0b, 0x9b, 0x4a, 0x10, 0xff, 0x8a, 0xe0, 0x7f, 0x91, 0x81, 0x02, 0xab, 0xeb, 0xa1, 0x8b, + 0xce, 0x3a, 0x0a, 0xe9, 0x78, 0xbf, 0x60, 0xf2, 0x31, 0x63, 0xf2, 0x11, 0xbe, 0xda, 0x3b, 0x93, + 0x2a, 0x77, 0x1d, 0x89, 0xd3, 0x1a, 0x82, 0xb1, 0xd8, 0x06, 0x34, 0x2d, 0x35, 0xd3, 0xc6, 0x97, + 0xb4, 0xd4, 0x4c, 0x1d, 0x3e, 0xf2, 0xd7, 0x19, 0xd3, 0x45, 0x7c, 0xa5, 0x77, 0xa6, 0xba, 0xb1, + 0x1c, 0x61, 0xf9, 0x12, 0xc1, 0xde, 0xf8, 0x36, 0x1b, 0x77, 0x0b, 0x37, 0xb8, 0x97, 0xa7, 0xbb, + 0x37, 0x14, 0x44, 0x6f, 0x30, 0xa2, 0x1f, 0x62, 0x6d, 0x53, 0x88, 0x46, 0xe9, 0xdc, 0xcb, 0xc0, + 0x9e, 0xb6, 0xf6, 0x35, 0x2d, 0xef, 0x92, 0x9a, 0xf0, 0xb4, 0xbc, 0x4b, 0xec, 0x8f, 0x37, 0xa9, 0xbc, 0xc6, 0x95, 0x96, 0x94, 0xc6, 0xbe, 0x41, 0x6a, 0x01, 0xa0, 0x82, 0x23, 0x28, 0xff, 0x8d, - 0x60, 0x77, 0xb4, 0x89, 0xc5, 0x64, 0x3d, 0x8c, 0x42, 0x6d, 0xb7, 0x72, 0x72, 0xfd, 0x06, 0x82, - 0xff, 0x67, 0x8c, 0x7e, 0x1d, 0x7b, 0xbd, 0x61, 0x1f, 0xe9, 0xe2, 0x23, 0xb4, 0xfd, 0x1b, 0x8f, - 0x7f, 0x43, 0x30, 0x14, 0xd3, 0xe5, 0xe2, 0x94, 0x36, 0x20, 0xb9, 0xe1, 0x56, 0xde, 0xe8, 0xd0, - 0x4a, 0x48, 0x70, 0x85, 0x49, 0xf0, 0x3e, 0xbe, 0xd0, 0x85, 0x04, 0x91, 0x5e, 0x7c, 0x76, 0xe1, - 0xf1, 0x8b, 0x1c, 0x7a, 0xf2, 0x22, 0x87, 0xfe, 0x7c, 0x91, 0x43, 0xdf, 0xac, 0xe6, 0xfa, 0x9e, - 0xac, 0xe6, 0xfa, 0x7e, 0x5f, 0xcd, 0xf5, 0xdd, 0x7c, 0xab, 0x6c, 0x7a, 0x8b, 0xb5, 0xa2, 0x6a, - 0xd8, 0x15, 0x22, 0xfe, 0x31, 0x68, 0x16, 0x8d, 0x13, 0x65, 0x9b, 0xd4, 0x67, 0x48, 0xc5, 0x2e, - 0xd5, 0x96, 0xa9, 0xcb, 0x21, 0x9c, 0x3c, 0x75, 0x42, 0xa2, 0xf0, 0xee, 0x39, 0xd4, 0x2d, 0x6e, - 0x67, 0x3f, 0xe2, 0xce, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x82, 0x70, 0x0e, 0x40, 0xa8, 0x1c, + 0x60, 0x67, 0xb4, 0x89, 0xc5, 0xa4, 0x13, 0x46, 0xa1, 0xb6, 0x5b, 0x39, 0xde, 0xb9, 0x81, 0xe0, + 0xff, 0x19, 0xa3, 0x5f, 0xc7, 0x5e, 0x7f, 0xd8, 0x47, 0xba, 0xf8, 0x08, 0x6d, 0xff, 0xc6, 0xe3, + 0xdf, 0x10, 0x8c, 0xc4, 0x74, 0xb9, 0x38, 0xa5, 0x0d, 0x48, 0x6e, 0xb8, 0x95, 0x37, 0xba, 0xb4, + 0x12, 0x12, 0x5c, 0x66, 0x12, 0xbc, 0x8f, 0xcf, 0xf7, 0x20, 0x41, 0xa4, 0x17, 0x9f, 0x5b, 0x7c, + 0xf4, 0x3c, 0x87, 0x1e, 0x3f, 0xcf, 0xa1, 0x3f, 0x9f, 0xe7, 0xd0, 0x37, 0x6b, 0xb9, 0x81, 0xc7, + 0x6b, 0xb9, 0x81, 0xdf, 0xd7, 0x72, 0x03, 0x37, 0xde, 0x2a, 0x9b, 0xde, 0x52, 0xad, 0xa8, 0x1a, + 0x76, 0x85, 0x88, 0x7f, 0x0c, 0x9a, 0x45, 0xe3, 0x58, 0xd9, 0x26, 0xf5, 0x93, 0xa4, 0x62, 0x97, + 0x6a, 0x2b, 0xd4, 0xe5, 0x10, 0x8e, 0x9f, 0x3c, 0x26, 0x51, 0x78, 0x77, 0x1d, 0xea, 0x16, 0xb7, + 0xb2, 0x1f, 0x71, 0x4f, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x9c, 0x44, 0xc0, 0x72, 0xa8, 0x1c, 0x00, 0x00, } diff --git a/modules/core/04-channel/types/tx.pb.go b/modules/core/04-channel/types/tx.pb.go index fe6f344384d..4c8d176bd15 100644 --- a/modules/core/04-channel/types/tx.pb.go +++ b/modules/core/04-channel/types/tx.pb.go @@ -6,7 +6,7 @@ package types import ( context "context" fmt "fmt" - types "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + types "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -921,7 +921,7 @@ var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ // 1294 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4d, 0x6f, 0xe2, 0x56, 0x17, 0xc6, 0x40, 0x20, 0x39, 0xe4, 0x4d, 0x88, 0x49, 0x32, 0xc4, 0x24, 0x98, 0xd7, 0x8b, 0x49, - 0x94, 0x2a, 0x30, 0x49, 0x66, 0x54, 0x4d, 0x54, 0xa9, 0x0a, 0x94, 0x51, 0xa3, 0x36, 0x1f, 0x32, + 0x94, 0x2a, 0x30, 0xc9, 0x64, 0x54, 0x4d, 0x54, 0xa9, 0x0a, 0x94, 0x51, 0xa3, 0x36, 0x1f, 0x32, 0xa4, 0x52, 0xd3, 0xaa, 0x08, 0xcc, 0x1d, 0x62, 0x01, 0x36, 0xb5, 0x0d, 0x33, 0xfc, 0x83, 0x51, 0x56, 0xb3, 0x1e, 0x29, 0xd2, 0x54, 0x5d, 0x55, 0x5d, 0x4c, 0x7f, 0xc6, 0x2c, 0x67, 0xd5, 0x56, 0x5d, 0xa0, 0x2a, 0xd9, 0x74, 0xcd, 0x2f, 0xa8, 0x7c, 0x7d, 0x6d, 0x0c, 0xd8, 0x8a, 0x33, 0x93, @@ -936,61 +936,61 @@ var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ 0x06, 0x61, 0xe2, 0x34, 0xee, 0x4f, 0x51, 0x6b, 0x91, 0xad, 0xe5, 0xb4, 0xc3, 0x24, 0xd2, 0x24, 0x46, 0x36, 0xf8, 0xb6, 0xc7, 0xfa, 0x78, 0x73, 0x08, 0xbd, 0x08, 0x21, 0x55, 0xac, 0x49, 0x48, 0x89, 0x07, 0xf4, 0x48, 0x3c, 0x69, 0xed, 0x4c, 0xbe, 0x78, 0xcd, 0xfa, 0xfe, 0x79, 0xcd, 0xfa, - 0xb8, 0x06, 0x30, 0xe3, 0x29, 0xf2, 0x48, 0x6d, 0xc9, 0x92, 0x8a, 0xe8, 0x87, 0x00, 0xc4, 0xd5, - 0x20, 0xdb, 0x85, 0x7e, 0x8f, 0x9d, 0x33, 0xb2, 0x1d, 0xd8, 0x38, 0x7e, 0x8a, 0x34, 0xf6, 0xaa, - 0x74, 0x1c, 0xc2, 0x1d, 0xa4, 0xa8, 0xa2, 0x2c, 0xe1, 0x9c, 0xa7, 0x78, 0xb3, 0xc9, 0xfd, 0x1e, - 0x80, 0xb9, 0xe1, 0x70, 0x45, 0xa5, 0x7b, 0x3d, 0x42, 0x0e, 0x20, 0xd6, 0x52, 0x50, 0x47, 0x94, - 0xdb, 0x6a, 0xc9, 0x96, 0x1b, 0x0e, 0x94, 0x4d, 0xf6, 0x7b, 0x2c, 0x43, 0x06, 0x8e, 0x83, 0x38, - 0x7e, 0xce, 0xec, 0xcd, 0x59, 0xc9, 0xda, 0x08, 0x0e, 0x5c, 0x9f, 0x60, 0x1e, 0xe6, 0x05, 0xb9, - 0x2d, 0x69, 0x48, 0x69, 0x95, 0x15, 0xad, 0x5b, 0x32, 0xe7, 0x1d, 0xc4, 0xe9, 0xb0, 0xfd, 0x1e, - 0x9b, 0x20, 0x54, 0x39, 0xa0, 0x38, 0x3e, 0x66, 0xef, 0xfe, 0xc6, 0xe8, 0xd5, 0x49, 0x6f, 0x29, - 0xb2, 0xfc, 0xb4, 0x24, 0x4a, 0xa2, 0x16, 0x9f, 0x48, 0x51, 0x6b, 0xd3, 0x76, 0xd2, 0x07, 0x36, - 0x8e, 0x9f, 0xc2, 0x0d, 0xac, 0xaa, 0x13, 0x98, 0x36, 0x2c, 0xa7, 0x48, 0xac, 0x9d, 0x6a, 0xf1, - 0x10, 0x9e, 0x0c, 0x63, 0x9b, 0x8c, 0xa1, 0xde, 0xce, 0x66, 0xfa, 0x4b, 0x8c, 0xc8, 0x26, 0xf4, - 0xa9, 0xf4, 0x7b, 0x6c, 0xcc, 0xee, 0xd7, 0x18, 0xcd, 0xf1, 0x11, 0xdc, 0x34, 0x90, 0x36, 0x19, - 0x85, 0x5d, 0x64, 0xf4, 0x08, 0x96, 0xc6, 0xea, 0x6a, 0xa9, 0xc8, 0xa6, 0x07, 0x6a, 0x58, 0x0f, - 0x7f, 0x8c, 0xe9, 0x61, 0x57, 0xa8, 0x5f, 0x4f, 0x0f, 0xc3, 0x12, 0xf5, 0x7b, 0x94, 0xe8, 0x09, - 0xdc, 0x1b, 0xaa, 0x88, 0xcd, 0x05, 0x5e, 0x29, 0x59, 0xae, 0xdf, 0x63, 0x93, 0x0e, 0xa5, 0xb3, - 0xfb, 0x5b, 0xb0, 0x5b, 0x06, 0x8a, 0xba, 0x0d, 0x4d, 0x6c, 0x82, 0x51, 0xea, 0x92, 0xa6, 0x74, - 0x89, 0x24, 0xe6, 0xfb, 0x3d, 0x36, 0x6a, 0x2f, 0x9d, 0xa6, 0x74, 0x39, 0x7e, 0x12, 0x7f, 0xeb, - 0xab, 0xea, 0xe3, 0x0a, 0x22, 0x31, 0x2a, 0x88, 0x5d, 0xa1, 0x6e, 0x0a, 0x82, 0xfb, 0xd5, 0x0f, - 0x0b, 0xc3, 0xd6, 0x9c, 0x2c, 0x3d, 0x15, 0x95, 0xe6, 0x5d, 0x94, 0xde, 0xa2, 0xb2, 0x2c, 0xd4, - 0x71, 0xb1, 0x1d, 0xa8, 0x2c, 0x0b, 0x75, 0x93, 0x4a, 0x5d, 0x90, 0xa3, 0x54, 0x06, 0x6f, 0x85, - 0xca, 0x09, 0x17, 0x2a, 0x59, 0x58, 0x71, 0x24, 0xcb, 0xa2, 0xf3, 0x15, 0x05, 0xb1, 0x01, 0x22, - 0xd7, 0x90, 0x55, 0x74, 0xfd, 0x83, 0xe6, 0xfd, 0xc8, 0xbc, 0xfa, 0x80, 0x59, 0x81, 0x84, 0x43, - 0x6e, 0x56, 0xee, 0x6f, 0xfc, 0xb0, 0x38, 0x62, 0xbf, 0x43, 0x2d, 0x0c, 0x6f, 0xb5, 0x81, 0xf7, - 0xdc, 0x6a, 0xef, 0x56, 0x0e, 0x29, 0x48, 0x3a, 0x13, 0x66, 0x71, 0xfa, 0xd2, 0x0f, 0xff, 0xdb, - 0x57, 0x6b, 0x3c, 0x12, 0x3a, 0x47, 0x65, 0xa1, 0x8e, 0x34, 0xfa, 0x31, 0x84, 0x5a, 0xf8, 0x0b, - 0x33, 0x19, 0xd9, 0x4a, 0x38, 0x9e, 0x71, 0x06, 0x98, 0x1c, 0x71, 0x64, 0x00, 0xfd, 0x04, 0xa2, - 0x46, 0xba, 0x82, 0xdc, 0x6c, 0x8a, 0x5a, 0x13, 0x49, 0x1a, 0xa6, 0x77, 0x3a, 0x9b, 0xe8, 0xf7, - 0xd8, 0x7b, 0xf6, 0x09, 0x0d, 0x10, 0x1c, 0x3f, 0x8b, 0xbb, 0x72, 0x56, 0xcf, 0x18, 0x69, 0x81, - 0x5b, 0x21, 0x2d, 0xe8, 0x42, 0xda, 0x0f, 0x78, 0xc3, 0x19, 0x30, 0x62, 0x9d, 0x4d, 0x9f, 0x43, - 0x48, 0x41, 0x6a, 0xbb, 0x61, 0x30, 0x33, 0xb3, 0xb5, 0xea, 0xc8, 0x8c, 0x09, 0xe7, 0x31, 0xb4, - 0xd8, 0x6d, 0x21, 0x9e, 0x0c, 0xdb, 0x09, 0xea, 0x31, 0xb8, 0xbf, 0xfc, 0x00, 0xfb, 0x6a, 0xad, - 0x28, 0x36, 0x91, 0xdc, 0xbe, 0x19, 0xbe, 0xdb, 0x92, 0x82, 0x04, 0x24, 0x76, 0x50, 0xd5, 0x8d, - 0xef, 0x01, 0xc2, 0xe4, 0xfb, 0xd8, 0xea, 0xb9, 0x55, 0xbe, 0xbf, 0x02, 0x5a, 0x42, 0xcf, 0xb5, - 0x92, 0x8a, 0x7e, 0x6c, 0x23, 0x49, 0x40, 0x25, 0x05, 0x09, 0x1d, 0xcc, 0x7d, 0x30, 0xbb, 0xd2, - 0xef, 0xb1, 0x4b, 0x86, 0x87, 0x71, 0x0c, 0xc7, 0x47, 0xf5, 0xce, 0x02, 0xe9, 0xd3, 0xeb, 0xe1, - 0x41, 0xf1, 0xdf, 0xe1, 0x6b, 0x34, 0xe1, 0xf6, 0xa6, 0x2b, 0xf7, 0xca, 0xb8, 0x82, 0x10, 0xef, - 0x87, 0x12, 0x5e, 0x51, 0xff, 0x85, 0x02, 0x7e, 0x0a, 0x11, 0xb2, 0xac, 0xf4, 0x8c, 0xc8, 0xe6, - 0xb4, 0xd8, 0xef, 0xb1, 0xf4, 0xd0, 0x9a, 0xd3, 0x8d, 0x1c, 0x6f, 0x6c, 0x63, 0x46, 0xee, 0xb7, - 0xb9, 0x3d, 0x39, 0x57, 0x7e, 0xe2, 0x43, 0x2b, 0x1f, 0x72, 0xa9, 0x7c, 0x05, 0xdf, 0x22, 0x86, - 0x6b, 0x73, 0xd3, 0x02, 0xf8, 0xcd, 0x8f, 0xe5, 0xb5, 0x2b, 0xd4, 0x25, 0xf9, 0x59, 0x03, 0x55, - 0x6b, 0x08, 0xef, 0x57, 0x1f, 0xa0, 0x80, 0x35, 0x98, 0x2d, 0x0f, 0x7b, 0x33, 0x04, 0xc0, 0x8f, - 0x76, 0x0f, 0x6a, 0xac, 0x0f, 0xac, 0xba, 0xd5, 0x18, 0x1b, 0xcd, 0x1a, 0xef, 0xea, 0x8d, 0x8f, - 0x7c, 0x04, 0x09, 0xf8, 0xd1, 0x38, 0xc2, 0xd8, 0x0d, 0xd7, 0x65, 0xfd, 0x17, 0x0a, 0xe8, 0x71, - 0x10, 0xfd, 0x08, 0x52, 0x7c, 0xbe, 0x70, 0x74, 0x78, 0x50, 0xc8, 0x97, 0xf8, 0x7c, 0xe1, 0xf8, - 0xeb, 0x62, 0xa9, 0xf8, 0xed, 0x51, 0xbe, 0x74, 0x7c, 0x50, 0x38, 0xca, 0xe7, 0xf6, 0x9e, 0xec, - 0xe5, 0xbf, 0x88, 0xfa, 0x98, 0xd9, 0xb3, 0xf3, 0x54, 0xc4, 0xd6, 0x45, 0xaf, 0xc2, 0x92, 0xe3, - 0xb0, 0x83, 0xc3, 0xc3, 0xa3, 0x28, 0xc5, 0x4c, 0x9e, 0x9d, 0xa7, 0x82, 0xfa, 0x37, 0xbd, 0x01, - 0xcb, 0x8e, 0xc0, 0xc2, 0x71, 0x2e, 0x97, 0x2f, 0x14, 0xa2, 0x7e, 0x26, 0x72, 0x76, 0x9e, 0x0a, - 0x93, 0x26, 0x13, 0x7c, 0xf1, 0x73, 0xd2, 0xb7, 0xf5, 0x66, 0x12, 0x02, 0xfb, 0x6a, 0x8d, 0xae, - 0xc3, 0xec, 0xe8, 0x6b, 0xdf, 0x79, 0xf6, 0xe3, 0x6f, 0x6e, 0x26, 0xe3, 0x11, 0x68, 0xf1, 0x7c, - 0x0a, 0x33, 0x23, 0x0f, 0xe9, 0xfb, 0x1e, 0x5c, 0x14, 0x95, 0x2e, 0x93, 0xf6, 0x86, 0x73, 0x89, - 0xa4, 0xdf, 0x88, 0xbd, 0x44, 0xda, 0x15, 0xea, 0x9e, 0x22, 0xd9, 0x5e, 0x06, 0xb4, 0x06, 0xb4, - 0xc3, 0xab, 0x60, 0xdd, 0x83, 0x17, 0x82, 0x65, 0xb6, 0xbc, 0x63, 0xad, 0xa8, 0x12, 0x44, 0xc7, - 0x2e, 0xcf, 0x6b, 0x57, 0xf8, 0xb1, 0x90, 0xcc, 0x03, 0xaf, 0x48, 0x2b, 0xde, 0x33, 0x88, 0x39, - 0x5e, 0x78, 0xbd, 0x38, 0x32, 0xe7, 0xb9, 0x7d, 0x0d, 0xb0, 0x15, 0xf8, 0x7b, 0x00, 0xdb, 0xad, + 0xb8, 0x06, 0x30, 0xe3, 0x29, 0xf2, 0x48, 0x6d, 0xc9, 0x92, 0x8a, 0xe8, 0x6d, 0x00, 0xe2, 0x6a, + 0x90, 0xed, 0x42, 0xbf, 0xc7, 0xce, 0x19, 0xd9, 0x0e, 0x6c, 0x1c, 0x3f, 0x45, 0x1a, 0x7b, 0x55, + 0x3a, 0x0e, 0xe1, 0x0e, 0x52, 0x54, 0x51, 0x96, 0x70, 0xce, 0x53, 0xbc, 0xd9, 0xe4, 0x7e, 0x0f, + 0xc0, 0xdc, 0x70, 0xb8, 0xa2, 0xd2, 0xbd, 0x1e, 0x21, 0x07, 0x10, 0x6b, 0x29, 0xa8, 0x23, 0xca, + 0x6d, 0xb5, 0x64, 0xcb, 0x0d, 0x07, 0xca, 0x26, 0xfb, 0x3d, 0x96, 0x21, 0x03, 0xc7, 0x41, 0x1c, + 0x3f, 0x67, 0xf6, 0xe6, 0xac, 0x64, 0x6d, 0x04, 0x07, 0xae, 0x4f, 0x30, 0x0f, 0xf3, 0x82, 0xdc, + 0x96, 0x34, 0xa4, 0xb4, 0xca, 0x8a, 0xd6, 0x2d, 0x99, 0xf3, 0x0e, 0xe2, 0x74, 0xd8, 0x7e, 0x8f, + 0x4d, 0x10, 0xaa, 0x1c, 0x50, 0x1c, 0x1f, 0xb3, 0x77, 0x7f, 0x63, 0xf4, 0xea, 0xa4, 0xb7, 0x14, + 0x59, 0x7e, 0x5a, 0x12, 0x25, 0x51, 0x8b, 0x4f, 0xa4, 0xa8, 0xb5, 0x69, 0x3b, 0xe9, 0x03, 0x1b, + 0xc7, 0x4f, 0xe1, 0x06, 0x56, 0xd5, 0x09, 0x4c, 0x1b, 0x96, 0x53, 0x24, 0xd6, 0x4e, 0xb5, 0x78, + 0x08, 0x4f, 0x86, 0xb1, 0x4d, 0xc6, 0x50, 0x6f, 0x67, 0x33, 0xfd, 0x25, 0x46, 0x64, 0x13, 0xfa, + 0x54, 0xfa, 0x3d, 0x36, 0x66, 0xf7, 0x6b, 0x8c, 0xe6, 0xf8, 0x08, 0x6e, 0x1a, 0x48, 0x9b, 0x8c, + 0xc2, 0x2e, 0x32, 0x7a, 0x04, 0x4b, 0x63, 0x75, 0xb5, 0x54, 0x64, 0xd3, 0x03, 0x35, 0xac, 0x87, + 0x3f, 0xc6, 0xf4, 0xb0, 0x2b, 0xd4, 0xaf, 0xa7, 0x87, 0x61, 0x89, 0xfa, 0x3d, 0x4a, 0xf4, 0x04, + 0xee, 0x0d, 0x55, 0xc4, 0xe6, 0x02, 0xaf, 0x94, 0x2c, 0xd7, 0xef, 0xb1, 0x49, 0x87, 0xd2, 0xd9, + 0xfd, 0x2d, 0xd8, 0x2d, 0x03, 0x45, 0xdd, 0x86, 0x26, 0x36, 0xc1, 0x28, 0x75, 0x49, 0x53, 0xba, + 0x44, 0x12, 0xf3, 0xfd, 0x1e, 0x1b, 0xb5, 0x97, 0x4e, 0x53, 0xba, 0x1c, 0x3f, 0x89, 0xbf, 0xf5, + 0x55, 0xf5, 0x71, 0x05, 0x91, 0x18, 0x15, 0xc4, 0xae, 0x50, 0x37, 0x05, 0xc1, 0xfd, 0xea, 0x87, + 0x85, 0x61, 0x6b, 0x4e, 0x96, 0x9e, 0x8a, 0x4a, 0xf3, 0x2e, 0x4a, 0x6f, 0x51, 0x59, 0x16, 0xea, + 0xb8, 0xd8, 0x0e, 0x54, 0x96, 0x85, 0xba, 0x49, 0xa5, 0x2e, 0xc8, 0x51, 0x2a, 0x83, 0xb7, 0x42, + 0xe5, 0x84, 0x0b, 0x95, 0x2c, 0xac, 0x38, 0x92, 0x65, 0xd1, 0xf9, 0x8a, 0x82, 0xd8, 0x00, 0x91, + 0x6b, 0xc8, 0x2a, 0xba, 0xfe, 0x41, 0xf3, 0x7e, 0x64, 0x5e, 0x7d, 0xc0, 0xac, 0x40, 0xc2, 0x21, + 0x37, 0x2b, 0xf7, 0x37, 0x7e, 0x58, 0x1c, 0xb1, 0xdf, 0xa1, 0x16, 0x86, 0xb7, 0xda, 0xc0, 0x7b, + 0x6e, 0xb5, 0x77, 0x2b, 0x87, 0x14, 0x24, 0x9d, 0x09, 0xb3, 0x38, 0x7d, 0xe9, 0x87, 0xff, 0xed, + 0xab, 0x35, 0x1e, 0x09, 0x9d, 0xa3, 0xb2, 0x50, 0x47, 0x1a, 0xfd, 0x18, 0x42, 0x2d, 0xfc, 0x85, + 0x99, 0x8c, 0x6c, 0x25, 0x1c, 0xcf, 0x38, 0x03, 0x4c, 0x8e, 0x38, 0x32, 0x80, 0x7e, 0x02, 0x51, + 0x23, 0x5d, 0x41, 0x6e, 0x36, 0x45, 0xad, 0x89, 0x24, 0x0d, 0xd3, 0x3b, 0x9d, 0x4d, 0xf4, 0x7b, + 0xec, 0x3d, 0xfb, 0x84, 0x06, 0x08, 0x8e, 0x9f, 0xc5, 0x5d, 0x39, 0xab, 0x67, 0x8c, 0xb4, 0xc0, + 0xad, 0x90, 0x16, 0x74, 0x21, 0xed, 0x07, 0xbc, 0xe1, 0x0c, 0x18, 0xb1, 0xce, 0xa6, 0xcf, 0x21, + 0xa4, 0x20, 0xb5, 0xdd, 0x30, 0x98, 0x99, 0xd9, 0x5a, 0x75, 0x64, 0xc6, 0x84, 0xf3, 0x18, 0x5a, + 0xec, 0xb6, 0x10, 0x4f, 0x86, 0xed, 0x04, 0xf5, 0x18, 0xdc, 0x5f, 0x7e, 0x80, 0x7d, 0xb5, 0x56, + 0x14, 0x9b, 0x48, 0x6e, 0xdf, 0x0c, 0xdf, 0x6d, 0x49, 0x41, 0x02, 0x12, 0x3b, 0xa8, 0xea, 0xc6, + 0xf7, 0x00, 0x61, 0xf2, 0x7d, 0x6c, 0xf5, 0xdc, 0x2a, 0xdf, 0x5f, 0x01, 0x2d, 0xa1, 0xe7, 0x5a, + 0x49, 0x45, 0x3f, 0xb6, 0x91, 0x24, 0xa0, 0x92, 0x82, 0x84, 0x0e, 0xe6, 0x3e, 0x98, 0x5d, 0xe9, + 0xf7, 0xd8, 0x25, 0xc3, 0xc3, 0x38, 0x86, 0xe3, 0xa3, 0x7a, 0x67, 0x81, 0xf4, 0xe9, 0xf5, 0xf0, + 0xa0, 0xf8, 0xef, 0xf0, 0x35, 0x9a, 0x70, 0x7b, 0xd3, 0x95, 0x7b, 0x65, 0x5c, 0x41, 0x88, 0xf7, + 0x43, 0x09, 0xaf, 0xa8, 0xff, 0x42, 0x01, 0x3f, 0x85, 0x08, 0x59, 0x56, 0x7a, 0x46, 0x64, 0x73, + 0x5a, 0xec, 0xf7, 0x58, 0x7a, 0x68, 0xcd, 0xe9, 0x46, 0x8e, 0x37, 0xb6, 0x31, 0x23, 0xf7, 0xdb, + 0xdc, 0x9e, 0x9c, 0x2b, 0x3f, 0xf1, 0xa1, 0x95, 0x0f, 0xb9, 0x54, 0xbe, 0x82, 0x6f, 0x11, 0xc3, + 0xb5, 0xb9, 0x69, 0x01, 0xfc, 0xe6, 0xc7, 0xf2, 0xda, 0x15, 0xea, 0x92, 0xfc, 0xac, 0x81, 0xaa, + 0x35, 0x84, 0xf7, 0xab, 0x0f, 0x50, 0xc0, 0x1a, 0xcc, 0x96, 0x87, 0xbd, 0x19, 0x02, 0xe0, 0x47, + 0xbb, 0x07, 0x35, 0xd6, 0x07, 0x56, 0xdd, 0x6a, 0x8c, 0x8d, 0x66, 0x8d, 0x77, 0xf5, 0xc6, 0x47, + 0x3e, 0x82, 0x04, 0xfc, 0x68, 0x1c, 0x61, 0xec, 0x86, 0xeb, 0xb2, 0xfe, 0x0b, 0x05, 0xf4, 0x38, + 0x88, 0x7e, 0x04, 0x29, 0x3e, 0x5f, 0x38, 0x3a, 0x3c, 0x28, 0xe4, 0x4b, 0x7c, 0xbe, 0x70, 0xfc, + 0x75, 0xb1, 0x54, 0xfc, 0xf6, 0x28, 0x5f, 0x3a, 0x3e, 0x28, 0x1c, 0xe5, 0x73, 0x7b, 0x4f, 0xf6, + 0xf2, 0x5f, 0x44, 0x7d, 0xcc, 0xec, 0xd9, 0x79, 0x2a, 0x62, 0xeb, 0xa2, 0x57, 0x61, 0xc9, 0x71, + 0xd8, 0xc1, 0xe1, 0xe1, 0x51, 0x94, 0x62, 0x26, 0xcf, 0xce, 0x53, 0x41, 0xfd, 0x9b, 0xde, 0x80, + 0x65, 0x47, 0x60, 0xe1, 0x38, 0x97, 0xcb, 0x17, 0x0a, 0x51, 0x3f, 0x13, 0x39, 0x3b, 0x4f, 0x85, + 0x49, 0x93, 0x09, 0xbe, 0xf8, 0x39, 0xe9, 0xdb, 0x7a, 0x33, 0x09, 0x81, 0x7d, 0xb5, 0x46, 0xd7, + 0x61, 0x76, 0xf4, 0xb5, 0xef, 0x3c, 0xfb, 0xf1, 0x37, 0x37, 0x93, 0xf1, 0x08, 0xb4, 0x78, 0x3e, + 0x85, 0x99, 0x91, 0x87, 0xf4, 0x7d, 0x0f, 0x2e, 0x8a, 0x4a, 0x97, 0x49, 0x7b, 0xc3, 0xb9, 0x44, + 0xd2, 0x6f, 0xc4, 0x5e, 0x22, 0xed, 0x0a, 0x75, 0x4f, 0x91, 0x6c, 0x2f, 0x03, 0x5a, 0x03, 0xda, + 0xe1, 0x55, 0xb0, 0xee, 0xc1, 0x0b, 0xc1, 0x32, 0x5b, 0xde, 0xb1, 0x56, 0x54, 0x09, 0xa2, 0x63, + 0x97, 0xe7, 0xb5, 0x2b, 0xfc, 0x58, 0x48, 0xe6, 0x81, 0x57, 0xa4, 0x15, 0xef, 0x19, 0xc4, 0x1c, + 0x2f, 0xbc, 0x5e, 0x1c, 0x99, 0xf3, 0x7c, 0x78, 0x0d, 0xb0, 0x15, 0xf8, 0x7b, 0x00, 0xdb, 0xad, 0x90, 0x73, 0x73, 0x31, 0xc0, 0x30, 0xeb, 0x57, 0x63, 0x2c, 0xef, 0x05, 0x08, 0x9b, 0x17, 0x20, 0xd6, 0x6d, 0x18, 0x01, 0x30, 0xab, 0x57, 0x00, 0xec, 0xda, 0x1b, 0x39, 0x9b, 0xef, 0x5f, 0x31, 0x94, 0xe0, 0xdc, 0xb5, 0xe7, 0x72, 0x9e, 0xd4, 0x61, 0x76, 0xf4, 0x10, 0x70, 0xcd, 0x72, 0x04, @@ -998,8 +998,8 @@ var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ 0xbe, 0x48, 0x52, 0x2f, 0x2f, 0x93, 0xbe, 0x77, 0x97, 0x49, 0xdf, 0x9f, 0x97, 0x49, 0xdf, 0xc9, 0xe3, 0x9a, 0xa8, 0x9d, 0xb6, 0x2b, 0x69, 0x41, 0x6e, 0x66, 0x04, 0x59, 0x6d, 0xca, 0x6a, 0x46, 0xac, 0x08, 0x1b, 0x35, 0x39, 0xd3, 0xd9, 0xce, 0x34, 0xe5, 0x6a, 0xbb, 0x81, 0x54, 0xe3, 0xc7, - 0xe3, 0x83, 0x87, 0x1b, 0xe6, 0xbf, 0x47, 0xad, 0xdb, 0x42, 0x6a, 0x25, 0x84, 0xff, 0x3b, 0x6e, - 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x51, 0x2e, 0xf7, 0xe5, 0x06, 0x15, 0x00, 0x00, + 0xe3, 0x83, 0xed, 0x0d, 0xf3, 0xdf, 0xa3, 0xd6, 0x6d, 0x21, 0xb5, 0x12, 0xc2, 0xff, 0x1d, 0x1f, + 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x4f, 0x1a, 0x39, 0xd7, 0x06, 0x15, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/04-channel/types/version_test.go b/modules/core/04-channel/types/version_test.go index 1ccacf7d9f2..d735f162ae1 100644 --- a/modules/core/04-channel/types/version_test.go +++ b/modules/core/04-channel/types/version_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) func TestSplitVersions(t *testing.T) { diff --git a/modules/core/05-port/keeper/keeper.go b/modules/core/05-port/keeper/keeper.go index ef898664337..db65f384455 100644 --- a/modules/core/05-port/keeper/keeper.go +++ b/modules/core/05-port/keeper/keeper.go @@ -8,8 +8,8 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // Keeper defines the IBC connection keeper diff --git a/modules/core/05-port/keeper/keeper_test.go b/modules/core/05-port/keeper/keeper_test.go index 52fa4198730..fe2449b81be 100644 --- a/modules/core/05-port/keeper/keeper_test.go +++ b/modules/core/05-port/keeper/keeper_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/suite" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - "github.com/cosmos/ibc-go/v3/modules/core/05-port/keeper" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/modules/core/05-port/keeper" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) var ( diff --git a/modules/core/05-port/module.go b/modules/core/05-port/module.go index 8aab55b1fb8..dd13e8a1b1b 100644 --- a/modules/core/05-port/module.go +++ b/modules/core/05-port/module.go @@ -4,8 +4,8 @@ import ( "github.com/gogo/protobuf/grpc" "github.com/spf13/cobra" - "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v3/modules/core/client/cli" + "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v4/modules/core/client/cli" ) // Name returns the IBC port ICS name. diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 26501af313c..3f71e1d0339 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -4,8 +4,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // IBCModule defines an interface that implements all the callbacks diff --git a/modules/core/05-port/types/query.pb.go b/modules/core/05-port/types/query.pb.go index 17a6cfc65da..3d7b414c747 100644 --- a/modules/core/05-port/types/query.pb.go +++ b/modules/core/05-port/types/query.pb.go @@ -6,7 +6,7 @@ package types import ( context "context" fmt "fmt" - types "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + types "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" grpc "google.golang.org/grpc" diff --git a/modules/core/23-commitment/types/codec.go b/modules/core/23-commitment/types/codec.go index 886a6c14e5b..5c1334cec6d 100644 --- a/modules/core/23-commitment/types/codec.go +++ b/modules/core/23-commitment/types/codec.go @@ -3,7 +3,7 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // RegisterInterfaces registers the commitment interfaces to protobuf Any. diff --git a/modules/core/23-commitment/types/commitment.pb.go b/modules/core/23-commitment/types/commitment.pb.go index b5c4a458535..8b77f6aa693 100644 --- a/modules/core/23-commitment/types/commitment.pb.go +++ b/modules/core/23-commitment/types/commitment.pb.go @@ -217,28 +217,28 @@ func init() { } var fileDescriptor_7921d88972a41469 = []byte{ - // 334 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x91, 0xbf, 0x4e, 0xeb, 0x30, - 0x14, 0xc6, 0x13, 0xdd, 0xaa, 0x97, 0xba, 0x95, 0x10, 0x01, 0x2a, 0xd4, 0x21, 0x45, 0x19, 0xa0, - 0x4b, 0x6d, 0xb5, 0x61, 0xaa, 0x60, 0x09, 0xac, 0x48, 0x55, 0x06, 0x06, 0x16, 0x94, 0x18, 0x37, - 0xb1, 0xda, 0x70, 0xa2, 0xd8, 0xad, 0xc8, 0x1b, 0x30, 0x32, 0x32, 0xf2, 0x38, 0x8c, 0x1d, 0x99, - 0x2a, 0xd4, 0xbe, 0x41, 0x9f, 0x00, 0xd9, 0xa6, 0x90, 0xed, 0x7c, 0x3a, 0xbf, 0xf3, 0xef, 0x3b, - 0xe8, 0x9c, 0xc7, 0x94, 0x50, 0x28, 0x18, 0xa1, 0x90, 0x65, 0x5c, 0x66, 0xec, 0x49, 0x92, 0xc5, - 0xa0, 0xa2, 0x70, 0x5e, 0x80, 0x04, 0xa7, 0xcd, 0x63, 0x8a, 0x15, 0x88, 0x2b, 0xa9, 0xc5, 0xa0, - 0x73, 0x94, 0x40, 0x02, 0x1a, 0x21, 0x2a, 0x32, 0x74, 0xa7, 0x95, 0x17, 0x00, 0x13, 0x61, 0x94, - 0x77, 0x86, 0xd0, 0x2d, 0x2b, 0xa6, 0x33, 0x16, 0x02, 0x48, 0xc7, 0x41, 0xb5, 0x34, 0x12, 0xe9, - 0x89, 0x7d, 0x6a, 0xf7, 0x5a, 0xa1, 0x8e, 0x47, 0xb5, 0x97, 0xf7, 0xae, 0xe5, 0xdd, 0xa0, 0x96, - 0xe1, 0xc6, 0x05, 0x9b, 0xf0, 0x67, 0xe7, 0x02, 0xa1, 0x29, 0x2b, 0x1f, 0x72, 0xad, 0x0c, 0x1f, - 0x1c, 0x6f, 0x57, 0xdd, 0x83, 0x32, 0xca, 0x66, 0x23, 0xef, 0x2f, 0xe7, 0x85, 0x8d, 0x29, 0x2b, - 0x4d, 0x95, 0x17, 0xec, 0xa6, 0x8d, 0x23, 0x99, 0x3a, 0x18, 0xed, 0x69, 0x2e, 0x92, 0x6a, 0xe2, - 0xbf, 0x5e, 0x23, 0x38, 0xdc, 0xae, 0xba, 0xfb, 0x95, 0x0e, 0x91, 0x4c, 0xbd, 0xf0, 0xbf, 0xaa, - 0x8f, 0x64, 0x3a, 0xaa, 0xbd, 0xa9, 0x4d, 0xae, 0x50, 0x73, 0xb7, 0x09, 0xc0, 0xc4, 0xc1, 0xa8, - 0x6e, 0x0e, 0xd2, 0x2d, 0x9a, 0xc3, 0x36, 0xe6, 0x54, 0x0c, 0x7d, 0x7c, 0xfd, 0x6b, 0x85, 0xe6, - 0xc2, 0x1f, 0x2a, 0xb8, 0xfb, 0x58, 0xbb, 0xf6, 0x72, 0xed, 0xda, 0x5f, 0x6b, 0xd7, 0x7e, 0xdd, - 0xb8, 0xd6, 0x72, 0xe3, 0x5a, 0x9f, 0x1b, 0xd7, 0xba, 0xbf, 0x4c, 0xb8, 0x4c, 0xe7, 0xb1, 0x32, - 0x91, 0x50, 0x10, 0x19, 0x08, 0xc2, 0x63, 0xda, 0x4f, 0x80, 0x2c, 0x7c, 0x92, 0xc1, 0xe3, 0x7c, - 0xc6, 0x84, 0xf9, 0xc7, 0xd0, 0xef, 0x57, 0x5e, 0x22, 0xcb, 0x9c, 0x89, 0xb8, 0xae, 0xfd, 0xf4, - 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xec, 0x9a, 0x38, 0xca, 0xb6, 0x01, 0x00, 0x00, + // 333 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x91, 0xbd, 0x4e, 0xc3, 0x30, + 0x10, 0xc7, 0x13, 0x51, 0x15, 0xea, 0x56, 0x42, 0x04, 0xa8, 0x50, 0x87, 0x14, 0x65, 0x80, 0x2e, + 0xb5, 0xd5, 0x8f, 0xa9, 0x82, 0x25, 0xb0, 0x22, 0x55, 0x19, 0x18, 0x58, 0x50, 0x62, 0xdc, 0xc4, + 0x6a, 0xc3, 0x45, 0xb1, 0x5b, 0x91, 0x37, 0x60, 0x64, 0x64, 0xe4, 0x71, 0x18, 0x3b, 0x32, 0x55, + 0xa8, 0x7d, 0x83, 0x3e, 0x01, 0xb2, 0x4d, 0x21, 0xdb, 0xfd, 0x75, 0xbf, 0xfb, 0xfa, 0x1f, 0xba, + 0xe4, 0x11, 0x25, 0x14, 0x72, 0x46, 0x28, 0xa4, 0x29, 0x97, 0x29, 0x7b, 0x96, 0x64, 0xd1, 0x2b, + 0x29, 0x9c, 0xe5, 0x20, 0xc1, 0x69, 0xf2, 0x88, 0x62, 0x05, 0xe2, 0x52, 0x6a, 0xd1, 0x6b, 0x9d, + 0xc4, 0x10, 0x83, 0x46, 0x88, 0x8a, 0x0c, 0xdd, 0x6a, 0x64, 0x39, 0xc0, 0x44, 0x18, 0xe5, 0x5d, + 0x20, 0x74, 0xc7, 0xf2, 0xe9, 0x8c, 0x05, 0x00, 0xd2, 0x71, 0x50, 0x25, 0x09, 0x45, 0x72, 0x66, + 0x9f, 0xdb, 0x9d, 0x46, 0xa0, 0xe3, 0x51, 0xe5, 0xf5, 0xa3, 0x6d, 0x79, 0xb7, 0xa8, 0x61, 0xb8, + 0x71, 0xce, 0x26, 0xfc, 0xc5, 0x19, 0x22, 0x34, 0x65, 0xc5, 0x63, 0xa6, 0x95, 0xe1, 0xfd, 0xd3, + 0xed, 0xaa, 0x7d, 0x54, 0x84, 0xe9, 0x6c, 0xe4, 0xfd, 0xe7, 0xbc, 0xa0, 0x36, 0x65, 0x85, 0xa9, + 0xf2, 0xfc, 0xdd, 0xb4, 0x71, 0x28, 0x13, 0x07, 0xa3, 0x03, 0xcd, 0x85, 0x52, 0x4d, 0xdc, 0xeb, + 0xd4, 0xfc, 0xe3, 0xed, 0xaa, 0x7d, 0x58, 0xea, 0x10, 0xca, 0xc4, 0x0b, 0xf6, 0x55, 0x7d, 0x28, + 0x93, 0x51, 0xe5, 0x5d, 0x6d, 0x72, 0x8d, 0xea, 0xbb, 0x4d, 0x00, 0x26, 0x0e, 0x46, 0x55, 0x73, + 0x90, 0x6e, 0x51, 0xef, 0x37, 0x31, 0xa7, 0xa2, 0x3f, 0xc0, 0x37, 0x7f, 0x56, 0x68, 0x2e, 0xf8, + 0xa5, 0xfc, 0xfb, 0xcf, 0xb5, 0x6b, 0x2f, 0xd7, 0xae, 0xfd, 0xbd, 0x76, 0xed, 0xb7, 0x8d, 0x6b, + 0x2d, 0x37, 0xae, 0xf5, 0xb5, 0x71, 0xad, 0x87, 0xab, 0x98, 0xcb, 0x64, 0x1e, 0x29, 0x13, 0x09, + 0x05, 0x91, 0x82, 0x20, 0x3c, 0xa2, 0xdd, 0x18, 0xc8, 0x62, 0x48, 0x52, 0x78, 0x9a, 0xcf, 0x98, + 0x30, 0xff, 0xe8, 0x0f, 0xba, 0xa5, 0x97, 0xc8, 0x22, 0x63, 0x22, 0xaa, 0x6a, 0x3f, 0x07, 0x3f, + 0x01, 0x00, 0x00, 0xff, 0xff, 0xe4, 0x08, 0x76, 0x1b, 0xb6, 0x01, 0x00, 0x00, } func (m *MerkleRoot) Marshal() (dAtA []byte, err error) { diff --git a/modules/core/23-commitment/types/merkle.go b/modules/core/23-commitment/types/merkle.go index 17f1487d982..133c5277771 100644 --- a/modules/core/23-commitment/types/merkle.go +++ b/modules/core/23-commitment/types/merkle.go @@ -10,7 +10,7 @@ import ( "github.com/gogo/protobuf/proto" tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // var representing the proofspecs for a SDK chain diff --git a/modules/core/23-commitment/types/merkle_test.go b/modules/core/23-commitment/types/merkle_test.go index 68a96c9b0c3..cf13348faf3 100644 --- a/modules/core/23-commitment/types/merkle_test.go +++ b/modules/core/23-commitment/types/merkle_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" ) func (suite *MerkleTestSuite) TestVerifyMembership() { diff --git a/modules/core/23-commitment/types/utils_test.go b/modules/core/23-commitment/types/utils_test.go index ea2abea2026..270d13cae5e 100644 --- a/modules/core/23-commitment/types/utils_test.go +++ b/modules/core/23-commitment/types/utils_test.go @@ -7,7 +7,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" crypto "github.com/tendermint/tendermint/proto/tendermint/crypto" - "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" ) func (suite *MerkleTestSuite) TestConvertProofs() { diff --git a/modules/core/24-host/keys.go b/modules/core/24-host/keys.go index c12449f182f..b38d022d907 100644 --- a/modules/core/24-host/keys.go +++ b/modules/core/24-host/keys.go @@ -3,7 +3,7 @@ package host import ( "fmt" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) const ( diff --git a/modules/core/24-host/parse_test.go b/modules/core/24-host/parse_test.go index 60b33d8ce45..18b9848e950 100644 --- a/modules/core/24-host/parse_test.go +++ b/modules/core/24-host/parse_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) func TestParseIdentifier(t *testing.T) { diff --git a/modules/core/ante/ante.go b/modules/core/ante/ante.go index e9218ea4b94..1ad8d776b70 100644 --- a/modules/core/ante/ante.go +++ b/modules/core/ante/ante.go @@ -3,9 +3,9 @@ package ante import ( sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/modules/core/keeper" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/keeper" ) type AnteDecorator struct { diff --git a/modules/core/ante/ante_test.go b/modules/core/ante/ante_test.go index c04f6483f74..fb71db32b0f 100644 --- a/modules/core/ante/ante_test.go +++ b/modules/core/ante/ante_test.go @@ -7,12 +7,12 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/ante" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/ante" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type AnteTestSuite struct { diff --git a/modules/core/client/cli/cli.go b/modules/core/client/cli/cli.go index 92a3756cdb5..a16b1d17751 100644 --- a/modules/core/client/cli/cli.go +++ b/modules/core/client/cli/cli.go @@ -5,10 +5,10 @@ import ( "github.com/cosmos/cosmos-sdk/client" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/02-client" - connection "github.com/cosmos/ibc-go/v3/modules/core/03-connection" - channel "github.com/cosmos/ibc-go/v3/modules/core/04-channel" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/02-client" + connection "github.com/cosmos/ibc-go/v4/modules/core/03-connection" + channel "github.com/cosmos/ibc-go/v4/modules/core/04-channel" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // GetTxCmd returns the transaction commands for this module diff --git a/modules/core/client/query.go b/modules/core/client/query.go index 30377a495c4..3dd56aa92cc 100644 --- a/modules/core/client/query.go +++ b/modules/core/client/query.go @@ -7,9 +7,9 @@ import ( "github.com/cosmos/cosmos-sdk/codec" abci "github.com/tendermint/tendermint/abci/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) // QueryTendermintProof performs an ABCI query with the given key and returns diff --git a/modules/core/genesis.go b/modules/core/genesis.go index 9bc30a2d28f..7f9f65fa46f 100644 --- a/modules/core/genesis.go +++ b/modules/core/genesis.go @@ -3,11 +3,11 @@ package ibc import ( sdk "github.com/cosmos/cosmos-sdk/types" - client "github.com/cosmos/ibc-go/v3/modules/core/02-client" - connection "github.com/cosmos/ibc-go/v3/modules/core/03-connection" - channel "github.com/cosmos/ibc-go/v3/modules/core/04-channel" - "github.com/cosmos/ibc-go/v3/modules/core/keeper" - "github.com/cosmos/ibc-go/v3/modules/core/types" + client "github.com/cosmos/ibc-go/v4/modules/core/02-client" + connection "github.com/cosmos/ibc-go/v4/modules/core/03-connection" + channel "github.com/cosmos/ibc-go/v4/modules/core/04-channel" + "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/cosmos/ibc-go/v4/modules/core/types" ) // InitGenesis initializes the ibc state from a provided genesis diff --git a/modules/core/genesis_test.go b/modules/core/genesis_test.go index aa921f7c19e..cf0cf19efb0 100644 --- a/modules/core/genesis_test.go +++ b/modules/core/genesis_test.go @@ -8,17 +8,17 @@ import ( "github.com/stretchr/testify/suite" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - ibc "github.com/cosmos/ibc-go/v3/modules/core" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/core/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - "github.com/cosmos/ibc-go/v3/testing/simapp" + ibc "github.com/cosmos/ibc-go/v4/modules/core" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + localhosttypes "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) const ( diff --git a/modules/core/keeper/grpc_query.go b/modules/core/keeper/grpc_query.go index 138a4e7aa01..c42d7857616 100644 --- a/modules/core/keeper/grpc_query.go +++ b/modules/core/keeper/grpc_query.go @@ -3,9 +3,9 @@ package keeper import ( "context" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // ClientState implements the IBC QueryServer interface diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 12b259498ea..5ae7f4e40e7 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -9,14 +9,14 @@ import ( capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - clientkeeper "github.com/cosmos/ibc-go/v3/modules/core/02-client/keeper" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectionkeeper "github.com/cosmos/ibc-go/v3/modules/core/03-connection/keeper" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channelkeeper "github.com/cosmos/ibc-go/v3/modules/core/04-channel/keeper" - portkeeper "github.com/cosmos/ibc-go/v3/modules/core/05-port/keeper" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v3/modules/core/types" + clientkeeper "github.com/cosmos/ibc-go/v4/modules/core/02-client/keeper" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectionkeeper "github.com/cosmos/ibc-go/v4/modules/core/03-connection/keeper" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channelkeeper "github.com/cosmos/ibc-go/v4/modules/core/04-channel/keeper" + portkeeper "github.com/cosmos/ibc-go/v4/modules/core/05-port/keeper" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v4/modules/core/types" ) var _ types.QueryServer = (*Keeper)(nil) diff --git a/modules/core/keeper/keeper_test.go b/modules/core/keeper/keeper_test.go index 8e8c1138374..ef00da59032 100644 --- a/modules/core/keeper/keeper_test.go +++ b/modules/core/keeper/keeper_test.go @@ -11,10 +11,10 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type KeeperTestSuite struct { diff --git a/modules/core/keeper/migrations.go b/modules/core/keeper/migrations.go index 286ce5b2e97..5a79c8399ec 100644 --- a/modules/core/keeper/migrations.go +++ b/modules/core/keeper/migrations.go @@ -3,7 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - clientkeeper "github.com/cosmos/ibc-go/v3/modules/core/02-client/keeper" + clientkeeper "github.com/cosmos/ibc-go/v4/modules/core/02-client/keeper" ) // Migrator is a struct for handling in-place store migrations. diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index c090d7187d7..335998078b4 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -9,11 +9,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/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" - coretypes "github.com/cosmos/ibc-go/v3/modules/core/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + coretypes "github.com/cosmos/ibc-go/v4/modules/core/types" ) var ( diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 3cb0dc4fca0..3205c218bc7 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -4,15 +4,15 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/core/keeper" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" ) var ( diff --git a/modules/core/legacy/v100/genesis.go b/modules/core/legacy/v100/genesis.go index a1c85978ba2..78e8f0d6065 100644 --- a/modules/core/legacy/v100/genesis.go +++ b/modules/core/legacy/v100/genesis.go @@ -6,11 +6,11 @@ import ( genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" tmtypes "github.com/tendermint/tendermint/types" - clientv100 "github.com/cosmos/ibc-go/v3/modules/core/02-client/legacy/v100" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/types" + clientv100 "github.com/cosmos/ibc-go/v4/modules/core/02-client/legacy/v100" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/types" ) // MigrateGenesis accepts exported v1.0.0 IBC client genesis file and migrates it to: diff --git a/modules/core/legacy/v100/genesis_test.go b/modules/core/legacy/v100/genesis_test.go index b0db2e4e1b3..85e239862d9 100644 --- a/modules/core/legacy/v100/genesis_test.go +++ b/modules/core/legacy/v100/genesis_test.go @@ -9,15 +9,15 @@ import ( "github.com/stretchr/testify/suite" tmtypes "github.com/tendermint/tendermint/types" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/02-client" - clientv100 "github.com/cosmos/ibc-go/v3/modules/core/02-client/legacy/v100" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/legacy/v100" - "github.com/cosmos/ibc-go/v3/modules/core/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - "github.com/cosmos/ibc-go/v3/testing/simapp" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/02-client" + clientv100 "github.com/cosmos/ibc-go/v4/modules/core/02-client/legacy/v100" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + v100 "github.com/cosmos/ibc-go/v4/modules/core/legacy/v100" + "github.com/cosmos/ibc-go/v4/modules/core/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) type LegacyTestSuite struct { diff --git a/modules/core/module.go b/modules/core/module.go index 0cca3e37f1e..b6285997652 100644 --- a/modules/core/module.go +++ b/modules/core/module.go @@ -17,16 +17,16 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/02-client" - clientkeeper "github.com/cosmos/ibc-go/v3/modules/core/02-client/keeper" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/client/cli" - "github.com/cosmos/ibc-go/v3/modules/core/keeper" - "github.com/cosmos/ibc-go/v3/modules/core/simulation" - "github.com/cosmos/ibc-go/v3/modules/core/types" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/02-client" + clientkeeper "github.com/cosmos/ibc-go/v4/modules/core/02-client/keeper" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/client/cli" + "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/cosmos/ibc-go/v4/modules/core/simulation" + "github.com/cosmos/ibc-go/v4/modules/core/types" ) var ( diff --git a/modules/core/simulation/decoder.go b/modules/core/simulation/decoder.go index 16869f1b061..fc2cc40bf00 100644 --- a/modules/core/simulation/decoder.go +++ b/modules/core/simulation/decoder.go @@ -5,11 +5,11 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" - clientsim "github.com/cosmos/ibc-go/v3/modules/core/02-client/simulation" - connectionsim "github.com/cosmos/ibc-go/v3/modules/core/03-connection/simulation" - channelsim "github.com/cosmos/ibc-go/v3/modules/core/04-channel/simulation" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/keeper" + clientsim "github.com/cosmos/ibc-go/v4/modules/core/02-client/simulation" + connectionsim "github.com/cosmos/ibc-go/v4/modules/core/03-connection/simulation" + channelsim "github.com/cosmos/ibc-go/v4/modules/core/04-channel/simulation" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/keeper" ) // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's diff --git a/modules/core/simulation/decoder_test.go b/modules/core/simulation/decoder_test.go index 6639c96b8e4..f16d824c579 100644 --- a/modules/core/simulation/decoder_test.go +++ b/modules/core/simulation/decoder_test.go @@ -7,13 +7,13 @@ import ( "github.com/cosmos/cosmos-sdk/types/kv" "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/simulation" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v3/testing/simapp" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/simulation" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) func TestDecodeStore(t *testing.T) { diff --git a/modules/core/simulation/genesis.go b/modules/core/simulation/genesis.go index e6decacb26b..9f5e0bc7f8d 100644 --- a/modules/core/simulation/genesis.go +++ b/modules/core/simulation/genesis.go @@ -9,14 +9,14 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" - clientsims "github.com/cosmos/ibc-go/v3/modules/core/02-client/simulation" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectionsims "github.com/cosmos/ibc-go/v3/modules/core/03-connection/simulation" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channelsims "github.com/cosmos/ibc-go/v3/modules/core/04-channel/simulation" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/types" + clientsims "github.com/cosmos/ibc-go/v4/modules/core/02-client/simulation" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectionsims "github.com/cosmos/ibc-go/v4/modules/core/03-connection/simulation" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channelsims "github.com/cosmos/ibc-go/v4/modules/core/04-channel/simulation" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/types" ) // Simulation parameter constants diff --git a/modules/core/simulation/genesis_test.go b/modules/core/simulation/genesis_test.go index 6010f74c20f..20946fd5fd3 100644 --- a/modules/core/simulation/genesis_test.go +++ b/modules/core/simulation/genesis_test.go @@ -11,9 +11,9 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/stretchr/testify/require" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/simulation" - "github.com/cosmos/ibc-go/v3/modules/core/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/simulation" + "github.com/cosmos/ibc-go/v4/modules/core/types" ) // TestRandomizedGenState tests the normal scenario of applying RandomizedGenState. diff --git a/modules/core/types/codec.go b/modules/core/types/codec.go index 5caf105514e..c879aa3234e 100644 --- a/modules/core/types/codec.go +++ b/modules/core/types/codec.go @@ -3,13 +3,13 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - solomachinetypes "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - localhosttypes "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + solomachinetypes "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + localhosttypes "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types" ) // RegisterInterfaces registers x/ibc interfaces into protobuf Any. diff --git a/modules/core/types/genesis.go b/modules/core/types/genesis.go index 6b9304d9b8e..36a346cafff 100644 --- a/modules/core/types/genesis.go +++ b/modules/core/types/genesis.go @@ -3,9 +3,9 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) var _ codectypes.UnpackInterfacesMessage = GenesisState{} diff --git a/modules/core/types/genesis.pb.go b/modules/core/types/genesis.pb.go index 11fe53adab2..6072e44d1bd 100644 --- a/modules/core/types/genesis.pb.go +++ b/modules/core/types/genesis.pb.go @@ -5,9 +5,9 @@ package types import ( fmt "fmt" - types "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - types1 "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - types2 "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + types "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + types1 "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + types2 "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -97,28 +97,28 @@ func init() { func init() { proto.RegisterFile("ibc/core/types/v1/genesis.proto", fileDescriptor_b9a49c5663e6fc59) } var fileDescriptor_b9a49c5663e6fc59 = []byte{ - // 323 bytes of a gzipped FileDescriptorProto + // 324 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xb1, 0x4e, 0xeb, 0x30, 0x14, 0x86, 0x93, 0x5e, 0xe9, 0x0e, 0x01, 0x8a, 0x1a, 0x01, 0x82, 0x4a, 0xb8, 0x6d, 0xd4, 0x81, - 0x05, 0x5b, 0xa5, 0x1b, 0x63, 0x17, 0x98, 0xc3, 0xc6, 0x82, 0x12, 0x63, 0x52, 0xa3, 0xc4, 0xa7, - 0xaa, 0xdd, 0x48, 0x7d, 0x0b, 0x1e, 0xab, 0x63, 0x47, 0xc4, 0x50, 0xa1, 0xe4, 0x0d, 0x78, 0x02, - 0xd4, 0xd8, 0x24, 0xa9, 0xbc, 0x45, 0xff, 0xf9, 0xce, 0xff, 0x1d, 0x25, 0xf1, 0x06, 0x3c, 0xa6, - 0x84, 0xc2, 0x92, 0x11, 0xb5, 0x5e, 0x30, 0x49, 0xf2, 0x09, 0x49, 0x98, 0x60, 0x92, 0x4b, 0xbc, - 0x58, 0x82, 0x02, 0xbf, 0xc7, 0x63, 0x8a, 0xf7, 0x00, 0xae, 0x00, 0x9c, 0x4f, 0xfa, 0x67, 0x09, - 0x24, 0x50, 0x4d, 0xc9, 0xfe, 0x49, 0x83, 0xfd, 0x61, 0xdd, 0x44, 0x53, 0xce, 0x84, 0xb2, 0xaa, - 0xfa, 0xe3, 0x86, 0x00, 0x21, 0x18, 0x55, 0x1c, 0x84, 0x4d, 0x8d, 0x1a, 0x6a, 0x1e, 0x09, 0xc1, - 0x52, 0x0b, 0x09, 0xbe, 0x3a, 0xde, 0xf1, 0x83, 0x4e, 0x9e, 0x54, 0xa4, 0x98, 0xff, 0xe6, 0x75, - 0xb5, 0xf4, 0xc5, 0x80, 0x97, 0xee, 0xd0, 0xbd, 0x39, 0xba, 0x1b, 0xe2, 0xfa, 0x7a, 0x3d, 0xc7, - 0xf9, 0x04, 0xb7, 0x37, 0x67, 0xd7, 0x9b, 0xdd, 0xc0, 0xf9, 0xd9, 0x0d, 0xce, 0xd7, 0x51, 0x96, - 0xde, 0x07, 0x87, 0x2d, 0x41, 0x78, 0xa2, 0x03, 0xb3, 0xe2, 0xe7, 0x9e, 0xdf, 0x9c, 0x5e, 0xbb, - 0x3a, 0x95, 0x6b, 0xdc, 0x72, 0xd5, 0x8c, 0xe5, 0x1b, 0x19, 0xdf, 0x95, 0xf1, 0x59, 0x6d, 0x41, - 0xd8, 0x6b, 0xc2, 0x3f, 0xef, 0xbb, 0x77, 0x6a, 0x5e, 0x46, 0x2d, 0xfd, 0x57, 0x49, 0x47, 0x2d, - 0xa9, 0x06, 0x2c, 0x23, 0x32, 0xc6, 0x0b, 0x63, 0x3c, 0xec, 0x09, 0xc2, 0xae, 0x49, 0xcc, 0xd2, - 0xec, 0x71, 0x53, 0x20, 0x77, 0x5b, 0x20, 0xf7, 0xbb, 0x40, 0xee, 0x47, 0x89, 0x9c, 0x6d, 0x89, - 0x9c, 0xcf, 0x12, 0x39, 0xcf, 0x38, 0xe1, 0x6a, 0xbe, 0x8a, 0x31, 0x85, 0x8c, 0x50, 0x90, 0x19, - 0x48, 0xc2, 0x63, 0x7a, 0x9b, 0x00, 0xc9, 0xa7, 0x24, 0x83, 0xd7, 0x55, 0xca, 0x64, 0xeb, 0x5f, - 0x8a, 0xff, 0x57, 0x5f, 0x6b, 0xfa, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x81, 0x4d, 0x5d, 0x1d, 0x64, - 0x02, 0x00, 0x00, + 0x05, 0x5b, 0x05, 0x26, 0xc6, 0x2e, 0x30, 0x87, 0x8d, 0x05, 0x25, 0xc6, 0xa4, 0x46, 0x89, 0x4f, + 0x55, 0xbb, 0x91, 0xfa, 0x16, 0x3c, 0x56, 0xc7, 0x8e, 0x88, 0xa1, 0x42, 0xc9, 0x1b, 0xf0, 0x04, + 0xa8, 0xb1, 0x49, 0x52, 0x79, 0x8b, 0xfe, 0xf3, 0x9d, 0xff, 0x3b, 0x4a, 0xe2, 0x0d, 0x78, 0x4c, + 0x09, 0x85, 0x05, 0x23, 0x6a, 0x35, 0x67, 0x92, 0xe4, 0x13, 0x92, 0x30, 0xc1, 0x24, 0x97, 0x78, + 0xbe, 0x00, 0x05, 0x7e, 0x8f, 0xc7, 0x14, 0xef, 0x00, 0x5c, 0x01, 0x38, 0x9f, 0xf4, 0x4f, 0x12, + 0x48, 0xa0, 0x9a, 0x92, 0xdd, 0x93, 0x06, 0xfb, 0xc3, 0xba, 0x89, 0xa6, 0x9c, 0x09, 0x65, 0x55, + 0xf5, 0xc7, 0x0d, 0x01, 0x42, 0x30, 0xaa, 0x38, 0x08, 0x9b, 0x1a, 0x35, 0xd4, 0x2c, 0x12, 0x82, + 0xa5, 0x16, 0x12, 0x7c, 0x75, 0xbc, 0xc3, 0x07, 0x9d, 0x3c, 0xa9, 0x48, 0x31, 0xff, 0xcd, 0xeb, + 0x6a, 0xe9, 0x8b, 0x01, 0xcf, 0xdd, 0xa1, 0x7b, 0x75, 0x70, 0x33, 0xc4, 0xf5, 0xf5, 0x7a, 0x8e, + 0xf3, 0x09, 0x6e, 0x6f, 0x4e, 0x2f, 0xd7, 0xdb, 0x81, 0xf3, 0xb3, 0x1d, 0x9c, 0xae, 0xa2, 0x2c, + 0xbd, 0x0f, 0xf6, 0x5b, 0x82, 0xf0, 0x48, 0x07, 0x66, 0xc5, 0xcf, 0x3d, 0xbf, 0x39, 0xbd, 0x76, + 0x75, 0x2a, 0xd7, 0xb8, 0xe5, 0xaa, 0x19, 0xcb, 0x37, 0x32, 0xbe, 0x0b, 0xe3, 0xb3, 0xda, 0x82, + 0xb0, 0xd7, 0x84, 0x7f, 0xde, 0x77, 0xef, 0xd8, 0xbc, 0x8c, 0x5a, 0xfa, 0xaf, 0x92, 0x8e, 0x5a, + 0x52, 0x0d, 0x58, 0x46, 0x64, 0x8c, 0x67, 0xc6, 0xb8, 0xdf, 0x13, 0x84, 0x5d, 0x93, 0x98, 0xa5, + 0xe9, 0xe3, 0xba, 0x40, 0xee, 0xa6, 0x40, 0xee, 0x77, 0x81, 0xdc, 0x8f, 0x12, 0x39, 0x9b, 0x12, + 0x39, 0x9f, 0x25, 0x72, 0x9e, 0x71, 0xc2, 0xd5, 0x6c, 0x19, 0x63, 0x0a, 0x19, 0xa1, 0x20, 0x33, + 0x90, 0x84, 0xc7, 0xf4, 0x3a, 0x01, 0x92, 0xdf, 0x91, 0x0c, 0x5e, 0x97, 0x29, 0x93, 0xad, 0x7f, + 0x29, 0xfe, 0x5f, 0x7d, 0xad, 0xdb, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd2, 0xbe, 0x54, 0x19, + 0x64, 0x02, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/modules/core/types/query.go b/modules/core/types/query.go index ef9d0589448..6ebeb77ba5e 100644 --- a/modules/core/types/query.go +++ b/modules/core/types/query.go @@ -3,12 +3,12 @@ package types import ( "github.com/gogo/protobuf/grpc" - client "github.com/cosmos/ibc-go/v3/modules/core/02-client" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connection "github.com/cosmos/ibc-go/v3/modules/core/03-connection" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channel "github.com/cosmos/ibc-go/v3/modules/core/04-channel" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + client "github.com/cosmos/ibc-go/v4/modules/core/02-client" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connection "github.com/cosmos/ibc-go/v4/modules/core/03-connection" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channel "github.com/cosmos/ibc-go/v4/modules/core/04-channel" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // QueryServer defines the IBC interfaces that the gRPC query server must implement diff --git a/modules/light-clients/06-solomachine/module.go b/modules/light-clients/06-solomachine/module.go index d607282725a..60cfedb88f0 100644 --- a/modules/light-clients/06-solomachine/module.go +++ b/modules/light-clients/06-solomachine/module.go @@ -1,7 +1,7 @@ package solomachine import ( - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" ) // Name returns the solo machine client name. diff --git a/modules/light-clients/06-solomachine/types/client_state.go b/modules/light-clients/06-solomachine/types/client_state.go index d92f69b98e4..aa43e77e56d 100644 --- a/modules/light-clients/06-solomachine/types/client_state.go +++ b/modules/light-clients/06-solomachine/types/client_state.go @@ -9,10 +9,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/tx/signing" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.ClientState = (*ClientState)(nil) diff --git a/modules/light-clients/06-solomachine/types/client_state_test.go b/modules/light-clients/06-solomachine/types/client_state_test.go index 16b62b2722b..7ebd9bec925 100644 --- a/modules/light-clients/06-solomachine/types/client_state_test.go +++ b/modules/light-clients/06-solomachine/types/client_state_test.go @@ -1,14 +1,14 @@ package types_test import ( - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) const ( diff --git a/modules/light-clients/06-solomachine/types/codec.go b/modules/light-clients/06-solomachine/types/codec.go index 1db36165157..2fc3c930f5b 100644 --- a/modules/light-clients/06-solomachine/types/codec.go +++ b/modules/light-clients/06-solomachine/types/codec.go @@ -6,8 +6,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/tx/signing" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // RegisterInterfaces register the ibc channel submodule interfaces to protobuf diff --git a/modules/light-clients/06-solomachine/types/codec_test.go b/modules/light-clients/06-solomachine/types/codec_test.go index 0ed8760daa3..ed2afdafc41 100644 --- a/modules/light-clients/06-solomachine/types/codec_test.go +++ b/modules/light-clients/06-solomachine/types/codec_test.go @@ -1,11 +1,11 @@ package types_test import ( - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite SoloMachineTestSuite) TestUnmarshalDataByType() { diff --git a/modules/light-clients/06-solomachine/types/consensus_state.go b/modules/light-clients/06-solomachine/types/consensus_state.go index 3012f91a567..e6b53fced72 100644 --- a/modules/light-clients/06-solomachine/types/consensus_state.go +++ b/modules/light-clients/06-solomachine/types/consensus_state.go @@ -6,8 +6,8 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.ConsensusState = &ConsensusState{} diff --git a/modules/light-clients/06-solomachine/types/consensus_state_test.go b/modules/light-clients/06-solomachine/types/consensus_state_test.go index 2bb1ab5a456..29ea918a00b 100644 --- a/modules/light-clients/06-solomachine/types/consensus_state_test.go +++ b/modules/light-clients/06-solomachine/types/consensus_state_test.go @@ -1,9 +1,9 @@ package types_test import ( - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *SoloMachineTestSuite) TestConsensusState() { diff --git a/modules/light-clients/06-solomachine/types/header.go b/modules/light-clients/06-solomachine/types/header.go index 7bcfb9937c5..2f9ab4147fb 100644 --- a/modules/light-clients/06-solomachine/types/header.go +++ b/modules/light-clients/06-solomachine/types/header.go @@ -6,8 +6,8 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.Header = &Header{} diff --git a/modules/light-clients/06-solomachine/types/header_test.go b/modules/light-clients/06-solomachine/types/header_test.go index 48ce858c76a..607306f40c3 100644 --- a/modules/light-clients/06-solomachine/types/header_test.go +++ b/modules/light-clients/06-solomachine/types/header_test.go @@ -1,9 +1,9 @@ package types_test import ( - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *SoloMachineTestSuite) TestHeaderValidateBasic() { diff --git a/modules/light-clients/06-solomachine/types/misbehaviour.go b/modules/light-clients/06-solomachine/types/misbehaviour.go index f5df3e1bad9..6c002c45046 100644 --- a/modules/light-clients/06-solomachine/types/misbehaviour.go +++ b/modules/light-clients/06-solomachine/types/misbehaviour.go @@ -5,9 +5,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.Misbehaviour = &Misbehaviour{} diff --git a/modules/light-clients/06-solomachine/types/misbehaviour_handle.go b/modules/light-clients/06-solomachine/types/misbehaviour_handle.go index fb3dc573c3e..339ec884f1b 100644 --- a/modules/light-clients/06-solomachine/types/misbehaviour_handle.go +++ b/modules/light-clients/06-solomachine/types/misbehaviour_handle.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // CheckMisbehaviourAndUpdateState determines whether or not the currently registered diff --git a/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go b/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go index 7aa19617a76..d2718f75689 100644 --- a/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go +++ b/modules/light-clients/06-solomachine/types/misbehaviour_handle_test.go @@ -1,10 +1,10 @@ package types_test import ( - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *SoloMachineTestSuite) TestCheckMisbehaviourAndUpdateState() { diff --git a/modules/light-clients/06-solomachine/types/misbehaviour_test.go b/modules/light-clients/06-solomachine/types/misbehaviour_test.go index c304fc576ed..47724375494 100644 --- a/modules/light-clients/06-solomachine/types/misbehaviour_test.go +++ b/modules/light-clients/06-solomachine/types/misbehaviour_test.go @@ -1,9 +1,9 @@ package types_test import ( - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *SoloMachineTestSuite) TestMisbehaviour() { diff --git a/modules/light-clients/06-solomachine/types/proof.go b/modules/light-clients/06-solomachine/types/proof.go index 75a58cc3101..7389121488f 100644 --- a/modules/light-clients/06-solomachine/types/proof.go +++ b/modules/light-clients/06-solomachine/types/proof.go @@ -7,11 +7,11 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/tx/signing" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // VerifySignature verifies if the the provided public key generated the signature diff --git a/modules/light-clients/06-solomachine/types/proof_test.go b/modules/light-clients/06-solomachine/types/proof_test.go index 65e88aa3bde..f7f386e6339 100644 --- a/modules/light-clients/06-solomachine/types/proof_test.go +++ b/modules/light-clients/06-solomachine/types/proof_test.go @@ -4,9 +4,9 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - solomachinetypes "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + solomachinetypes "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *SoloMachineTestSuite) TestVerifySignature() { diff --git a/modules/light-clients/06-solomachine/types/proposal_handle.go b/modules/light-clients/06-solomachine/types/proposal_handle.go index c7d29faedc9..c4316f982a8 100644 --- a/modules/light-clients/06-solomachine/types/proposal_handle.go +++ b/modules/light-clients/06-solomachine/types/proposal_handle.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // CheckSubstituteAndUpdateState verifies that the subject is allowed to be updated by diff --git a/modules/light-clients/06-solomachine/types/proposal_handle_test.go b/modules/light-clients/06-solomachine/types/proposal_handle_test.go index f52bbffde44..b283cdbfdd9 100644 --- a/modules/light-clients/06-solomachine/types/proposal_handle_test.go +++ b/modules/light-clients/06-solomachine/types/proposal_handle_test.go @@ -1,10 +1,10 @@ package types_test import ( - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *SoloMachineTestSuite) TestCheckSubstituteAndUpdateState() { diff --git a/modules/light-clients/06-solomachine/types/solomachine.go b/modules/light-clients/06-solomachine/types/solomachine.go index 90eff77d200..0ce953e12c8 100644 --- a/modules/light-clients/06-solomachine/types/solomachine.go +++ b/modules/light-clients/06-solomachine/types/solomachine.go @@ -4,7 +4,7 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // Interface implementation checks. diff --git a/modules/light-clients/06-solomachine/types/solomachine.pb.go b/modules/light-clients/06-solomachine/types/solomachine.pb.go index 441a7030402..238f9849ede 100644 --- a/modules/light-clients/06-solomachine/types/solomachine.pb.go +++ b/modules/light-clients/06-solomachine/types/solomachine.pb.go @@ -6,8 +6,8 @@ package types import ( fmt "fmt" types "github.com/cosmos/cosmos-sdk/codec/types" - types1 "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - types2 "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + types1 "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + types2 "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -826,90 +826,90 @@ var fileDescriptor_141333b361aae010 = []byte{ // 1370 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x5f, 0x8f, 0xdb, 0x44, 0x10, 0x3f, 0xa7, 0xe9, 0xf5, 0x32, 0xb9, 0xde, 0x05, 0x37, 0x6d, 0x73, 0x6e, 0x95, 0x18, 0x23, - 0xca, 0x81, 0x68, 0xc2, 0x5d, 0x45, 0x85, 0x2a, 0x04, 0x38, 0x8e, 0x4b, 0xd3, 0xde, 0xf9, 0x82, - 0xe3, 0x03, 0x5a, 0x21, 0x19, 0xc7, 0xd9, 0x4b, 0xac, 0x26, 0xde, 0x34, 0x76, 0x92, 0x06, 0x09, - 0x09, 0xf1, 0x54, 0x22, 0x1e, 0xf8, 0x02, 0x91, 0x10, 0x88, 0xcf, 0xc1, 0x1b, 0xf0, 0xd8, 0x47, - 0x9e, 0x02, 0x6a, 0xbf, 0x41, 0x3e, 0x01, 0xb2, 0x77, 0x13, 0xdb, 0xb9, 0x5e, 0x4e, 0xfc, 0x7b, - 0xdb, 0x9d, 0xdf, 0xcc, 0x6f, 0x66, 0x67, 0xc6, 0xb3, 0x6b, 0xd8, 0xb1, 0x6a, 0x66, 0xa1, 0x65, - 0x35, 0x9a, 0xae, 0xd9, 0xb2, 0x90, 0xed, 0x3a, 0x05, 0x07, 0xb7, 0x70, 0xdb, 0x30, 0x9b, 0x96, - 0x8d, 0x0a, 0xfd, 0xdd, 0xf0, 0x36, 0xdf, 0xe9, 0x62, 0x17, 0xb3, 0x39, 0xab, 0x66, 0xe6, 0xc3, - 0x26, 0xf9, 0xb0, 0x4e, 0x7f, 0x97, 0x7b, 0xcd, 0xe3, 0x34, 0x71, 0x17, 0x15, 0x4c, 0x6c, 0xdb, - 0xc8, 0x74, 0x2d, 0x6c, 0x17, 0xfa, 0x3b, 0xa1, 0x1d, 0x61, 0xe2, 0x5e, 0x0e, 0x14, 0x9b, 0x86, - 0x6d, 0xa3, 0x96, 0xaf, 0x45, 0x96, 0x54, 0x25, 0xdd, 0xc0, 0x0d, 0xec, 0x2f, 0x0b, 0xde, 0x8a, - 0x4a, 0xb7, 0x1a, 0x18, 0x37, 0x5a, 0xa8, 0xe0, 0xef, 0x6a, 0xbd, 0xa3, 0x82, 0x61, 0x0f, 0x09, - 0x24, 0xfc, 0x1c, 0x83, 0xa4, 0xe4, 0xc7, 0x55, 0x75, 0x0d, 0x17, 0xb1, 0x1c, 0xac, 0x39, 0xe8, - 0x51, 0x0f, 0xd9, 0x26, 0xca, 0x30, 0x3c, 0xb3, 0x1d, 0x57, 0xe7, 0x7b, 0x76, 0x07, 0x12, 0x96, - 0xa3, 0x1f, 0x75, 0xf1, 0x17, 0xc8, 0xce, 0xc4, 0x78, 0x66, 0x7b, 0xad, 0x98, 0x9e, 0x4e, 0x72, - 0xa9, 0xa1, 0xd1, 0x6e, 0xdd, 0x12, 0xe6, 0x90, 0xa0, 0xae, 0x59, 0xce, 0x6d, 0x7f, 0xc9, 0xba, - 0xb0, 0x69, 0x62, 0xdb, 0x41, 0xb6, 0xd3, 0x73, 0x74, 0xc7, 0xf3, 0x90, 0x39, 0xc3, 0x33, 0xdb, - 0xc9, 0xdd, 0x42, 0xfe, 0x94, 0xb4, 0xe4, 0xa5, 0x99, 0x9d, 0x1f, 0x58, 0x91, 0x9b, 0x4e, 0x72, - 0x97, 0x88, 0xa7, 0x05, 0x46, 0x41, 0xdd, 0x30, 0x23, 0xba, 0x2c, 0x82, 0x2b, 0x46, 0xab, 0x85, - 0x07, 0x7a, 0xaf, 0x53, 0x37, 0x5c, 0xa4, 0x1b, 0x47, 0x2e, 0xea, 0xea, 0x9d, 0x2e, 0xee, 0x60, - 0xc7, 0x68, 0x65, 0xe2, 0x7e, 0xe8, 0xd7, 0xa6, 0x93, 0x9c, 0x40, 0x08, 0x97, 0x28, 0x0b, 0x6a, - 0xc6, 0x47, 0x0f, 0x7d, 0x50, 0xf4, 0xb0, 0x0a, 0x85, 0x6e, 0xc5, 0x9f, 0x7c, 0x9f, 0x5b, 0x11, - 0x7e, 0x60, 0x60, 0x23, 0x1a, 0x2b, 0x7b, 0x17, 0xa0, 0xd3, 0xab, 0xb5, 0x2c, 0x53, 0x7f, 0x88, - 0x86, 0x7e, 0x1a, 0x93, 0xbb, 0xe9, 0x3c, 0x29, 0x42, 0x7e, 0x56, 0x84, 0xbc, 0x68, 0x0f, 0x8b, - 0x17, 0xa7, 0x93, 0xdc, 0x4b, 0x24, 0x88, 0xc0, 0x42, 0x50, 0x13, 0x64, 0x73, 0x0f, 0x0d, 0x59, - 0x1e, 0x92, 0x75, 0xab, 0x8f, 0xba, 0x8e, 0x75, 0x64, 0xa1, 0xae, 0x9f, 0xf6, 0x84, 0x1a, 0x16, - 0xb1, 0x57, 0x21, 0xe1, 0x5a, 0x6d, 0xe4, 0xb8, 0x46, 0xbb, 0xe3, 0x67, 0x37, 0xae, 0x06, 0x02, - 0x1a, 0xe4, 0xd7, 0x31, 0x58, 0xbd, 0x83, 0x8c, 0x3a, 0xea, 0x2e, 0xad, 0x70, 0x84, 0x2a, 0xb6, - 0x40, 0xe5, 0xa1, 0x8e, 0xd5, 0xb0, 0x0d, 0xb7, 0xd7, 0x25, 0x65, 0x5c, 0x57, 0x03, 0x01, 0x7b, - 0x08, 0x1b, 0x36, 0x1a, 0xe8, 0xa1, 0x83, 0xc7, 0x97, 0x1c, 0x7c, 0x6b, 0x3a, 0xc9, 0x5d, 0x24, - 0x07, 0x8f, 0x5a, 0x09, 0xea, 0xba, 0x8d, 0x06, 0x95, 0xf9, 0xf9, 0x25, 0xd8, 0xf4, 0x14, 0xc2, - 0x39, 0x38, 0xeb, 0xe5, 0x20, 0xdc, 0x10, 0x0b, 0x0a, 0x82, 0xea, 0x45, 0x52, 0x0a, 0x04, 0x34, - 0x09, 0xbf, 0xc6, 0x60, 0x7d, 0xdf, 0x72, 0x6a, 0xa8, 0x69, 0xf4, 0x2d, 0xdc, 0xeb, 0x7a, 0x0d, - 0x4d, 0x9a, 0x4f, 0xb7, 0xea, 0x7e, 0x2e, 0x12, 0xe1, 0x86, 0x9e, 0x43, 0x82, 0xba, 0x46, 0xd6, - 0xe5, 0x7a, 0x24, 0x7b, 0xb1, 0x85, 0xec, 0x75, 0xe0, 0xfc, 0x3c, 0x1d, 0x3a, 0xb6, 0x67, 0xad, - 0xbe, 0x73, 0x6a, 0xab, 0x57, 0x67, 0x56, 0xa2, 0x5d, 0x2f, 0x19, 0xae, 0x51, 0xcc, 0x4c, 0x27, - 0xb9, 0x34, 0x89, 0x22, 0xc2, 0x28, 0xa8, 0xeb, 0xf3, 0xfd, 0x81, 0xbd, 0xe0, 0xd1, 0x1d, 0x60, - 0x9a, 0xf2, 0xff, 0xca, 0xa3, 0x3b, 0xc0, 0x61, 0x8f, 0xda, 0x00, 0xd3, 0x4c, 0xfe, 0xc2, 0x40, - 0x6a, 0x91, 0x22, 0xda, 0x1e, 0xcc, 0x62, 0x7b, 0x7c, 0x06, 0x89, 0xba, 0xe1, 0x1a, 0xba, 0x3b, - 0xec, 0x90, 0xcc, 0x6d, 0xec, 0xbe, 0x7e, 0x6a, 0x98, 0x1e, 0xaf, 0x36, 0xec, 0xa0, 0x70, 0x59, - 0xe6, 0x2c, 0x82, 0xba, 0x56, 0xa7, 0x38, 0xcb, 0x42, 0xdc, 0x5b, 0xd3, 0xae, 0xf4, 0xd7, 0xd1, - 0x66, 0x8e, 0xbf, 0xf8, 0xbb, 0xf8, 0x8a, 0x81, 0x8c, 0x36, 0x93, 0xa1, 0xfa, 0xfc, 0x4c, 0xfe, - 0x81, 0x3e, 0x80, 0x8d, 0x20, 0x17, 0x3e, 0xbd, 0x7f, 0xaa, 0x70, 0xef, 0x46, 0x71, 0x41, 0x0d, - 0xca, 0x51, 0x3a, 0x16, 0x42, 0xec, 0xc5, 0x21, 0xfc, 0xc1, 0x40, 0xc2, 0xf3, 0x5b, 0x1c, 0xba, - 0xc8, 0xf9, 0x17, 0x5f, 0xe7, 0xc2, 0xa0, 0x38, 0x73, 0x7c, 0x50, 0x44, 0x4a, 0x10, 0xff, 0xbf, - 0x4a, 0x70, 0x36, 0x28, 0x01, 0x3d, 0xe1, 0x4f, 0x0c, 0x00, 0x19, 0x3e, 0x7e, 0x52, 0xf6, 0x20, - 0x49, 0x3f, 0xf9, 0x53, 0xc7, 0xe3, 0xa5, 0xe9, 0x24, 0xc7, 0x46, 0xa6, 0x04, 0x9d, 0x8f, 0x64, - 0x44, 0x9c, 0x30, 0x1f, 0x62, 0xff, 0x70, 0x3e, 0x7c, 0x09, 0x9b, 0xa1, 0xab, 0xd0, 0x8f, 0x95, - 0x85, 0x78, 0xc7, 0x70, 0x9b, 0xb4, 0x9d, 0xfd, 0x35, 0x5b, 0x81, 0x75, 0x3a, 0x1a, 0xc8, 0x85, - 0x16, 0x5b, 0x72, 0x80, 0xcb, 0xd3, 0x49, 0xee, 0x42, 0x64, 0x9c, 0xd0, 0x2b, 0x2b, 0x69, 0x06, - 0x9e, 0xa8, 0xfb, 0x6f, 0x18, 0x60, 0xa3, 0x17, 0xc9, 0x89, 0x21, 0xdc, 0x3f, 0x7e, 0xad, 0x2e, - 0x8b, 0xe2, 0x6f, 0xdc, 0x9d, 0x34, 0x96, 0x3e, 0x5c, 0x90, 0xe6, 0xcf, 0x8f, 0xe5, 0xb1, 0xc8, - 0x00, 0xc1, 0x4b, 0x85, 0x86, 0xf1, 0xaa, 0xdf, 0x56, 0xde, 0x53, 0x25, 0x1f, 0x7a, 0xc5, 0xf4, - 0x77, 0xf2, 0x01, 0xa9, 0x6c, 0xd7, 0xd5, 0x90, 0x21, 0xf5, 0x5b, 0x87, 0x94, 0x44, 0x1e, 0x34, - 0xcb, 0x9d, 0xde, 0x84, 0x73, 0xf4, 0xe1, 0x43, 0x3d, 0x5e, 0x0d, 0x79, 0xa4, 0x2f, 0x22, 0xcf, - 0x1d, 0x59, 0xaa, 0x33, 0x65, 0xea, 0xe5, 0x2e, 0xa4, 0x2b, 0x86, 0xf9, 0x10, 0xb9, 0x12, 0x6e, - 0xb7, 0x2d, 0xb7, 0x8d, 0x6c, 0xf7, 0x44, 0x4f, 0x59, 0xef, 0x78, 0x33, 0x2d, 0xdf, 0xd9, 0xba, - 0x1a, 0x92, 0x08, 0xf7, 0x61, 0x8b, 0x70, 0x89, 0xe6, 0x43, 0x1b, 0x0f, 0x5a, 0xa8, 0xde, 0x40, - 0x4b, 0x09, 0xb7, 0x61, 0xd3, 0x88, 0xaa, 0x52, 0xd6, 0x45, 0xb1, 0x90, 0x87, 0x0c, 0xa1, 0x56, - 0x91, 0x89, 0xac, 0x8e, 0x2b, 0xd6, 0x1c, 0x6f, 0x0e, 0x9c, 0xc4, 0x2c, 0x34, 0x21, 0xad, 0xa0, - 0xc7, 0x6e, 0x95, 0xce, 0x0b, 0x15, 0x99, 0xfd, 0x13, 0xa3, 0x78, 0x17, 0xce, 0xdb, 0xe8, 0xb1, - 0xab, 0x3b, 0xe8, 0x91, 0xde, 0x45, 0x66, 0x9f, 0xcc, 0x93, 0xf0, 0x35, 0x10, 0x81, 0x05, 0x35, - 0x69, 0x13, 0x6a, 0x8f, 0xf5, 0x8d, 0x6f, 0xe3, 0xb0, 0x36, 0x1b, 0x0c, 0xec, 0x3b, 0xf0, 0x4a, - 0x49, 0xd4, 0x44, 0x5d, 0xbb, 0x5f, 0x91, 0xf5, 0x43, 0xa5, 0xac, 0x94, 0xb5, 0xb2, 0xb8, 0x57, - 0x7e, 0x20, 0x97, 0xf4, 0x43, 0xa5, 0x5a, 0x91, 0xa5, 0xf2, 0xed, 0xb2, 0x5c, 0x4a, 0xad, 0x70, - 0x9b, 0xa3, 0x31, 0x9f, 0x0c, 0x89, 0xd8, 0x6b, 0x70, 0x29, 0xb0, 0x94, 0xf6, 0xca, 0xb2, 0xa2, - 0xe9, 0x55, 0x4d, 0xd4, 0xe4, 0x14, 0xc3, 0xc1, 0x68, 0xcc, 0xaf, 0x12, 0x19, 0xfb, 0x26, 0x6c, - 0x85, 0xf4, 0x0e, 0x94, 0xaa, 0xac, 0x54, 0x0f, 0xab, 0x54, 0x35, 0xc6, 0x9d, 0x1f, 0x8d, 0xf9, - 0xc4, 0x5c, 0xcc, 0xe6, 0x81, 0x8b, 0x68, 0x2b, 0xb2, 0xa4, 0x95, 0x0f, 0x14, 0xaa, 0x7e, 0x86, - 0xdb, 0x18, 0x8d, 0x79, 0x08, 0xe4, 0xec, 0x36, 0x5c, 0x0e, 0xe9, 0xdf, 0x11, 0x15, 0x45, 0xde, - 0xa3, 0xca, 0x71, 0x2e, 0x39, 0x1a, 0xf3, 0xe7, 0xa8, 0x90, 0x7d, 0x1b, 0xae, 0x04, 0x9a, 0x15, - 0x51, 0xba, 0x27, 0x6b, 0xba, 0x74, 0xb0, 0xbf, 0x5f, 0xd6, 0xf6, 0x65, 0x45, 0x4b, 0x9d, 0xe5, - 0xd2, 0xa3, 0x31, 0x9f, 0x22, 0x40, 0x20, 0x67, 0xdf, 0x07, 0xfe, 0x98, 0x99, 0x28, 0xdd, 0x53, - 0x0e, 0x3e, 0xd9, 0x93, 0x4b, 0x1f, 0xca, 0xbe, 0xed, 0x2a, 0xb7, 0x35, 0x1a, 0xf3, 0x17, 0x09, - 0xba, 0x00, 0xb2, 0xef, 0xbd, 0x80, 0x40, 0x95, 0x25, 0xb9, 0x5c, 0xd1, 0x74, 0xb1, 0x58, 0x95, - 0x15, 0x49, 0x4e, 0x9d, 0xe3, 0x32, 0xa3, 0x31, 0x9f, 0x26, 0x28, 0x05, 0x29, 0xc6, 0xde, 0x84, - 0xab, 0x81, 0xbd, 0x22, 0x7f, 0xaa, 0xe9, 0x55, 0xf9, 0xa3, 0x43, 0x0f, 0xf2, 0x68, 0x3e, 0x4e, - 0xad, 0x91, 0xc0, 0x3d, 0x64, 0x06, 0x78, 0x72, 0x96, 0x87, 0x54, 0x60, 0x77, 0x47, 0x16, 0x4b, - 0xb2, 0x9a, 0x4a, 0x90, 0xca, 0x90, 0x1d, 0x17, 0x7f, 0xf2, 0x63, 0x76, 0xa5, 0xf8, 0xf9, 0x6f, - 0xcf, 0xb2, 0xcc, 0xd3, 0x67, 0x59, 0xe6, 0xcf, 0x67, 0x59, 0xe6, 0xbb, 0xe7, 0xd9, 0x95, 0xa7, - 0xcf, 0xb3, 0x2b, 0xbf, 0x3f, 0xcf, 0xae, 0x3c, 0xb8, 0xdd, 0xb0, 0xdc, 0x66, 0xaf, 0x96, 0x37, - 0x71, 0xbb, 0x60, 0x62, 0xa7, 0x8d, 0x9d, 0x82, 0x55, 0x33, 0xaf, 0x37, 0x70, 0xa1, 0x7f, 0xa3, - 0xd0, 0xc6, 0xf5, 0x5e, 0x0b, 0x39, 0xe4, 0x7f, 0xea, 0xfa, 0xec, 0x87, 0xea, 0xad, 0x9b, 0xd7, - 0xc3, 0xff, 0x54, 0xde, 0x35, 0xe3, 0xd4, 0x56, 0xfd, 0x79, 0x76, 0xe3, 0xaf, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x5d, 0xd4, 0x6c, 0xfb, 0x80, 0x0d, 0x00, 0x00, + 0xca, 0x81, 0x68, 0xc2, 0x1d, 0x50, 0xa1, 0x0a, 0x01, 0x8e, 0xe3, 0xd2, 0xb4, 0x77, 0xbe, 0xe0, + 0xf8, 0x80, 0x56, 0x48, 0xc6, 0x71, 0xf6, 0x12, 0xab, 0x89, 0x37, 0x8d, 0x9d, 0xa4, 0x41, 0x42, + 0x42, 0x3c, 0x95, 0x88, 0x07, 0xbe, 0x40, 0x24, 0x04, 0xe2, 0x73, 0xf0, 0x06, 0x3c, 0xf6, 0x91, + 0xa7, 0x80, 0xda, 0x6f, 0x90, 0x4f, 0x80, 0xec, 0xdd, 0xc4, 0x76, 0xae, 0x97, 0x13, 0xff, 0xde, + 0x76, 0xe7, 0x37, 0xf3, 0x9b, 0xd9, 0x99, 0xf1, 0xec, 0x1a, 0x76, 0xac, 0x9a, 0x59, 0x68, 0x59, + 0x8d, 0xa6, 0x6b, 0xb6, 0x2c, 0x64, 0xbb, 0x4e, 0xc1, 0xc1, 0x2d, 0xdc, 0x36, 0xcc, 0xa6, 0x65, + 0xa3, 0x42, 0x7f, 0x37, 0xbc, 0xcd, 0x77, 0xba, 0xd8, 0xc5, 0x6c, 0xce, 0xaa, 0x99, 0xf9, 0xb0, + 0x49, 0x3e, 0xac, 0xd3, 0xdf, 0xe5, 0x5e, 0xf1, 0x38, 0x4d, 0xdc, 0x45, 0x05, 0x13, 0xdb, 0x36, + 0x32, 0x5d, 0x0b, 0xdb, 0x85, 0xfe, 0x4e, 0x68, 0x47, 0x98, 0xb8, 0x17, 0x03, 0xc5, 0xa6, 0x61, + 0xdb, 0xa8, 0xe5, 0x6b, 0x91, 0x25, 0x55, 0x49, 0x37, 0x70, 0x03, 0xfb, 0xcb, 0x82, 0xb7, 0xa2, + 0xd2, 0xad, 0x06, 0xc6, 0x8d, 0x16, 0x2a, 0xf8, 0xbb, 0x5a, 0xef, 0xa8, 0x60, 0xd8, 0x43, 0x02, + 0x09, 0x3f, 0xc7, 0x20, 0x29, 0xf9, 0x71, 0x55, 0x5d, 0xc3, 0x45, 0x2c, 0x07, 0x6b, 0x0e, 0x7a, + 0xd8, 0x43, 0xb6, 0x89, 0x32, 0x0c, 0xcf, 0x6c, 0xc7, 0xd5, 0xf9, 0x9e, 0xdd, 0x81, 0x84, 0xe5, + 0xe8, 0x47, 0x5d, 0xfc, 0x05, 0xb2, 0x33, 0x31, 0x9e, 0xd9, 0x5e, 0x2b, 0xa6, 0xa7, 0x93, 0x5c, + 0x6a, 0x68, 0xb4, 0x5b, 0x37, 0x85, 0x39, 0x24, 0xa8, 0x6b, 0x96, 0x73, 0xcb, 0x5f, 0xb2, 0x2e, + 0x6c, 0x9a, 0xd8, 0x76, 0x90, 0xed, 0xf4, 0x1c, 0xdd, 0xf1, 0x3c, 0x64, 0xce, 0xf0, 0xcc, 0x76, + 0x72, 0xb7, 0x90, 0x3f, 0x25, 0x2d, 0x79, 0x69, 0x66, 0xe7, 0x07, 0x56, 0xe4, 0xa6, 0x93, 0xdc, + 0x25, 0xe2, 0x69, 0x81, 0x51, 0x50, 0x37, 0xcc, 0x88, 0x2e, 0x8b, 0xe0, 0x8a, 0xd1, 0x6a, 0xe1, + 0x81, 0xde, 0xeb, 0xd4, 0x0d, 0x17, 0xe9, 0xc6, 0x91, 0x8b, 0xba, 0x7a, 0xa7, 0x8b, 0x3b, 0xd8, + 0x31, 0x5a, 0x99, 0xb8, 0x1f, 0xfa, 0xb5, 0xe9, 0x24, 0x27, 0x10, 0xc2, 0x25, 0xca, 0x82, 0x9a, + 0xf1, 0xd1, 0x43, 0x1f, 0x14, 0x3d, 0xac, 0x42, 0xa1, 0x9b, 0xf1, 0xc7, 0xdf, 0xe7, 0x56, 0x84, + 0x1f, 0x18, 0xd8, 0x88, 0xc6, 0xca, 0xde, 0x01, 0xe8, 0xf4, 0x6a, 0x2d, 0xcb, 0xd4, 0x1f, 0xa0, + 0xa1, 0x9f, 0xc6, 0xe4, 0x6e, 0x3a, 0x4f, 0x8a, 0x90, 0x9f, 0x15, 0x21, 0x2f, 0xda, 0xc3, 0xe2, + 0xc5, 0xe9, 0x24, 0xf7, 0x02, 0x09, 0x22, 0xb0, 0x10, 0xd4, 0x04, 0xd9, 0xdc, 0x45, 0x43, 0x96, + 0x87, 0x64, 0xdd, 0xea, 0xa3, 0xae, 0x63, 0x1d, 0x59, 0xa8, 0xeb, 0xa7, 0x3d, 0xa1, 0x86, 0x45, + 0xec, 0x55, 0x48, 0xb8, 0x56, 0x1b, 0x39, 0xae, 0xd1, 0xee, 0xf8, 0xd9, 0x8d, 0xab, 0x81, 0x80, + 0x06, 0xf9, 0x75, 0x0c, 0x56, 0x6f, 0x23, 0xa3, 0x8e, 0xba, 0x4b, 0x2b, 0x1c, 0xa1, 0x8a, 0x2d, + 0x50, 0x79, 0xa8, 0x63, 0x35, 0x6c, 0xc3, 0xed, 0x75, 0x49, 0x19, 0xd7, 0xd5, 0x40, 0xc0, 0x1e, + 0xc2, 0x86, 0x8d, 0x06, 0x7a, 0xe8, 0xe0, 0xf1, 0x25, 0x07, 0xdf, 0x9a, 0x4e, 0x72, 0x17, 0xc9, + 0xc1, 0xa3, 0x56, 0x82, 0xba, 0x6e, 0xa3, 0x41, 0x65, 0x7e, 0x7e, 0x09, 0x36, 0x3d, 0x85, 0x70, + 0x0e, 0xce, 0x7a, 0x39, 0x08, 0x37, 0xc4, 0x82, 0x82, 0xa0, 0x7a, 0x91, 0x94, 0x02, 0x01, 0x4d, + 0xc2, 0xaf, 0x31, 0x58, 0xdf, 0xb7, 0x9c, 0x1a, 0x6a, 0x1a, 0x7d, 0x0b, 0xf7, 0xba, 0x5e, 0x43, + 0x93, 0xe6, 0xd3, 0xad, 0xba, 0x9f, 0x8b, 0x44, 0xb8, 0xa1, 0xe7, 0x90, 0xa0, 0xae, 0x91, 0x75, + 0xb9, 0x1e, 0xc9, 0x5e, 0x6c, 0x21, 0x7b, 0x1d, 0x38, 0x3f, 0x4f, 0x87, 0x8e, 0xed, 0x59, 0xab, + 0xef, 0x9c, 0xda, 0xea, 0xd5, 0x99, 0x95, 0x68, 0xd7, 0x4b, 0x86, 0x6b, 0x14, 0x33, 0xd3, 0x49, + 0x2e, 0x4d, 0xa2, 0x88, 0x30, 0x0a, 0xea, 0xfa, 0x7c, 0x7f, 0x60, 0x2f, 0x78, 0x74, 0x07, 0x98, + 0xa6, 0xfc, 0xbf, 0xf2, 0xe8, 0x0e, 0x70, 0xd8, 0xa3, 0x36, 0xc0, 0x34, 0x93, 0xbf, 0x30, 0x90, + 0x5a, 0xa4, 0x88, 0xb6, 0x07, 0xb3, 0xd8, 0x1e, 0x9f, 0x41, 0xa2, 0x6e, 0xb8, 0x86, 0xee, 0x0e, + 0x3b, 0x24, 0x73, 0x1b, 0xbb, 0xaf, 0x9e, 0x1a, 0xa6, 0xc7, 0xab, 0x0d, 0x3b, 0x28, 0x5c, 0x96, + 0x39, 0x8b, 0xa0, 0xae, 0xd5, 0x29, 0xce, 0xb2, 0x10, 0xf7, 0xd6, 0xb4, 0x2b, 0xfd, 0x75, 0xb4, + 0x99, 0xe3, 0xcf, 0xff, 0x2e, 0xbe, 0x62, 0x20, 0xa3, 0xcd, 0x64, 0xa8, 0x3e, 0x3f, 0x93, 0x7f, + 0xa0, 0x0f, 0x60, 0x23, 0xc8, 0x85, 0x4f, 0xef, 0x9f, 0x2a, 0xdc, 0xbb, 0x51, 0x5c, 0x50, 0x83, + 0x72, 0x94, 0x8e, 0x85, 0x10, 0x7b, 0x7e, 0x08, 0x7f, 0x30, 0x90, 0xf0, 0xfc, 0x16, 0x87, 0x2e, + 0x72, 0xfe, 0xc5, 0xd7, 0xb9, 0x30, 0x28, 0xce, 0x1c, 0x1f, 0x14, 0x91, 0x12, 0xc4, 0xff, 0xaf, + 0x12, 0x9c, 0x0d, 0x4a, 0x40, 0x4f, 0xf8, 0x13, 0x03, 0x40, 0x86, 0x8f, 0x9f, 0x94, 0x3d, 0x48, + 0xd2, 0x4f, 0xfe, 0xd4, 0xf1, 0x78, 0x69, 0x3a, 0xc9, 0xb1, 0x91, 0x29, 0x41, 0xe7, 0x23, 0x19, + 0x11, 0x27, 0xcc, 0x87, 0xd8, 0x3f, 0x9c, 0x0f, 0x5f, 0xc2, 0x66, 0xe8, 0x2a, 0xf4, 0x63, 0x65, + 0x21, 0xde, 0x31, 0xdc, 0x26, 0x6d, 0x67, 0x7f, 0xcd, 0x56, 0x60, 0x9d, 0x8e, 0x06, 0x72, 0xa1, + 0xc5, 0x96, 0x1c, 0xe0, 0xf2, 0x74, 0x92, 0xbb, 0x10, 0x19, 0x27, 0xf4, 0xca, 0x4a, 0x9a, 0x81, + 0x27, 0xea, 0xfe, 0x1b, 0x06, 0xd8, 0xe8, 0x45, 0x72, 0x62, 0x08, 0xf7, 0x8e, 0x5f, 0xab, 0xcb, + 0xa2, 0xf8, 0x1b, 0x77, 0x27, 0x8d, 0xa5, 0x0f, 0x17, 0xa4, 0xf9, 0xf3, 0x63, 0x79, 0x2c, 0x32, + 0x40, 0xf0, 0x52, 0xa1, 0x61, 0xbc, 0xec, 0xb7, 0x95, 0xf7, 0x54, 0xc9, 0x87, 0x5e, 0x31, 0xfd, + 0x9d, 0x7c, 0x40, 0x2a, 0xdb, 0x75, 0x35, 0x64, 0x48, 0xfd, 0xd6, 0x21, 0x25, 0x91, 0x07, 0xcd, + 0x72, 0xa7, 0x37, 0xe0, 0x1c, 0x7d, 0xf8, 0x50, 0x8f, 0x57, 0x43, 0x1e, 0xe9, 0x8b, 0xc8, 0x73, + 0x47, 0x96, 0xea, 0x4c, 0x99, 0x7a, 0xb9, 0x03, 0xe9, 0x8a, 0x61, 0x3e, 0x40, 0xae, 0x84, 0xdb, + 0x6d, 0xcb, 0x6d, 0x23, 0xdb, 0x3d, 0xd1, 0x53, 0xd6, 0x3b, 0xde, 0x4c, 0xcb, 0x77, 0xb6, 0xae, + 0x86, 0x24, 0xc2, 0x3d, 0xd8, 0x22, 0x5c, 0xa2, 0xf9, 0xc0, 0xc6, 0x83, 0x16, 0xaa, 0x37, 0xd0, + 0x52, 0xc2, 0x6d, 0xd8, 0x34, 0xa2, 0xaa, 0x94, 0x75, 0x51, 0x2c, 0xe4, 0x21, 0x43, 0xa8, 0x55, + 0x64, 0x22, 0xab, 0xe3, 0x8a, 0x35, 0xc7, 0x9b, 0x03, 0x27, 0x31, 0x0b, 0x4d, 0x48, 0x2b, 0xe8, + 0x91, 0x5b, 0xa5, 0xf3, 0x42, 0x45, 0x66, 0xff, 0xc4, 0x28, 0xde, 0x85, 0xf3, 0x36, 0x7a, 0xe4, + 0xea, 0x0e, 0x7a, 0xa8, 0x77, 0x91, 0xd9, 0x27, 0xf3, 0x24, 0x7c, 0x0d, 0x44, 0x60, 0x41, 0x4d, + 0xda, 0x84, 0xda, 0x63, 0x7d, 0xed, 0xdb, 0x38, 0xac, 0xcd, 0x06, 0x03, 0xfb, 0x0e, 0xbc, 0x54, + 0x12, 0x35, 0x51, 0xd7, 0xee, 0x55, 0x64, 0xfd, 0x50, 0x29, 0x2b, 0x65, 0xad, 0x2c, 0xee, 0x95, + 0xef, 0xcb, 0x25, 0xfd, 0x50, 0xa9, 0x56, 0x64, 0xa9, 0x7c, 0xab, 0x2c, 0x97, 0x52, 0x2b, 0xdc, + 0xe6, 0x68, 0xcc, 0x27, 0x43, 0x22, 0xf6, 0x1a, 0x5c, 0x0a, 0x2c, 0xa5, 0xbd, 0xb2, 0xac, 0x68, + 0x7a, 0x55, 0x13, 0x35, 0x39, 0xc5, 0x70, 0x30, 0x1a, 0xf3, 0xab, 0x44, 0xc6, 0xbe, 0x0e, 0x5b, + 0x21, 0xbd, 0x03, 0xa5, 0x2a, 0x2b, 0xd5, 0xc3, 0x2a, 0x55, 0x8d, 0x71, 0xe7, 0x47, 0x63, 0x3e, + 0x31, 0x17, 0xb3, 0x79, 0xe0, 0x22, 0xda, 0x8a, 0x2c, 0x69, 0xe5, 0x03, 0x85, 0xaa, 0x9f, 0xe1, + 0x36, 0x46, 0x63, 0x1e, 0x02, 0x39, 0xbb, 0x0d, 0x97, 0x43, 0xfa, 0xb7, 0x45, 0x45, 0x91, 0xf7, + 0xa8, 0x72, 0x9c, 0x4b, 0x8e, 0xc6, 0xfc, 0x39, 0x2a, 0x64, 0xdf, 0x86, 0x2b, 0x81, 0x66, 0x45, + 0x94, 0xee, 0xca, 0x9a, 0x2e, 0x1d, 0xec, 0xef, 0x97, 0xb5, 0x7d, 0x59, 0xd1, 0x52, 0x67, 0xb9, + 0xf4, 0x68, 0xcc, 0xa7, 0x08, 0x10, 0xc8, 0xd9, 0xf7, 0x81, 0x3f, 0x66, 0x26, 0x4a, 0x77, 0x95, + 0x83, 0x4f, 0xf6, 0xe4, 0xd2, 0x87, 0xb2, 0x6f, 0xbb, 0xca, 0x6d, 0x8d, 0xc6, 0xfc, 0x45, 0x82, + 0x2e, 0x80, 0xec, 0x7b, 0xcf, 0x21, 0x50, 0x65, 0x49, 0x2e, 0x57, 0x34, 0x5d, 0x2c, 0x56, 0x65, + 0x45, 0x92, 0x53, 0xe7, 0xb8, 0xcc, 0x68, 0xcc, 0xa7, 0x09, 0x4a, 0x41, 0x8a, 0xb1, 0x37, 0xe0, + 0x6a, 0x60, 0xaf, 0xc8, 0x9f, 0x6a, 0x7a, 0x55, 0xfe, 0xe8, 0xd0, 0x83, 0x3c, 0x9a, 0x8f, 0x53, + 0x6b, 0x24, 0x70, 0x0f, 0x99, 0x01, 0x9e, 0x9c, 0xe5, 0x21, 0x15, 0xd8, 0xdd, 0x96, 0xc5, 0x92, + 0xac, 0xa6, 0x12, 0xa4, 0x32, 0x64, 0xc7, 0xc5, 0x1f, 0xff, 0x98, 0x5d, 0x29, 0x7e, 0xfe, 0xdb, + 0xd3, 0x2c, 0xf3, 0xe4, 0x69, 0x96, 0xf9, 0xf3, 0x69, 0x96, 0xf9, 0xee, 0x59, 0x76, 0xe5, 0xc9, + 0xb3, 0xec, 0xca, 0xef, 0xcf, 0xb2, 0x2b, 0xf7, 0x6f, 0x35, 0x2c, 0xb7, 0xd9, 0xab, 0xe5, 0x4d, + 0xdc, 0x2e, 0x98, 0xd8, 0x69, 0x63, 0xa7, 0x60, 0xd5, 0xcc, 0xeb, 0x0d, 0x5c, 0xe8, 0xbf, 0x55, + 0x68, 0xe3, 0x7a, 0xaf, 0x85, 0x1c, 0xf2, 0x3f, 0x75, 0x7d, 0xf6, 0x43, 0xf5, 0xc6, 0x8d, 0xeb, + 0xe1, 0x7f, 0x2a, 0xef, 0x9a, 0x71, 0x6a, 0xab, 0xfe, 0x3c, 0x7b, 0xf3, 0xaf, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x3f, 0x26, 0x7b, 0x3d, 0x80, 0x0d, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { diff --git a/modules/light-clients/06-solomachine/types/solomachine_test.go b/modules/light-clients/06-solomachine/types/solomachine_test.go index 56ebadee3d1..b286afc4ef7 100644 --- a/modules/light-clients/06-solomachine/types/solomachine_test.go +++ b/modules/light-clients/06-solomachine/types/solomachine_test.go @@ -12,10 +12,10 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) type SoloMachineTestSuite struct { diff --git a/modules/light-clients/06-solomachine/types/update.go b/modules/light-clients/06-solomachine/types/update.go index 3896d2dddec..a810548692d 100644 --- a/modules/light-clients/06-solomachine/types/update.go +++ b/modules/light-clients/06-solomachine/types/update.go @@ -5,8 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // CheckHeaderAndUpdateState checks if the provided header is valid and updates diff --git a/modules/light-clients/06-solomachine/types/update_test.go b/modules/light-clients/06-solomachine/types/update_test.go index ae3caa44a5c..459c72d0d76 100644 --- a/modules/light-clients/06-solomachine/types/update_test.go +++ b/modules/light-clients/06-solomachine/types/update_test.go @@ -4,10 +4,10 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *SoloMachineTestSuite) TestCheckHeaderAndUpdateState() { diff --git a/modules/light-clients/07-tendermint/module.go b/modules/light-clients/07-tendermint/module.go index 429105b4d33..05be0ea1217 100644 --- a/modules/light-clients/07-tendermint/module.go +++ b/modules/light-clients/07-tendermint/module.go @@ -1,7 +1,7 @@ package tendermint import ( - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) // Name returns the IBC client name diff --git a/modules/light-clients/07-tendermint/types/client_state.go b/modules/light-clients/07-tendermint/types/client_state.go index 51f826979fd..229fa53adb7 100644 --- a/modules/light-clients/07-tendermint/types/client_state.go +++ b/modules/light-clients/07-tendermint/types/client_state.go @@ -11,12 +11,12 @@ import ( "github.com/tendermint/tendermint/light" tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.ClientState = (*ClientState)(nil) diff --git a/modules/light-clients/07-tendermint/types/client_state_test.go b/modules/light-clients/07-tendermint/types/client_state_test.go index f45bd2fc6d6..cf596933b6f 100644 --- a/modules/light-clients/07-tendermint/types/client_state_test.go +++ b/modules/light-clients/07-tendermint/types/client_state_test.go @@ -5,14 +5,14 @@ import ( ics23 "github.com/confio/ics23/go" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" ) const ( diff --git a/modules/light-clients/07-tendermint/types/codec.go b/modules/light-clients/07-tendermint/types/codec.go index c363a0cbe65..28e68a2b7b4 100644 --- a/modules/light-clients/07-tendermint/types/codec.go +++ b/modules/light-clients/07-tendermint/types/codec.go @@ -3,7 +3,7 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // RegisterInterfaces registers the tendermint concrete client-related diff --git a/modules/light-clients/07-tendermint/types/consensus_state.go b/modules/light-clients/07-tendermint/types/consensus_state.go index aa475daa733..7f563285898 100644 --- a/modules/light-clients/07-tendermint/types/consensus_state.go +++ b/modules/light-clients/07-tendermint/types/consensus_state.go @@ -7,9 +7,9 @@ import ( tmbytes "github.com/tendermint/tendermint/libs/bytes" tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // SentinelRoot is used as a stand-in root value for the consensus state set at the upgrade height diff --git a/modules/light-clients/07-tendermint/types/consensus_state_test.go b/modules/light-clients/07-tendermint/types/consensus_state_test.go index 2d3be714799..86337eb5258 100644 --- a/modules/light-clients/07-tendermint/types/consensus_state_test.go +++ b/modules/light-clients/07-tendermint/types/consensus_state_test.go @@ -3,9 +3,9 @@ package types_test import ( "time" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) func (suite *TendermintTestSuite) TestConsensusStateValidateBasic() { diff --git a/modules/light-clients/07-tendermint/types/genesis.go b/modules/light-clients/07-tendermint/types/genesis.go index 82a996d3696..2a36e1653e4 100644 --- a/modules/light-clients/07-tendermint/types/genesis.go +++ b/modules/light-clients/07-tendermint/types/genesis.go @@ -3,8 +3,8 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // ExportMetadata exports all the consensus metadata in the client store so they can be included in clients genesis diff --git a/modules/light-clients/07-tendermint/types/genesis_test.go b/modules/light-clients/07-tendermint/types/genesis_test.go index 703cf5ce996..03fe79a935c 100644 --- a/modules/light-clients/07-tendermint/types/genesis_test.go +++ b/modules/light-clients/07-tendermint/types/genesis_test.go @@ -3,9 +3,9 @@ package types_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) // expected export ordering: diff --git a/modules/light-clients/07-tendermint/types/header.go b/modules/light-clients/07-tendermint/types/header.go index 58e7d671e4a..e3a420680b9 100644 --- a/modules/light-clients/07-tendermint/types/header.go +++ b/modules/light-clients/07-tendermint/types/header.go @@ -7,9 +7,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.Header = &Header{} diff --git a/modules/light-clients/07-tendermint/types/header_test.go b/modules/light-clients/07-tendermint/types/header_test.go index 8383a1a0be3..128882f8393 100644 --- a/modules/light-clients/07-tendermint/types/header_test.go +++ b/modules/light-clients/07-tendermint/types/header_test.go @@ -5,9 +5,9 @@ import ( tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) func (suite *TendermintTestSuite) TestGetHeight() { diff --git a/modules/light-clients/07-tendermint/types/misbehaviour.go b/modules/light-clients/07-tendermint/types/misbehaviour.go index 28ea7aa3666..f4355cf21f6 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour.go +++ b/modules/light-clients/07-tendermint/types/misbehaviour.go @@ -7,9 +7,9 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.Misbehaviour = &Misbehaviour{} diff --git a/modules/light-clients/07-tendermint/types/misbehaviour_handle.go b/modules/light-clients/07-tendermint/types/misbehaviour_handle.go index 67f4fccdd98..0f8a8f9c76b 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour_handle.go +++ b/modules/light-clients/07-tendermint/types/misbehaviour_handle.go @@ -9,8 +9,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // CheckMisbehaviourAndUpdateState determines whether or not two conflicting diff --git a/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go b/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go index 483e097435f..92711275887 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go +++ b/modules/light-clients/07-tendermint/types/misbehaviour_handle_test.go @@ -7,11 +7,11 @@ import ( "github.com/tendermint/tendermint/crypto/tmhash" tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctestingmock "github.com/cosmos/ibc-go/v3/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctestingmock "github.com/cosmos/ibc-go/v4/testing/mock" ) func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() { diff --git a/modules/light-clients/07-tendermint/types/misbehaviour_test.go b/modules/light-clients/07-tendermint/types/misbehaviour_test.go index 0ad5db5a7a5..5b67212be5e 100644 --- a/modules/light-clients/07-tendermint/types/misbehaviour_test.go +++ b/modules/light-clients/07-tendermint/types/misbehaviour_test.go @@ -7,11 +7,11 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibctestingmock "github.com/cosmos/ibc-go/v3/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibctestingmock "github.com/cosmos/ibc-go/v4/testing/mock" ) func (suite *TendermintTestSuite) TestMisbehaviour() { diff --git a/modules/light-clients/07-tendermint/types/proposal_handle.go b/modules/light-clients/07-tendermint/types/proposal_handle.go index 88951205c22..b1ba592453e 100644 --- a/modules/light-clients/07-tendermint/types/proposal_handle.go +++ b/modules/light-clients/07-tendermint/types/proposal_handle.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // CheckSubstituteAndUpdateState will try to update the client with the state of the diff --git a/modules/light-clients/07-tendermint/types/proposal_handle_test.go b/modules/light-clients/07-tendermint/types/proposal_handle_test.go index 0c3e9f054ef..459f38187ea 100644 --- a/modules/light-clients/07-tendermint/types/proposal_handle_test.go +++ b/modules/light-clients/07-tendermint/types/proposal_handle_test.go @@ -3,10 +3,10 @@ package types_test import ( "time" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var frozenHeight = clienttypes.NewHeight(0, 1) @@ -70,40 +70,40 @@ func (suite *TendermintTestSuite) TestCheckSubstituteUpdateStateBasic() { // this is to prevent headers from failing when attempting to update later. func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { testCases := []struct { - name string - FreezeClient bool - ExpireClient bool - expPass bool + name string + FreezeClient bool + ExpireClient bool + expPass bool }{ { - name: "PASS: update checks are deprecated, client is frozen and expired", - FreezeClient: true, - ExpireClient: true, - expPass: true, + name: "PASS: update checks are deprecated, client is frozen and expired", + FreezeClient: true, + ExpireClient: true, + expPass: true, }, { - name: "PASS: update checks are deprecated, not frozen or expired", - FreezeClient: false, - ExpireClient: false, - expPass: true, + name: "PASS: update checks are deprecated, not frozen or expired", + FreezeClient: false, + ExpireClient: false, + expPass: true, }, { - name: "PASS: update checks are deprecated, not frozen or expired", - FreezeClient: false, - ExpireClient: false, - expPass: true, + name: "PASS: update checks are deprecated, not frozen or expired", + FreezeClient: false, + ExpireClient: false, + expPass: true, }, { - name: "PASS: update checks are deprecated, client is frozen", - FreezeClient: true, - ExpireClient: false, - expPass: true, + name: "PASS: update checks are deprecated, client is frozen", + FreezeClient: true, + ExpireClient: false, + expPass: true, }, { - name: "PASS: update checks are deprecated, client is expired", - FreezeClient: false, - ExpireClient: true, - expPass: true, + name: "PASS: update checks are deprecated, client is expired", + FreezeClient: false, + ExpireClient: true, + expPass: true, }, } diff --git a/modules/light-clients/07-tendermint/types/store.go b/modules/light-clients/07-tendermint/types/store.go index 5cf7f5d8657..1c1157f65de 100644 --- a/modules/light-clients/07-tendermint/types/store.go +++ b/modules/light-clients/07-tendermint/types/store.go @@ -10,9 +10,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) /* diff --git a/modules/light-clients/07-tendermint/types/store_test.go b/modules/light-clients/07-tendermint/types/store_test.go index 22a8d069794..af003ba442d 100644 --- a/modules/light-clients/07-tendermint/types/store_test.go +++ b/modules/light-clients/07-tendermint/types/store_test.go @@ -4,13 +4,13 @@ import ( "math" "time" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - solomachinetypes "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + solomachinetypes "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func (suite *TendermintTestSuite) TestGetConsensusState() { diff --git a/modules/light-clients/07-tendermint/types/tendermint.pb.go b/modules/light-clients/07-tendermint/types/tendermint.pb.go index bcb71558313..3c34c10a9ad 100644 --- a/modules/light-clients/07-tendermint/types/tendermint.pb.go +++ b/modules/light-clients/07-tendermint/types/tendermint.pb.go @@ -6,8 +6,8 @@ package types import ( fmt "fmt" _go "github.com/confio/ics23/go" - types "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - types1 "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" + types "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + types1 "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" @@ -322,75 +322,75 @@ func init() { } var fileDescriptor_c6d6cf2b288949be = []byte{ - // 1080 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcf, 0x6f, 0xe3, 0x44, - 0x14, 0x6e, 0xda, 0xb2, 0x4d, 0x26, 0xe9, 0x76, 0x31, 0xa5, 0x9b, 0x96, 0x6e, 0x1c, 0x19, 0xa9, - 0xe4, 0x40, 0x6d, 0x92, 0x22, 0x21, 0x55, 0x5c, 0x70, 0x77, 0x51, 0x8b, 0x58, 0xa9, 0x72, 0xf9, - 0x21, 0x21, 0x21, 0x33, 0xb1, 0x27, 0xc9, 0x68, 0x6d, 0x8f, 0xe5, 0x99, 0x84, 0x96, 0xbf, 0x00, - 0x0e, 0x48, 0x7b, 0x44, 0x9c, 0x38, 0xf0, 0xc7, 0xec, 0xb1, 0x47, 0x4e, 0x06, 0xb5, 0x57, 0x4e, - 0x39, 0x72, 0x42, 0xf3, 0xc3, 0xf6, 0x34, 0xdb, 0xa5, 0x5a, 0x2e, 0xd1, 0xbc, 0xf7, 0xbe, 0xf7, - 0x7d, 0x99, 0x37, 0x6f, 0xde, 0x18, 0x38, 0x78, 0x18, 0x38, 0x11, 0x1e, 0x4f, 0x58, 0x10, 0x61, - 0x94, 0x30, 0xea, 0x30, 0x94, 0x84, 0x28, 0x8b, 0x71, 0xc2, 0x9c, 0x59, 0x5f, 0xb3, 0xec, 0x34, - 0x23, 0x8c, 0x18, 0x1d, 0x3c, 0x0c, 0x6c, 0x3d, 0xc1, 0xd6, 0x20, 0xb3, 0xfe, 0x4e, 0x57, 0xcb, - 0x67, 0x17, 0x29, 0xa2, 0xce, 0x0c, 0x46, 0x38, 0x84, 0x8c, 0x64, 0x92, 0x61, 0x67, 0xf7, 0x25, - 0x84, 0xf8, 0x55, 0xd1, 0x56, 0x9a, 0x11, 0x32, 0x2a, 0xac, 0xce, 0x98, 0x90, 0x71, 0x84, 0x1c, - 0x61, 0x0d, 0xa7, 0x23, 0x27, 0x9c, 0x66, 0x90, 0x61, 0x92, 0xa8, 0xb8, 0xb9, 0x18, 0x67, 0x38, - 0x46, 0x94, 0xc1, 0x38, 0x2d, 0x00, 0x7c, 0x7f, 0x01, 0xc9, 0x90, 0x23, 0xff, 0x2e, 0xdf, 0x93, - 0x5c, 0x29, 0xc0, 0x7b, 0x15, 0x80, 0xc4, 0x31, 0x66, 0x71, 0x01, 0x2a, 0x2d, 0x05, 0xdc, 0x1c, - 0x93, 0x31, 0x11, 0x4b, 0x87, 0xaf, 0xa4, 0xd7, 0xfa, 0x7b, 0x0d, 0x34, 0x8f, 0x04, 0xdf, 0x19, - 0x83, 0x0c, 0x19, 0xdb, 0xa0, 0x1e, 0x4c, 0x20, 0x4e, 0x7c, 0x1c, 0xb6, 0x6b, 0xdd, 0x5a, 0xaf, - 0xe1, 0xad, 0x09, 0xfb, 0x24, 0x34, 0x10, 0x68, 0xb2, 0x6c, 0x4a, 0x99, 0x1f, 0xa1, 0x19, 0x8a, - 0xda, 0xcb, 0xdd, 0x5a, 0xaf, 0x39, 0xe8, 0xd9, 0xff, 0x5d, 0x4f, 0xfb, 0xd3, 0x0c, 0x06, 0x7c, - 0xc3, 0xee, 0xce, 0x8b, 0xdc, 0x5c, 0x9a, 0xe7, 0xa6, 0x71, 0x01, 0xe3, 0xe8, 0xd0, 0xd2, 0xa8, - 0x2c, 0x0f, 0x08, 0xeb, 0x73, 0x6e, 0x18, 0x23, 0xb0, 0x21, 0x2c, 0x9c, 0x8c, 0xfd, 0x14, 0x65, - 0x98, 0x84, 0xed, 0x15, 0x21, 0xb5, 0x6d, 0xcb, 0x62, 0xd9, 0x45, 0xb1, 0xec, 0xc7, 0xaa, 0x98, - 0xae, 0xa5, 0xb8, 0xb7, 0x34, 0xee, 0x2a, 0xdf, 0xfa, 0xe5, 0x4f, 0xb3, 0xe6, 0xdd, 0x2f, 0xbc, - 0xa7, 0xc2, 0x69, 0x60, 0xf0, 0x60, 0x9a, 0x0c, 0x49, 0x12, 0x6a, 0x42, 0xab, 0x77, 0x09, 0xbd, - 0xab, 0x84, 0x1e, 0x4a, 0xa1, 0x45, 0x02, 0xa9, 0xb4, 0x51, 0xba, 0x95, 0x14, 0x02, 0x1b, 0x31, - 0x3c, 0xf7, 0x83, 0x88, 0x04, 0xcf, 0xfc, 0x30, 0xc3, 0x23, 0xd6, 0x7e, 0xe3, 0x35, 0xb7, 0xb4, - 0x90, 0x2f, 0x85, 0xd6, 0x63, 0x78, 0x7e, 0xc4, 0x9d, 0x8f, 0xb9, 0xcf, 0xf8, 0x16, 0xac, 0x8f, - 0x32, 0xf2, 0x03, 0x4a, 0xfc, 0x09, 0xe2, 0x07, 0xd2, 0xbe, 0x27, 0x44, 0x76, 0xc4, 0x11, 0xf1, - 0x16, 0xb1, 0x55, 0xe7, 0xcc, 0xfa, 0xf6, 0xb1, 0x40, 0xb8, 0xbb, 0x4a, 0x65, 0x53, 0xaa, 0xdc, - 0x48, 0xb7, 0xbc, 0x96, 0xb4, 0x25, 0x96, 0xd3, 0x47, 0x90, 0x21, 0xca, 0x0a, 0xfa, 0xb5, 0xd7, - 0xa5, 0xbf, 0x91, 0x6e, 0x79, 0x2d, 0x69, 0x2b, 0xfa, 0x13, 0xd0, 0x14, 0x57, 0xc7, 0xa7, 0x29, - 0x0a, 0x68, 0xbb, 0xde, 0x5d, 0xe9, 0x35, 0x07, 0x0f, 0x6c, 0x1c, 0xd0, 0xc1, 0x81, 0x7d, 0xca, - 0x23, 0x67, 0x29, 0x0a, 0xdc, 0xad, 0xaa, 0x85, 0x34, 0xb8, 0xe5, 0x81, 0xb4, 0x80, 0x50, 0xe3, - 0x10, 0xb4, 0xa6, 0xe9, 0x38, 0x83, 0x21, 0xf2, 0x53, 0xc8, 0x26, 0xed, 0x46, 0x77, 0xa5, 0xd7, - 0x70, 0x1f, 0xce, 0x73, 0xf3, 0x2d, 0x75, 0x6e, 0x5a, 0xd4, 0xf2, 0x9a, 0xca, 0x3c, 0x85, 0x6c, - 0x62, 0x40, 0xb0, 0x0d, 0xa3, 0x88, 0x7c, 0xef, 0x4f, 0xd3, 0x10, 0x32, 0xe4, 0xc3, 0x11, 0x43, - 0x99, 0x8f, 0xce, 0x53, 0x9c, 0x5d, 0xb4, 0x41, 0xb7, 0xd6, 0xab, 0xbb, 0x7b, 0xf3, 0xdc, 0xec, - 0x4a, 0xa2, 0x57, 0x42, 0xad, 0x76, 0xcd, 0xdb, 0x12, 0xd1, 0x2f, 0x45, 0xf0, 0x13, 0x1e, 0x7b, - 0x22, 0x42, 0x06, 0x05, 0xe6, 0x2d, 0x79, 0x31, 0xa6, 0x43, 0x34, 0x81, 0x33, 0x4c, 0xa6, 0x59, - 0xbb, 0x29, 0x84, 0xde, 0x9f, 0xe7, 0xe6, 0xde, 0x2b, 0x85, 0xf4, 0x04, 0x2e, 0xb7, 0xbb, 0x28, - 0xf7, 0x54, 0x03, 0x1c, 0xae, 0xfe, 0xf8, 0x9b, 0xb9, 0x64, 0xfd, 0xbe, 0x0c, 0xee, 0x1f, 0x91, - 0x84, 0xa2, 0x84, 0x4e, 0xa9, 0xbc, 0xf1, 0x2e, 0x68, 0x94, 0x43, 0x47, 0x5c, 0x79, 0x7e, 0xa4, - 0x8b, 0x6d, 0xf9, 0x45, 0x81, 0x70, 0xeb, 0xfc, 0x48, 0x9f, 0xf3, 0xee, 0xab, 0xd2, 0x8c, 0x8f, - 0xc1, 0x6a, 0x46, 0x08, 0x53, 0x33, 0xc1, 0xd2, 0x3a, 0xa2, 0x9a, 0x42, 0xb3, 0xbe, 0xfd, 0x14, - 0x65, 0xcf, 0x22, 0xe4, 0x11, 0xc2, 0xdc, 0x55, 0x4e, 0xe3, 0x89, 0x2c, 0xe3, 0xa7, 0x1a, 0xd8, - 0x4c, 0xd0, 0x39, 0xf3, 0xcb, 0x49, 0x4b, 0xfd, 0x09, 0xa4, 0x13, 0x71, 0xef, 0x5b, 0xee, 0xd7, - 0xf3, 0xdc, 0x7c, 0x47, 0x56, 0xe1, 0x36, 0x94, 0xf5, 0x4f, 0x6e, 0x7e, 0x38, 0xc6, 0x6c, 0x32, - 0x1d, 0x72, 0x39, 0x7d, 0xfe, 0x6b, 0xcb, 0x08, 0x0f, 0xa9, 0x33, 0xbc, 0x60, 0x88, 0xda, 0xc7, - 0xe8, 0xdc, 0xe5, 0x0b, 0xcf, 0xe0, 0x74, 0x5f, 0x95, 0x6c, 0xc7, 0x90, 0x4e, 0x54, 0x99, 0x7e, - 0x5e, 0x06, 0x2d, 0xbd, 0x7a, 0x46, 0x1f, 0x34, 0x64, 0x73, 0x97, 0x73, 0xd1, 0xdd, 0x9c, 0xe7, - 0xe6, 0x03, 0xf9, 0xb7, 0xca, 0x90, 0xe5, 0xd5, 0xe5, 0xfa, 0x24, 0x34, 0x20, 0xa8, 0x4f, 0x10, - 0x0c, 0x51, 0xe6, 0xf7, 0x55, 0x5d, 0xf6, 0xee, 0x9a, 0x95, 0xc7, 0x02, 0xef, 0x76, 0xae, 0x72, - 0x73, 0x4d, 0xae, 0xfb, 0xf3, 0xdc, 0xdc, 0x90, 0x22, 0x05, 0x99, 0xe5, 0xad, 0xc9, 0x65, 0x5f, - 0x93, 0x18, 0xa8, 0x19, 0xf9, 0x3f, 0x24, 0x06, 0x2f, 0x49, 0x0c, 0x4a, 0x89, 0x81, 0xaa, 0xc7, - 0xaf, 0x2b, 0xe0, 0x9e, 0x44, 0x1b, 0x10, 0xac, 0x53, 0x3c, 0x4e, 0x50, 0xe8, 0x4b, 0x88, 0x6a, - 0x99, 0x8e, 0xae, 0x23, 0xdf, 0xc3, 0x33, 0x01, 0x53, 0x82, 0xbb, 0x97, 0xb9, 0x59, 0xab, 0x26, - 0xc1, 0x0d, 0x0a, 0xcb, 0x6b, 0x51, 0x0d, 0xcb, 0x07, 0x4d, 0x79, 0xc6, 0x3e, 0x45, 0x45, 0x5b, - 0xdd, 0x22, 0x51, 0x1e, 0xde, 0x19, 0x62, 0x6e, 0xbb, 0xa2, 0xbf, 0x91, 0x6e, 0x79, 0xad, 0x99, - 0x86, 0x33, 0xbe, 0x03, 0xf2, 0x29, 0x10, 0xfa, 0x62, 0x90, 0xad, 0xdc, 0x39, 0xc8, 0x1e, 0xa9, - 0x41, 0xf6, 0xb6, 0xf6, 0xc0, 0x94, 0xf9, 0x96, 0xb7, 0xae, 0x1c, 0x6a, 0x94, 0x45, 0xc0, 0x28, - 0x10, 0x55, 0xb3, 0xaa, 0xc7, 0xe5, 0xae, 0x5d, 0x3c, 0x9a, 0xe7, 0xe6, 0xf6, 0x4d, 0x95, 0x8a, - 0xc3, 0xf2, 0xde, 0x54, 0xce, 0xaa, 0x6d, 0xad, 0xcf, 0x40, 0xbd, 0x78, 0x64, 0x8d, 0x5d, 0xd0, - 0x48, 0xa6, 0x31, 0xca, 0x78, 0x44, 0x9c, 0xcc, 0xaa, 0x57, 0x39, 0x8c, 0x2e, 0x68, 0x86, 0x28, - 0x21, 0x31, 0x4e, 0x44, 0x7c, 0x59, 0xc4, 0x75, 0x97, 0xeb, 0xbf, 0xb8, 0xea, 0xd4, 0x2e, 0xaf, - 0x3a, 0xb5, 0xbf, 0xae, 0x3a, 0xb5, 0xe7, 0xd7, 0x9d, 0xa5, 0xcb, 0xeb, 0xce, 0xd2, 0x1f, 0xd7, - 0x9d, 0xa5, 0x6f, 0x9e, 0x68, 0x57, 0x2c, 0x20, 0x34, 0x26, 0x94, 0x7f, 0x7a, 0xed, 0x8f, 0x89, - 0x33, 0x3b, 0x70, 0x62, 0x12, 0x4e, 0x23, 0x44, 0xe5, 0x87, 0xd8, 0x7e, 0xf1, 0x25, 0xf6, 0xc1, - 0x47, 0xfb, 0x8b, 0x9f, 0x4a, 0xc3, 0x7b, 0x62, 0xa4, 0x1c, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, - 0x31, 0x4f, 0x07, 0x47, 0xb8, 0x09, 0x00, 0x00, + // 1082 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcf, 0x6f, 0xe3, 0xc4, + 0x17, 0x6f, 0xda, 0x7e, 0xb7, 0xc9, 0x24, 0xdd, 0xf6, 0x6b, 0x4a, 0x37, 0x2d, 0xdd, 0x38, 0x32, + 0x52, 0xc9, 0x81, 0xda, 0x24, 0xbb, 0x12, 0x52, 0xc5, 0x05, 0x77, 0x17, 0xb5, 0x88, 0x95, 0x2a, + 0x97, 0x1f, 0x12, 0x12, 0x32, 0x13, 0x7b, 0x92, 0x8c, 0xd6, 0xf6, 0x58, 0x9e, 0x49, 0x68, 0xf9, + 0x0b, 0xe0, 0x80, 0xb4, 0x47, 0xc4, 0x89, 0x03, 0x7f, 0xcc, 0x1e, 0x7b, 0xe4, 0x64, 0x50, 0x7b, + 0xe5, 0x94, 0x23, 0x27, 0x34, 0x3f, 0x6c, 0x4f, 0xb3, 0x5d, 0xaa, 0xe5, 0x12, 0xcd, 0x7b, 0xef, + 0xf3, 0x3e, 0x9f, 0xcc, 0x9b, 0x37, 0x6f, 0x0c, 0x1c, 0x3c, 0x0c, 0x9c, 0x08, 0x8f, 0x27, 0x2c, + 0x88, 0x30, 0x4a, 0x18, 0x75, 0x18, 0x4a, 0x42, 0x94, 0xc5, 0x38, 0x61, 0xce, 0xac, 0xaf, 0x59, + 0x76, 0x9a, 0x11, 0x46, 0x8c, 0x0e, 0x1e, 0x06, 0xb6, 0x9e, 0x60, 0x6b, 0x90, 0x59, 0x7f, 0xb7, + 0xab, 0xe5, 0xb3, 0x8b, 0x14, 0x51, 0x67, 0x06, 0x23, 0x1c, 0x42, 0x46, 0x32, 0xc9, 0xb0, 0xbb, + 0xf7, 0x0a, 0x42, 0xfc, 0xaa, 0x68, 0x2b, 0xcd, 0x08, 0x19, 0x15, 0x56, 0x67, 0x4c, 0xc8, 0x38, + 0x42, 0x8e, 0xb0, 0x86, 0xd3, 0x91, 0x13, 0x4e, 0x33, 0xc8, 0x30, 0x49, 0x54, 0xdc, 0x5c, 0x8c, + 0x33, 0x1c, 0x23, 0xca, 0x60, 0x9c, 0x16, 0x00, 0xbe, 0xbf, 0x80, 0x64, 0xc8, 0x91, 0x7f, 0x97, + 0xef, 0x49, 0xae, 0x14, 0xe0, 0xbd, 0x0a, 0x40, 0xe2, 0x18, 0xb3, 0xb8, 0x00, 0x95, 0x96, 0x02, + 0x6e, 0x8d, 0xc9, 0x98, 0x88, 0xa5, 0xc3, 0x57, 0xd2, 0x6b, 0xfd, 0xb5, 0x06, 0x9a, 0x47, 0x82, + 0xef, 0x8c, 0x41, 0x86, 0x8c, 0x1d, 0x50, 0x0f, 0x26, 0x10, 0x27, 0x3e, 0x0e, 0xdb, 0xb5, 0x6e, + 0xad, 0xd7, 0xf0, 0xd6, 0x84, 0x7d, 0x12, 0x1a, 0x08, 0x34, 0x59, 0x36, 0xa5, 0xcc, 0x8f, 0xd0, + 0x0c, 0x45, 0xed, 0xe5, 0x6e, 0xad, 0xd7, 0x1c, 0xf4, 0xec, 0x7f, 0xaf, 0xa7, 0xfd, 0x49, 0x06, + 0x03, 0xbe, 0x61, 0x77, 0xf7, 0x65, 0x6e, 0x2e, 0xcd, 0x73, 0xd3, 0xb8, 0x80, 0x71, 0x74, 0x68, + 0x69, 0x54, 0x96, 0x07, 0x84, 0xf5, 0x19, 0x37, 0x8c, 0x11, 0xd8, 0x10, 0x16, 0x4e, 0xc6, 0x7e, + 0x8a, 0x32, 0x4c, 0xc2, 0xf6, 0x8a, 0x90, 0xda, 0xb1, 0x65, 0xb1, 0xec, 0xa2, 0x58, 0xf6, 0x13, + 0x55, 0x4c, 0xd7, 0x52, 0xdc, 0xdb, 0x1a, 0x77, 0x95, 0x6f, 0xfd, 0xfc, 0x87, 0x59, 0xf3, 0xee, + 0x17, 0xde, 0x53, 0xe1, 0x34, 0x30, 0xd8, 0x9c, 0x26, 0x43, 0x92, 0x84, 0x9a, 0xd0, 0xea, 0x5d, + 0x42, 0xef, 0x2a, 0xa1, 0x07, 0x52, 0x68, 0x91, 0x40, 0x2a, 0x6d, 0x94, 0x6e, 0x25, 0x85, 0xc0, + 0x46, 0x0c, 0xcf, 0xfd, 0x20, 0x22, 0xc1, 0x73, 0x3f, 0xcc, 0xf0, 0x88, 0xb5, 0xff, 0xf7, 0x86, + 0x5b, 0x5a, 0xc8, 0x97, 0x42, 0xeb, 0x31, 0x3c, 0x3f, 0xe2, 0xce, 0x27, 0xdc, 0x67, 0x7c, 0x03, + 0xd6, 0x47, 0x19, 0xf9, 0x1e, 0x25, 0xfe, 0x04, 0xf1, 0x03, 0x69, 0xdf, 0x13, 0x22, 0xbb, 0xe2, + 0x88, 0x78, 0x8b, 0xd8, 0xaa, 0x73, 0x66, 0x7d, 0xfb, 0x58, 0x20, 0xdc, 0x3d, 0xa5, 0xb2, 0x25, + 0x55, 0x6e, 0xa4, 0x5b, 0x5e, 0x4b, 0xda, 0x12, 0xcb, 0xe9, 0x23, 0xc8, 0x10, 0x65, 0x05, 0xfd, + 0xda, 0x9b, 0xd2, 0xdf, 0x48, 0xb7, 0xbc, 0x96, 0xb4, 0x15, 0xfd, 0x09, 0x68, 0x8a, 0xab, 0xe3, + 0xd3, 0x14, 0x05, 0xb4, 0x5d, 0xef, 0xae, 0xf4, 0x9a, 0x83, 0x4d, 0x1b, 0x07, 0x74, 0xf0, 0xc8, + 0x3e, 0xe5, 0x91, 0xb3, 0x14, 0x05, 0xee, 0x76, 0xd5, 0x42, 0x1a, 0xdc, 0xf2, 0x40, 0x5a, 0x40, + 0xa8, 0x71, 0x08, 0x5a, 0xd3, 0x74, 0x9c, 0xc1, 0x10, 0xf9, 0x29, 0x64, 0x93, 0x76, 0xa3, 0xbb, + 0xd2, 0x6b, 0xb8, 0x0f, 0xe6, 0xb9, 0xf9, 0x96, 0x3a, 0x37, 0x2d, 0x6a, 0x79, 0x4d, 0x65, 0x9e, + 0x42, 0x36, 0x31, 0x20, 0xd8, 0x81, 0x51, 0x44, 0xbe, 0xf3, 0xa7, 0x69, 0x08, 0x19, 0xf2, 0xe1, + 0x88, 0xa1, 0xcc, 0x47, 0xe7, 0x29, 0xce, 0x2e, 0xda, 0xa0, 0x5b, 0xeb, 0xd5, 0xdd, 0xfd, 0x79, + 0x6e, 0x76, 0x25, 0xd1, 0x6b, 0xa1, 0x56, 0xbb, 0xe6, 0x6d, 0x8b, 0xe8, 0x17, 0x22, 0xf8, 0x31, + 0x8f, 0x3d, 0x15, 0x21, 0x83, 0x02, 0xf3, 0x96, 0xbc, 0x18, 0xd3, 0x21, 0x9a, 0xc0, 0x19, 0x26, + 0xd3, 0xac, 0xdd, 0x14, 0x42, 0xef, 0xcf, 0x73, 0x73, 0xff, 0xb5, 0x42, 0x7a, 0x02, 0x97, 0xdb, + 0x5b, 0x94, 0x7b, 0xa6, 0x01, 0x0e, 0x57, 0x7f, 0xf8, 0xd5, 0x5c, 0xb2, 0x7e, 0x5b, 0x06, 0xf7, + 0x8f, 0x48, 0x42, 0x51, 0x42, 0xa7, 0x54, 0xde, 0x78, 0x17, 0x34, 0xca, 0xa1, 0x23, 0xae, 0x3c, + 0x3f, 0xd2, 0xc5, 0xb6, 0xfc, 0xbc, 0x40, 0xb8, 0x75, 0x7e, 0xa4, 0x2f, 0x78, 0xf7, 0x55, 0x69, + 0xc6, 0x47, 0x60, 0x35, 0x23, 0x84, 0xa9, 0x99, 0x60, 0x69, 0x1d, 0x51, 0x4d, 0xa1, 0x59, 0xdf, + 0x7e, 0x86, 0xb2, 0xe7, 0x11, 0xf2, 0x08, 0x61, 0xee, 0x2a, 0xa7, 0xf1, 0x44, 0x96, 0xf1, 0x63, + 0x0d, 0x6c, 0x25, 0xe8, 0x9c, 0xf9, 0xe5, 0xa4, 0xa5, 0xfe, 0x04, 0xd2, 0x89, 0xb8, 0xf7, 0x2d, + 0xf7, 0xab, 0x79, 0x6e, 0xbe, 0x23, 0xab, 0x70, 0x1b, 0xca, 0xfa, 0x3b, 0x37, 0x1f, 0x8f, 0x31, + 0x9b, 0x4c, 0x87, 0x5c, 0x4e, 0x9f, 0xff, 0xda, 0x32, 0xc2, 0x43, 0xea, 0x0c, 0x2f, 0x18, 0xa2, + 0xf6, 0x31, 0x3a, 0x77, 0xf9, 0xc2, 0x33, 0x38, 0xdd, 0x97, 0x25, 0xdb, 0x31, 0xa4, 0x13, 0x55, + 0xa6, 0x9f, 0x96, 0x41, 0x4b, 0xaf, 0x9e, 0xd1, 0x07, 0x0d, 0xd9, 0xdc, 0xe5, 0x5c, 0x74, 0xb7, + 0xe6, 0xb9, 0xb9, 0x29, 0xff, 0x56, 0x19, 0xb2, 0xbc, 0xba, 0x5c, 0x9f, 0x84, 0x06, 0x04, 0xf5, + 0x09, 0x82, 0x21, 0xca, 0xfc, 0xbe, 0xaa, 0xcb, 0xfe, 0x5d, 0xb3, 0xf2, 0x58, 0xe0, 0xdd, 0xce, + 0x55, 0x6e, 0xae, 0xc9, 0x75, 0x7f, 0x9e, 0x9b, 0x1b, 0x52, 0xa4, 0x20, 0xb3, 0xbc, 0x35, 0xb9, + 0xec, 0x6b, 0x12, 0x03, 0x35, 0x23, 0xff, 0x83, 0xc4, 0xe0, 0x15, 0x89, 0x41, 0x29, 0x31, 0x50, + 0xf5, 0xf8, 0x65, 0x05, 0xdc, 0x93, 0x68, 0x03, 0x82, 0x75, 0x8a, 0xc7, 0x09, 0x0a, 0x7d, 0x09, + 0x51, 0x2d, 0xd3, 0xd1, 0x75, 0xe4, 0x7b, 0x78, 0x26, 0x60, 0x4a, 0x70, 0xef, 0x32, 0x37, 0x6b, + 0xd5, 0x24, 0xb8, 0x41, 0x61, 0x79, 0x2d, 0xaa, 0x61, 0xf9, 0xa0, 0x29, 0xcf, 0xd8, 0xa7, 0xa8, + 0x68, 0xab, 0x5b, 0x24, 0xca, 0xc3, 0x3b, 0x43, 0xcc, 0x6d, 0x57, 0xf4, 0x37, 0xd2, 0x2d, 0xaf, + 0x35, 0xd3, 0x70, 0xc6, 0xb7, 0x40, 0x3e, 0x05, 0x42, 0x5f, 0x0c, 0xb2, 0x95, 0x3b, 0x07, 0xd9, + 0x43, 0x35, 0xc8, 0xde, 0xd6, 0x1e, 0x98, 0x32, 0xdf, 0xf2, 0xd6, 0x95, 0x43, 0x8d, 0xb2, 0x08, + 0x18, 0x05, 0xa2, 0x6a, 0x56, 0xf5, 0xb8, 0xdc, 0xb5, 0x8b, 0x87, 0xf3, 0xdc, 0xdc, 0xb9, 0xa9, + 0x52, 0x71, 0x58, 0xde, 0xff, 0x95, 0xb3, 0x6a, 0x5b, 0xeb, 0x53, 0x50, 0x2f, 0x1e, 0x59, 0x63, + 0x0f, 0x34, 0x92, 0x69, 0x8c, 0x32, 0x1e, 0x11, 0x27, 0xb3, 0xea, 0x55, 0x0e, 0xa3, 0x0b, 0x9a, + 0x21, 0x4a, 0x48, 0x8c, 0x13, 0x11, 0x5f, 0x16, 0x71, 0xdd, 0xe5, 0xfa, 0x2f, 0xaf, 0x3a, 0xb5, + 0xcb, 0xab, 0x4e, 0xed, 0xcf, 0xab, 0x4e, 0xed, 0xc5, 0x75, 0x67, 0xe9, 0xf2, 0xba, 0xb3, 0xf4, + 0xfb, 0x75, 0x67, 0xe9, 0xeb, 0xa7, 0xda, 0x15, 0x0b, 0x08, 0x8d, 0x09, 0xe5, 0x9f, 0x5e, 0x07, + 0x63, 0xe2, 0xcc, 0x1e, 0x3b, 0x31, 0x09, 0xa7, 0x11, 0xa2, 0xf2, 0x43, 0xec, 0xa0, 0xf8, 0x12, + 0xfb, 0xe0, 0xc3, 0x83, 0xc5, 0x4f, 0xa5, 0xe1, 0x3d, 0x31, 0x52, 0x1e, 0xfd, 0x13, 0x00, 0x00, + 0xff, 0xff, 0x0b, 0x9f, 0x2c, 0x5c, 0xb8, 0x09, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { diff --git a/modules/light-clients/07-tendermint/types/tendermint_test.go b/modules/light-clients/07-tendermint/types/tendermint_test.go index 898a48efe72..f653f94fe48 100644 --- a/modules/light-clients/07-tendermint/types/tendermint_test.go +++ b/modules/light-clients/07-tendermint/types/tendermint_test.go @@ -11,11 +11,11 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibctestingmock "github.com/cosmos/ibc-go/v3/testing/mock" - "github.com/cosmos/ibc-go/v3/testing/simapp" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibctestingmock "github.com/cosmos/ibc-go/v4/testing/mock" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) const ( diff --git a/modules/light-clients/07-tendermint/types/update.go b/modules/light-clients/07-tendermint/types/update.go index c4d422ccb73..b75e9ddbf9e 100644 --- a/modules/light-clients/07-tendermint/types/update.go +++ b/modules/light-clients/07-tendermint/types/update.go @@ -11,9 +11,9 @@ import ( "github.com/tendermint/tendermint/light" tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // CheckHeaderAndUpdateState checks if the provided header is valid, and if valid it will: diff --git a/modules/light-clients/07-tendermint/types/update_test.go b/modules/light-clients/07-tendermint/types/update_test.go index 379ccba5e00..9dae5d56f7d 100644 --- a/modules/light-clients/07-tendermint/types/update_test.go +++ b/modules/light-clients/07-tendermint/types/update_test.go @@ -6,12 +6,12 @@ import ( tmtypes "github.com/tendermint/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - types "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - ibctestingmock "github.com/cosmos/ibc-go/v3/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + types "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + ibctestingmock "github.com/cosmos/ibc-go/v4/testing/mock" ) func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() { diff --git a/modules/light-clients/07-tendermint/types/upgrade.go b/modules/light-clients/07-tendermint/types/upgrade.go index 5e23c8d9036..b5b5ebe40f4 100644 --- a/modules/light-clients/07-tendermint/types/upgrade.go +++ b/modules/light-clients/07-tendermint/types/upgrade.go @@ -8,9 +8,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // VerifyUpgradeAndUpdateState checks if the upgraded client has been committed by the current client diff --git a/modules/light-clients/07-tendermint/types/upgrade_test.go b/modules/light-clients/07-tendermint/types/upgrade_test.go index 6ad81df3520..c5f1216e8b8 100644 --- a/modules/light-clients/07-tendermint/types/upgrade_test.go +++ b/modules/light-clients/07-tendermint/types/upgrade_test.go @@ -3,11 +3,11 @@ package types_test import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) var newChainId = "newChainId-1" diff --git a/modules/light-clients/09-localhost/module.go b/modules/light-clients/09-localhost/module.go index e8d9eff55cf..fd77e2e62b5 100644 --- a/modules/light-clients/09-localhost/module.go +++ b/modules/light-clients/09-localhost/module.go @@ -1,7 +1,7 @@ package localhost import ( - "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types" + "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types" ) // Name returns the IBC client name diff --git a/modules/light-clients/09-localhost/types/client_state.go b/modules/light-clients/09-localhost/types/client_state.go index 1670d4f1e6b..d75690bee7c 100644 --- a/modules/light-clients/09-localhost/types/client_state.go +++ b/modules/light-clients/09-localhost/types/client_state.go @@ -10,11 +10,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) var _ exported.ClientState = (*ClientState)(nil) diff --git a/modules/light-clients/09-localhost/types/client_state_test.go b/modules/light-clients/09-localhost/types/client_state_test.go index 04b57fcbbf0..75d827f3ae8 100644 --- a/modules/light-clients/09-localhost/types/client_state_test.go +++ b/modules/light-clients/09-localhost/types/client_state_test.go @@ -3,14 +3,14 @@ package types_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types" ) const ( diff --git a/modules/light-clients/09-localhost/types/codec.go b/modules/light-clients/09-localhost/types/codec.go index a1f48114bd4..96e414a95c4 100644 --- a/modules/light-clients/09-localhost/types/codec.go +++ b/modules/light-clients/09-localhost/types/codec.go @@ -3,7 +3,7 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // RegisterInterfaces register the ibc interfaces submodule implementations to protobuf diff --git a/modules/light-clients/09-localhost/types/localhost.pb.go b/modules/light-clients/09-localhost/types/localhost.pb.go index 60fecb51822..15ef33136e9 100644 --- a/modules/light-clients/09-localhost/types/localhost.pb.go +++ b/modules/light-clients/09-localhost/types/localhost.pb.go @@ -5,7 +5,7 @@ package types import ( fmt "fmt" - types "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + types "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -91,9 +91,9 @@ var fileDescriptor_acd9f5b22d41bf6d = []byte{ 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xb9, 0xa4, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x27, 0xe7, 0x17, 0xe7, 0xe6, 0x17, 0xeb, 0x67, 0x26, 0x25, 0xeb, - 0xa6, 0xe7, 0xeb, 0x97, 0x19, 0xeb, 0xe7, 0xe6, 0xa7, 0x94, 0xe6, 0xa4, 0x16, 0x43, 0x42, 0x4f, + 0xa6, 0xe7, 0xeb, 0x97, 0x99, 0xe8, 0xe7, 0xe6, 0xa7, 0x94, 0xe6, 0xa4, 0x16, 0x43, 0x42, 0x4f, 0x17, 0x16, 0x7c, 0x06, 0x96, 0xba, 0x88, 0x10, 0x2c, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, 0x62, 0x03, - 0xfb, 0xd2, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0xd1, 0xbf, 0x6a, 0xbf, 0x6c, 0x01, 0x00, 0x00, + 0xfb, 0xd2, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x84, 0xfe, 0x1f, 0x95, 0x6c, 0x01, 0x00, 0x00, } func (m *ClientState) Marshal() (dAtA []byte, err error) { diff --git a/modules/light-clients/09-localhost/types/localhost_test.go b/modules/light-clients/09-localhost/types/localhost_test.go index cb80d5ba424..56bf9379fbe 100644 --- a/modules/light-clients/09-localhost/types/localhost_test.go +++ b/modules/light-clients/09-localhost/types/localhost_test.go @@ -8,9 +8,9 @@ import ( "github.com/stretchr/testify/suite" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/testing/simapp" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) const ( diff --git a/proto/ibc/applications/fee/v1/ack.proto b/proto/ibc/applications/fee/v1/ack.proto index 88b4d9fdd2c..b6c20acf74e 100644 --- a/proto/ibc/applications/fee/v1/ack.proto +++ b/proto/ibc/applications/fee/v1/ack.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.fee.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/fee/v1/fee.proto b/proto/ibc/applications/fee/v1/fee.proto index e7a1fa438df..d85ebcfeb31 100644 --- a/proto/ibc/applications/fee/v1/fee.proto +++ b/proto/ibc/applications/fee/v1/fee.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.fee.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types"; import "cosmos/base/v1beta1/coin.proto"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/fee/v1/genesis.proto b/proto/ibc/applications/fee/v1/genesis.proto index 601f32ca5d0..9bce6ac599b 100644 --- a/proto/ibc/applications/fee/v1/genesis.proto +++ b/proto/ibc/applications/fee/v1/genesis.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.fee.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types"; import "gogoproto/gogo.proto"; import "ibc/applications/fee/v1/fee.proto"; diff --git a/proto/ibc/applications/fee/v1/metadata.proto b/proto/ibc/applications/fee/v1/metadata.proto index 0afb3e09b2e..e1ec1b12bfd 100644 --- a/proto/ibc/applications/fee/v1/metadata.proto +++ b/proto/ibc/applications/fee/v1/metadata.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.fee.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/fee/v1/query.proto b/proto/ibc/applications/fee/v1/query.proto index ffa447ffd68..41b8c6ba5b6 100644 --- a/proto/ibc/applications/fee/v1/query.proto +++ b/proto/ibc/applications/fee/v1/query.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.fee.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; diff --git a/proto/ibc/applications/fee/v1/tx.proto b/proto/ibc/applications/fee/v1/tx.proto index f876ea50483..8d6fca58fbb 100644 --- a/proto/ibc/applications/fee/v1/tx.proto +++ b/proto/ibc/applications/fee/v1/tx.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.fee.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types"; import "gogoproto/gogo.proto"; import "ibc/applications/fee/v1/fee.proto"; diff --git a/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto b/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto index 291f3e4fd90..c7abd9f3372 100644 --- a/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto +++ b/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.interchain_accounts.controller.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/interchain_accounts/controller/v1/query.proto b/proto/ibc/applications/interchain_accounts/controller/v1/query.proto index d3960e9d14c..6ccc0456731 100644 --- a/proto/ibc/applications/interchain_accounts/controller/v1/query.proto +++ b/proto/ibc/applications/interchain_accounts/controller/v1/query.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.interchain_accounts.controller.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types"; import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; import "google/api/annotations.proto"; diff --git a/proto/ibc/applications/interchain_accounts/host/v1/host.proto b/proto/ibc/applications/interchain_accounts/host/v1/host.proto index a9d951cef82..e73510e57f1 100644 --- a/proto/ibc/applications/interchain_accounts/host/v1/host.proto +++ b/proto/ibc/applications/interchain_accounts/host/v1/host.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.interchain_accounts.host.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/interchain_accounts/host/v1/query.proto b/proto/ibc/applications/interchain_accounts/host/v1/query.proto index 5512d7b4fa5..02d17d314a7 100644 --- a/proto/ibc/applications/interchain_accounts/host/v1/query.proto +++ b/proto/ibc/applications/interchain_accounts/host/v1/query.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.interchain_accounts.host.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types"; import "google/api/annotations.proto"; import "ibc/applications/interchain_accounts/host/v1/host.proto"; diff --git a/proto/ibc/applications/interchain_accounts/v1/account.proto b/proto/ibc/applications/interchain_accounts/v1/account.proto index 75d2fbd89ed..2748b935778 100644 --- a/proto/ibc/applications/interchain_accounts/v1/account.proto +++ b/proto/ibc/applications/interchain_accounts/v1/account.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.interchain_accounts.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/interchain_accounts/v1/genesis.proto b/proto/ibc/applications/interchain_accounts/v1/genesis.proto index 3902f890708..a92b6a0f17a 100644 --- a/proto/ibc/applications/interchain_accounts/v1/genesis.proto +++ b/proto/ibc/applications/interchain_accounts/v1/genesis.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.interchain_accounts.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types"; import "gogoproto/gogo.proto"; import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; diff --git a/proto/ibc/applications/interchain_accounts/v1/metadata.proto b/proto/ibc/applications/interchain_accounts/v1/metadata.proto index 3eab1d04a69..6a4b4abe57e 100644 --- a/proto/ibc/applications/interchain_accounts/v1/metadata.proto +++ b/proto/ibc/applications/interchain_accounts/v1/metadata.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.interchain_accounts.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/interchain_accounts/v1/packet.proto b/proto/ibc/applications/interchain_accounts/v1/packet.proto index 51ff4279aeb..8e09a9d670c 100644 --- a/proto/ibc/applications/interchain_accounts/v1/packet.proto +++ b/proto/ibc/applications/interchain_accounts/v1/packet.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.interchain_accounts.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types"; import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/transfer/v1/genesis.proto b/proto/ibc/applications/transfer/v1/genesis.proto index 0b5c0e0d122..34672fdebfb 100644 --- a/proto/ibc/applications/transfer/v1/genesis.proto +++ b/proto/ibc/applications/transfer/v1/genesis.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.transfer.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"; import "ibc/applications/transfer/v1/transfer.proto"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/transfer/v1/query.proto b/proto/ibc/applications/transfer/v1/query.proto index 5298338c10c..075c0001c8a 100644 --- a/proto/ibc/applications/transfer/v1/query.proto +++ b/proto/ibc/applications/transfer/v1/query.proto @@ -7,7 +7,7 @@ import "cosmos/base/query/v1beta1/pagination.proto"; import "ibc/applications/transfer/v1/transfer.proto"; import "google/api/annotations.proto"; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"; // Query provides defines the gRPC querier service. service Query { diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index 7a99485c589..1f92e81a627 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.transfer.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index 8f1392b0cf3..5befdf2fbc3 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.transfer.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"; import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto index 850320df340..acae83530f6 100644 --- a/proto/ibc/applications/transfer/v2/packet.proto +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.applications.transfer.v2; -option go_package = "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"; // FungibleTokenPacketData defines a struct for the packet payload // See FungibleTokenPacketData spec: diff --git a/proto/ibc/core/channel/v1/channel.proto b/proto/ibc/core/channel/v1/channel.proto index 177f2c85fd1..646884d5712 100644 --- a/proto/ibc/core/channel/v1/channel.proto +++ b/proto/ibc/core/channel/v1/channel.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.channel.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"; import "gogoproto/gogo.proto"; import "ibc/core/client/v1/client.proto"; diff --git a/proto/ibc/core/channel/v1/genesis.proto b/proto/ibc/core/channel/v1/genesis.proto index d95c891b6c8..1c0ff6ee883 100644 --- a/proto/ibc/core/channel/v1/genesis.proto +++ b/proto/ibc/core/channel/v1/genesis.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.channel.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"; import "gogoproto/gogo.proto"; import "ibc/core/channel/v1/channel.proto"; diff --git a/proto/ibc/core/channel/v1/query.proto b/proto/ibc/core/channel/v1/query.proto index ceb13d00091..986633173cc 100644 --- a/proto/ibc/core/channel/v1/query.proto +++ b/proto/ibc/core/channel/v1/query.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.channel.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"; import "ibc/core/client/v1/client.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; diff --git a/proto/ibc/core/channel/v1/tx.proto b/proto/ibc/core/channel/v1/tx.proto index d34b00e9124..5e3ccf32ff0 100644 --- a/proto/ibc/core/channel/v1/tx.proto +++ b/proto/ibc/core/channel/v1/tx.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.channel.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types"; import "gogoproto/gogo.proto"; import "ibc/core/client/v1/client.proto"; diff --git a/proto/ibc/core/client/v1/client.proto b/proto/ibc/core/client/v1/client.proto index 657d99ed204..9d386592fa9 100644 --- a/proto/ibc/core/client/v1/client.proto +++ b/proto/ibc/core/client/v1/client.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.client.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/02-client/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; diff --git a/proto/ibc/core/client/v1/genesis.proto b/proto/ibc/core/client/v1/genesis.proto index 0ca29d224b0..b2930c48418 100644 --- a/proto/ibc/core/client/v1/genesis.proto +++ b/proto/ibc/core/client/v1/genesis.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.client.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/02-client/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"; import "ibc/core/client/v1/client.proto"; import "gogoproto/gogo.proto"; diff --git a/proto/ibc/core/client/v1/query.proto b/proto/ibc/core/client/v1/query.proto index 33a4191cd06..2c9618bc801 100644 --- a/proto/ibc/core/client/v1/query.proto +++ b/proto/ibc/core/client/v1/query.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.client.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/02-client/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"; import "cosmos/base/query/v1beta1/pagination.proto"; import "ibc/core/client/v1/client.proto"; diff --git a/proto/ibc/core/client/v1/tx.proto b/proto/ibc/core/client/v1/tx.proto index 06dbfbd0dfe..11dfdadeaa6 100644 --- a/proto/ibc/core/client/v1/tx.proto +++ b/proto/ibc/core/client/v1/tx.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.client.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/02-client/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; diff --git a/proto/ibc/core/commitment/v1/commitment.proto b/proto/ibc/core/commitment/v1/commitment.proto index b0afed2273b..b6a68a99fb7 100644 --- a/proto/ibc/core/commitment/v1/commitment.proto +++ b/proto/ibc/core/commitment/v1/commitment.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.commitment.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types"; import "gogoproto/gogo.proto"; import "proofs.proto"; diff --git a/proto/ibc/core/connection/v1/connection.proto b/proto/ibc/core/connection/v1/connection.proto index 7fd2a6909ad..8360af98883 100644 --- a/proto/ibc/core/connection/v1/connection.proto +++ b/proto/ibc/core/connection/v1/connection.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.connection.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"; import "gogoproto/gogo.proto"; import "ibc/core/commitment/v1/commitment.proto"; diff --git a/proto/ibc/core/connection/v1/genesis.proto b/proto/ibc/core/connection/v1/genesis.proto index 1a53422c94a..f616ae67e0d 100644 --- a/proto/ibc/core/connection/v1/genesis.proto +++ b/proto/ibc/core/connection/v1/genesis.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.connection.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"; import "gogoproto/gogo.proto"; import "ibc/core/connection/v1/connection.proto"; diff --git a/proto/ibc/core/connection/v1/query.proto b/proto/ibc/core/connection/v1/query.proto index f28578f5fc5..129f30a71a8 100644 --- a/proto/ibc/core/connection/v1/query.proto +++ b/proto/ibc/core/connection/v1/query.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.connection.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"; import "gogoproto/gogo.proto"; import "cosmos/base/query/v1beta1/pagination.proto"; diff --git a/proto/ibc/core/connection/v1/tx.proto b/proto/ibc/core/connection/v1/tx.proto index e7e09c84cff..1ca0b404000 100644 --- a/proto/ibc/core/connection/v1/tx.proto +++ b/proto/ibc/core/connection/v1/tx.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.connection.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; diff --git a/proto/ibc/core/types/v1/genesis.proto b/proto/ibc/core/types/v1/genesis.proto index fbddbf3035f..4cc931d32f7 100644 --- a/proto/ibc/core/types/v1/genesis.proto +++ b/proto/ibc/core/types/v1/genesis.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.core.types.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/types"; import "gogoproto/gogo.proto"; import "ibc/core/client/v1/genesis.proto"; diff --git a/proto/ibc/lightclients/localhost/v1/localhost.proto b/proto/ibc/lightclients/localhost/v1/localhost.proto index 43056801542..9eda835ebb1 100644 --- a/proto/ibc/lightclients/localhost/v1/localhost.proto +++ b/proto/ibc/lightclients/localhost/v1/localhost.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.lightclients.localhost.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/light-clients/09-localhost/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/light-clients/09-localhost/types"; import "gogoproto/gogo.proto"; import "ibc/core/client/v1/client.proto"; diff --git a/proto/ibc/lightclients/solomachine/v1/solomachine.proto b/proto/ibc/lightclients/solomachine/v1/solomachine.proto index c279f5e728e..37bd81e923a 100644 --- a/proto/ibc/lightclients/solomachine/v1/solomachine.proto +++ b/proto/ibc/lightclients/solomachine/v1/solomachine.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.lightclients.solomachine.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/core/02-client/legacy/v100"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/core/02-client/legacy/v100"; import "ibc/core/connection/v1/connection.proto"; import "ibc/core/channel/v1/channel.proto"; diff --git a/proto/ibc/lightclients/solomachine/v2/solomachine.proto b/proto/ibc/lightclients/solomachine/v2/solomachine.proto index e626c18ac66..c735fddddf9 100644 --- a/proto/ibc/lightclients/solomachine/v2/solomachine.proto +++ b/proto/ibc/lightclients/solomachine/v2/solomachine.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.lightclients.solomachine.v2; -option go_package = "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types"; import "ibc/core/connection/v1/connection.proto"; import "ibc/core/channel/v1/channel.proto"; diff --git a/proto/ibc/lightclients/tendermint/v1/tendermint.proto b/proto/ibc/lightclients/tendermint/v1/tendermint.proto index 2815fe6ad2a..55a4e06906d 100644 --- a/proto/ibc/lightclients/tendermint/v1/tendermint.proto +++ b/proto/ibc/lightclients/tendermint/v1/tendermint.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package ibc.lightclients.tendermint.v1; -option go_package = "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types"; +option go_package = "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types"; import "tendermint/types/validator.proto"; import "tendermint/types/types.proto"; diff --git a/testing/README.md b/testing/README.md index ad02a80e640..c682ba9ed8e 100644 --- a/testing/README.md +++ b/testing/README.md @@ -255,8 +255,8 @@ import ( "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/simapp" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer/simapp" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func SetupTransferTestingApp() (ibctesting.TestingApp, map[string]json.RawMessage) { diff --git a/testing/app.go b/testing/app.go index 1cde8614b6d..9392c42424c 100644 --- a/testing/app.go +++ b/testing/app.go @@ -23,8 +23,8 @@ import ( tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/ibc-go/v3/modules/core/keeper" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) var DefaultTestingAppInit func() (TestingApp, map[string]json.RawMessage) = SetupTestingApp diff --git a/testing/chain.go b/testing/chain.go index 9e248312bc8..038d20c4c54 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -25,14 +25,14 @@ import ( tmtypes "github.com/tendermint/tendermint/types" tmversion "github.com/tendermint/tendermint/version" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/core/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v3/testing/mock" - "github.com/cosmos/ibc-go/v3/testing/simapp" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/testing/mock" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) var MaxAccounts = 10 diff --git a/testing/chain_test.go b/testing/chain_test.go index 64ddc6c751e..595609ce4ac 100644 --- a/testing/chain_test.go +++ b/testing/chain_test.go @@ -7,7 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) func TestChangeValSet(t *testing.T) { diff --git a/testing/config.go b/testing/config.go index a47dea1701b..b75ecc8d918 100644 --- a/testing/config.go +++ b/testing/config.go @@ -3,11 +3,11 @@ package ibctesting import ( "time" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v3/testing/mock" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/testing/mock" ) type ClientConfig interface { diff --git a/testing/endpoint.go b/testing/endpoint.go index 94fa14f8b0d..ce8895ebb51 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -6,13 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" ) // Endpoint is a which represents a channel endpoint and its associated diff --git a/testing/events.go b/testing/events.go index 8beaa0a2beb..18169d30818 100644 --- a/testing/events.go +++ b/testing/events.go @@ -6,9 +6,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // ParseClientIDFromEvents parses events emitted from a MsgCreateClient and returns the diff --git a/testing/mock/ibc_app.go b/testing/mock/ibc_app.go index 0504c2df0de..47f39deb5ce 100644 --- a/testing/mock/ibc_app.go +++ b/testing/mock/ibc_app.go @@ -5,8 +5,8 @@ import ( capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // MockIBCApp contains IBC application module callbacks as defined in 05-port. diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 69f3c388a8a..12d35564005 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -9,9 +9,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // IBCModule implements the ICS26 callbacks for testing/mock. diff --git a/testing/mock/ibc_module_test.go b/testing/mock/ibc_module_test.go index b36d58d2004..e790f6e39e7 100644 --- a/testing/mock/ibc_module_test.go +++ b/testing/mock/ibc_module_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v3/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v4/testing/mock" ) func TestCreateCapabilityName(t *testing.T) { diff --git a/testing/mock/mock.go b/testing/mock/mock.go index a4ac465353d..3ee9e1dec89 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -15,9 +15,9 @@ import ( "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" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" ) const ( diff --git a/testing/mock/privval_test.go b/testing/mock/privval_test.go index 452fa667824..8fbabd90729 100644 --- a/testing/mock/privval_test.go +++ b/testing/mock/privval_test.go @@ -7,7 +7,7 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/ibc-go/v3/testing/mock" + "github.com/cosmos/ibc-go/v4/testing/mock" ) const chainID = "testChain" diff --git a/testing/path.go b/testing/path.go index 731d3cd5e1b..bfec2c803f2 100644 --- a/testing/path.go +++ b/testing/path.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) // Path contains two endpoints representing two chains connected over IBC diff --git a/testing/sdk_test.go b/testing/sdk_test.go index 415c61eee11..a56dae3b73e 100644 --- a/testing/sdk_test.go +++ b/testing/sdk_test.go @@ -27,9 +27,9 @@ import ( tmrand "github.com/tendermint/tendermint/libs/rand" dbm "github.com/tendermint/tm-db" - ibcclientcli "github.com/cosmos/ibc-go/v3/modules/core/02-client/client/cli" - "github.com/cosmos/ibc-go/v3/testing/simapp" - "github.com/cosmos/ibc-go/v3/testing/simapp/params" + ibcclientcli "github.com/cosmos/ibc-go/v4/modules/core/02-client/client/cli" + "github.com/cosmos/ibc-go/v4/testing/simapp" + "github.com/cosmos/ibc-go/v4/testing/simapp/params" ) /* diff --git a/testing/simapp/ante_handler.go b/testing/simapp/ante_handler.go index 5d32e9199bb..5f8a6265399 100644 --- a/testing/simapp/ante_handler.go +++ b/testing/simapp/ante_handler.go @@ -5,8 +5,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v3/modules/core/ante" - "github.com/cosmos/ibc-go/v3/modules/core/keeper" + ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante" + "github.com/cosmos/ibc-go/v4/modules/core/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC keeper. diff --git a/testing/simapp/app.go b/testing/simapp/app.go index cb6c1cdccb3..744e8c96b01 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -43,8 +43,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/capability" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/ibc-go/v3/testing/mock" - simappparams "github.com/cosmos/ibc-go/v3/testing/simapp/params" "github.com/cosmos/cosmos-sdk/x/crisis" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" @@ -82,28 +80,29 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" - icacontroller "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller" - icacontrollerkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/keeper" - icacontrollertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - icahost "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host" - icahostkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" - icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - ibcfee "github.com/cosmos/ibc-go/v3/modules/apps/29-fee" - ibcfeekeeper "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/keeper" - ibcfeetypes "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" - transfer "github.com/cosmos/ibc-go/v3/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v3/modules/core" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/02-client" - ibcclientclient "github.com/cosmos/ibc-go/v3/modules/core/02-client/client" - ibcclienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" - ibcmock "github.com/cosmos/ibc-go/v3/testing/mock" + ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" + icacontroller "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller" + icacontrollerkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/keeper" + icacontrollertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + icahost "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" + icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibcfee "github.com/cosmos/ibc-go/v4/modules/apps/29-fee" + ibcfeekeeper "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/keeper" + ibcfeetypes "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + transfer "github.com/cosmos/ibc-go/v4/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v4/modules/core" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/02-client" + ibcclientclient "github.com/cosmos/ibc-go/v4/modules/core/02-client/client" + ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" + simappparams "github.com/cosmos/ibc-go/v4/testing/simapp/params" authz "github.com/cosmos/cosmos-sdk/x/authz" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" @@ -165,7 +164,7 @@ var ( ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, ibcfeetypes.ModuleName: nil, icatypes.ModuleName: nil, - mock.ModuleName: nil, + ibcmock.ModuleName: nil, } ) @@ -658,7 +657,7 @@ func (app *SimApp) ModuleAccountAddrs() map[string]bool { for acc := range maccPerms { // do not add mock module to blocked addresses // this is only used for testing - if acc == mock.ModuleName { + if acc == ibcmock.ModuleName { continue } diff --git a/testing/simapp/encoding.go b/testing/simapp/encoding.go index f308cadc23d..c13124c5c7b 100644 --- a/testing/simapp/encoding.go +++ b/testing/simapp/encoding.go @@ -3,7 +3,7 @@ package simapp import ( "github.com/cosmos/cosmos-sdk/std" - simappparams "github.com/cosmos/ibc-go/v3/testing/simapp/params" + simappparams "github.com/cosmos/ibc-go/v4/testing/simapp/params" ) // MakeTestEncodingConfig creates an EncodingConfig for testing. This function diff --git a/testing/simapp/genesis_account_test.go b/testing/simapp/genesis_account_test.go index 8a223148955..f4595c0fdf0 100644 --- a/testing/simapp/genesis_account_test.go +++ b/testing/simapp/genesis_account_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/ibc-go/v3/testing/simapp" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) func TestSimGenesisAccountValidate(t *testing.T) { diff --git a/testing/simapp/sim_bench_test.go b/testing/simapp/sim_bench_test.go index 6f8b020a043..26c2223c543 100644 --- a/testing/simapp/sim_bench_test.go +++ b/testing/simapp/sim_bench_test.go @@ -11,7 +11,7 @@ import ( ) // Profile with: -// /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/ibc-go/v3/testing/simapp -bench ^BenchmarkFullAppSimulation$ -Commit=true -cpuprofile cpu.out +// /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/ibc-go/v4/testing/simapp -bench ^BenchmarkFullAppSimulation$ -Commit=true -cpuprofile cpu.out func BenchmarkFullAppSimulation(b *testing.B) { b.ReportAllocs() config, db, dir, logger, _, err := SetupSimulation("goleveldb-app-sim", "Simulation") diff --git a/testing/simapp/sim_test.go b/testing/simapp/sim_test.go index 12c96755aca..7935213c9b3 100644 --- a/testing/simapp/sim_test.go +++ b/testing/simapp/sim_test.go @@ -29,9 +29,9 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/testing/simapp/helpers" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/testing/simapp/helpers" ) // Get flags every time the simulator is run diff --git a/testing/simapp/simd/cmd/cmd_test.go b/testing/simapp/simd/cmd/cmd_test.go index 446639c5bf0..5108d3c0a2e 100644 --- a/testing/simapp/simd/cmd/cmd_test.go +++ b/testing/simapp/simd/cmd/cmd_test.go @@ -8,8 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v3/testing/simapp" - "github.com/cosmos/ibc-go/v3/testing/simapp/simd/cmd" + "github.com/cosmos/ibc-go/v4/testing/simapp" + "github.com/cosmos/ibc-go/v4/testing/simapp/simd/cmd" ) func TestInitCmd(t *testing.T) { diff --git a/testing/simapp/simd/cmd/genaccounts_test.go b/testing/simapp/simd/cmd/genaccounts_test.go index c7c2f92682c..b22f956d4d2 100644 --- a/testing/simapp/simd/cmd/genaccounts_test.go +++ b/testing/simapp/simd/cmd/genaccounts_test.go @@ -16,8 +16,8 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/ibc-go/v3/testing/simapp" - simcmd "github.com/cosmos/ibc-go/v3/testing/simapp/simd/cmd" + "github.com/cosmos/ibc-go/v4/testing/simapp" + simcmd "github.com/cosmos/ibc-go/v4/testing/simapp/simd/cmd" ) var testMbm = module.NewBasicManager(genutil.AppModuleBasic{}) diff --git a/testing/simapp/simd/cmd/root.go b/testing/simapp/simd/cmd/root.go index e130cb16a32..219091ea09a 100644 --- a/testing/simapp/simd/cmd/root.go +++ b/testing/simapp/simd/cmd/root.go @@ -30,8 +30,8 @@ import ( "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/ibc-go/v3/testing/simapp" - "github.com/cosmos/ibc-go/v3/testing/simapp/params" + "github.com/cosmos/ibc-go/v4/testing/simapp" + "github.com/cosmos/ibc-go/v4/testing/simapp/params" ) // NewRootCmd creates a new root command for simd. It is called once in the diff --git a/testing/simapp/simd/main.go b/testing/simapp/simd/main.go index 79a7da2ac28..c6450c79f58 100644 --- a/testing/simapp/simd/main.go +++ b/testing/simapp/simd/main.go @@ -6,8 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/server" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - "github.com/cosmos/ibc-go/v3/testing/simapp" - "github.com/cosmos/ibc-go/v3/testing/simapp/simd/cmd" + "github.com/cosmos/ibc-go/v4/testing/simapp" + "github.com/cosmos/ibc-go/v4/testing/simapp/simd/cmd" ) func main() { diff --git a/testing/simapp/state.go b/testing/simapp/state.go index c0a9e2ea1ec..0b1830d7c4b 100644 --- a/testing/simapp/state.go +++ b/testing/simapp/state.go @@ -19,7 +19,7 @@ import ( tmjson "github.com/tendermint/tendermint/libs/json" tmtypes "github.com/tendermint/tendermint/types" - simappparams "github.com/cosmos/ibc-go/v3/testing/simapp/params" + simappparams "github.com/cosmos/ibc-go/v4/testing/simapp/params" ) // AppStateFn returns the initial application state using a genesis or the simulation parameters. diff --git a/testing/simapp/test_helpers.go b/testing/simapp/test_helpers.go index 8f76c8507ab..58e1ac2eb23 100644 --- a/testing/simapp/test_helpers.go +++ b/testing/simapp/test_helpers.go @@ -25,7 +25,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/ibc-go/v3/testing/simapp/helpers" + "github.com/cosmos/ibc-go/v4/testing/simapp/helpers" ) // DefaultConsensusParams defines the default Tendermint consensus params used in diff --git a/testing/simapp/utils.go b/testing/simapp/utils.go index 51788f5a322..668feb3f7f6 100644 --- a/testing/simapp/utils.go +++ b/testing/simapp/utils.go @@ -13,7 +13,7 @@ import ( "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/ibc-go/v3/testing/simapp/helpers" + "github.com/cosmos/ibc-go/v4/testing/simapp/helpers" ) // SetupSimulation creates the config, db (levelDB), temporary directory and logger for diff --git a/testing/solomachine.go b/testing/solomachine.go index 485fb75be0e..a97f63c3919 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -12,11 +12,11 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - solomachinetypes "github.com/cosmos/ibc-go/v3/modules/light-clients/06-solomachine/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + solomachinetypes "github.com/cosmos/ibc-go/v4/modules/light-clients/06-solomachine/types" ) // Solomachine is a testing helper used to simulate a counterparty diff --git a/testing/values.go b/testing/values.go index 655a4731a74..481db7915e8 100644 --- a/testing/values.go +++ b/testing/values.go @@ -9,12 +9,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v3/testing/mock" - "github.com/cosmos/ibc-go/v3/testing/simapp" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v4/testing/mock" + "github.com/cosmos/ibc-go/v4/testing/simapp" ) const ( From 7d971ecc79a347bd8ca278274c0d98ecadc94d64 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Fri, 1 Jul 2022 11:27:40 +0200 Subject: [PATCH 200/275] deps: bumping go version 1.18 (#1627) * bumping go version 1.18 * updating broken workflow setup --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 8 ++-- CHANGELOG.md | 1 + Dockerfile | 2 +- go.mod | 2 +- go.sum | 77 ----------------------------------- 6 files changed, 8 insertions(+), 84 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f59f0c63d25..cb453590607 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: - uses: actions/setup-go@v3 with: - go-version: '1.17' + go-version: '1.18' - name: Release uses: goreleaser/goreleaser-action@v3 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d6e00030df0..c915db779cd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,12 +20,12 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.18 - name: Display go version run: go version - name: install tparse run: | - export GO111MODULE="on" && go get github.com/mfridman/tparse@v0.8.3 + go install github.com/mfridman/tparse@v0.8.3 - uses: actions/cache@v3 with: path: ~/go/bin @@ -40,7 +40,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.18 - uses: technote-space/get-diff-action@v6.1.0 id: git_diff with: @@ -95,7 +95,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.18 - uses: technote-space/get-diff-action@v6.1.0 with: PATTERNS: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 900ef224f5f..4e7357459f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies * [\#1525](https://github.com/cosmos/ibc-go/pull/1525) Bump SDK version to v0.45.5 +* [\#1627](https://github.com/cosmos/ibc-go/pull/1627) Bump Go version to 1.18 ### API Breaking diff --git a/Dockerfile b/Dockerfile index eb044d5eaf9..a193f54906e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.17 as builder +FROM golang:1.18 as builder ENV GOPATH="" ENV GOMODULE="on" diff --git a/go.mod b/go.mod index 6bae0c1635d..1f3f2227636 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -go 1.17 +go 1.18 module github.com/cosmos/ibc-go/v4 diff --git a/go.sum b/go.sum index 508fcd0b421..2634352b610 100644 --- a/go.sum +++ b/go.sum @@ -29,18 +29,12 @@ cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+Y cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= @@ -328,7 +322,6 @@ github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= @@ -443,9 +436,7 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= @@ -479,12 +470,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= @@ -533,7 +520,6 @@ github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/S github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -566,7 +552,6 @@ github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM= github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87/go.mod h1:XGsKKeXxeRr95aEOgipvluMPlgjr7dGlk9ZTWOjcUcg= github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= @@ -590,7 +575,6 @@ github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1C github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.9.0 h1:npqHz788dryJiR/l6K/RUQAyh2SwV91+d1dnh4RjO9w= -github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= @@ -633,7 +617,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -738,7 +721,6 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -754,7 +736,6 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -787,11 +768,6 @@ github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= -github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -833,7 +809,6 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -883,7 +858,6 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= @@ -897,7 +871,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= -github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= @@ -1036,15 +1009,11 @@ go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= -go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1204,13 +1173,7 @@ golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1230,9 +1193,6 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1244,7 +1204,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1344,14 +1303,8 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1420,10 +1373,8 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1446,8 +1397,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1485,13 +1434,6 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1570,21 +1512,6 @@ google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I= google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1622,10 +1549,8 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -1639,7 +1564,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= @@ -1679,7 +1603,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= From ea64db7f670b259af7fba0d287285d4b96cc38fc Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 1 Jul 2022 11:57:30 +0200 Subject: [PATCH 201/275] add backport to v4.0.x and remove backports to v1 (EoL) (#1629) --- .github/mergify.yml | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/.github/mergify.yml b/.github/mergify.yml index 868594d1d57..6f6464653e1 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -18,30 +18,6 @@ pull_request_rules: commit_message_template: | {{ title }} (#{{ number }}) {{ body }} - - name: backport patches to v1.3.x branch - conditions: - - base=main - - label=backport-to-v1.3.x - actions: - backport: - branches: - - release/v1.3.x - - name: backport patches to v1.4.x branch - conditions: - - base=main - - label=backport-to-v1.4.x - actions: - backport: - branches: - - release/v1.4.x - - name: backport patches to v1.5.x branch - conditions: - - base=main - - label=backport-to-v1.5.x - actions: - backport: - branches: - - release/v1.5.x - name: backport patches to v2.1.x branch conditions: - base=main @@ -81,4 +57,12 @@ pull_request_rules: actions: backport: branches: - - release/v3.1.x + - release/v3.1.x + - name: backport patches to v4.0.x branch + conditions: + - base=main + - label=backport-to-v4.0.x + actions: + backport: + branches: + - release/v4.0.x From 6c4a44243e6a381293920aab483c44aa840cf556 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 1 Jul 2022 22:45:13 +0200 Subject: [PATCH 202/275] delete unused 04-channel version functions (#1636) * delete unused code and associated tests * Update CHANGELOG.md --- CHANGELOG.md | 1 + modules/core/04-channel/types/version.go | 27 ------- modules/core/04-channel/types/version_test.go | 77 ------------------- 3 files changed, 1 insertion(+), 104 deletions(-) delete mode 100644 modules/core/04-channel/types/version.go delete mode 100644 modules/core/04-channel/types/version_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e7357459f4..766d232d43b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (apps/27-interchain-accounts)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Removing `NewErrorAcknowledgement` in favour of `channeltypes.NewErrorAcknowledgement`. * (transfer)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Removing `NewErrorAcknowledgement` in favour of `channeltypes.NewErrorAcknowledgement`. * (channel)[\#1565](https://github.com/cosmos/ibc-go/pull/1565) Updating `NewErrorAcknowledgement` to accept an error instead of a string and removing the possibility of non-deterministic writes to application state. +* (core/04-channel)[\#1636](https://github.com/cosmos/ibc-go/pull/1636) Removing `SplitChannelVersion` and `MergeChannelVersions` functions since they are not used. ### State Machine Breaking diff --git a/modules/core/04-channel/types/version.go b/modules/core/04-channel/types/version.go deleted file mode 100644 index a2696d291ed..00000000000 --- a/modules/core/04-channel/types/version.go +++ /dev/null @@ -1,27 +0,0 @@ -package types - -import "strings" - -const ChannelVersionDelimiter = ":" - -// SplitChannelVersion middleware version will split the channel version string -// into the outermost middleware version and the underlying app version. -// It will use the default delimiter `:` for middleware versions. -// In case there's no delimeter, this function returns an empty string for the middleware version (first return argument), -// and the full input as the second underlying app version. -func SplitChannelVersion(version string) (middlewareVersion, appVersion string) { - // only split out the first middleware version - splitVersions := strings.Split(version, ChannelVersionDelimiter) - if len(splitVersions) == 1 { - return "", version - } - middlewareVersion = splitVersions[0] - appVersion = strings.Join(splitVersions[1:], ChannelVersionDelimiter) - return -} - -// MergeChannelVersions merges the provided versions together with the channel version delimiter -// the versions should be passed in from the highest-level middleware to the base application -func MergeChannelVersions(versions ...string) string { - return strings.Join(versions, ChannelVersionDelimiter) -} diff --git a/modules/core/04-channel/types/version_test.go b/modules/core/04-channel/types/version_test.go deleted file mode 100644 index d735f162ae1..00000000000 --- a/modules/core/04-channel/types/version_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" -) - -func TestSplitVersions(t *testing.T) { - testCases := []struct { - name string - version string - mwVersion string - appVersion string - }{ - { - "single wrapped middleware", - "fee29-1:ics20-1", - "fee29-1", - "ics20-1", - }, - { - "multiple wrapped middleware", - "fee29-1:whitelist:ics20-1", - "fee29-1", - "whitelist:ics20-1", - }, - { - "no middleware", - "ics20-1", - "", - "ics20-1", - }, - } - - for _, tc := range testCases { - mwVersion, appVersion := types.SplitChannelVersion(tc.version) - require.Equal(t, tc.mwVersion, mwVersion, "middleware version is unexpected for case: %s", tc.name) - require.Equal(t, tc.appVersion, appVersion, "app version is unexpected for case: %s", tc.name) - } -} - -func TestMergeVersions(t *testing.T) { - testCases := []struct { - name string - versions []string - merged string - }{ - { - "single version", - []string{"ics20-1"}, - "ics20-1", - }, - { - "empty version", - []string{}, - "", - }, - { - "two versions", - []string{"fee29-1", "ics20-1"}, - "fee29-1:ics20-1", - }, - { - "multiple versions", - []string{"fee29-1", "whitelist", "ics20-1"}, - "fee29-1:whitelist:ics20-1", - }, - } - - for _, tc := range testCases { - actual := types.MergeChannelVersions(tc.versions...) - require.Equal(t, tc.merged, actual, "merged versions string does not equal expected value") - } -} From e04964912c266bab923253c48d72cc8ec8b38f5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 10:01:49 +0200 Subject: [PATCH 203/275] build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.5 to 0.45.6 (#1615) * build(deps): bump github.com/cosmos/cosmos-sdk from 0.45.5 to 0.45.6 Bumps [github.com/cosmos/cosmos-sdk](https://github.com/cosmos/cosmos-sdk) from 0.45.5 to 0.45.6. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/v0.45.5...v0.45.6) --- updated-dependencies: - dependency-name: github.com/cosmos/cosmos-sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update CHANGELOG.md * copying part of codeql workflow to try to make it pass Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: Carlos Rodriguez --- .github/workflows/codeql-analysis.yml | 18 +++++++++++++++++- CHANGELOG.md | 2 +- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index aaf7c7b8db3..f9a7c4a9230 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,9 +56,25 @@ jobs: # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main + queries: crypto-com/cosmos-sdk-codeql@main,security-and-quality if: env.GIT_DIFF + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) - - run: make build + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + if: env.GIT_DIFF + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 766d232d43b..f0c9dcfe094 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,7 +38,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies -* [\#1525](https://github.com/cosmos/ibc-go/pull/1525) Bump SDK version to v0.45.5 +* [\#1615](https://github.com/cosmos/ibc-go/pull/1615) Bump SDK version to v0.45.6 * [\#1627](https://github.com/cosmos/ibc-go/pull/1627) Bump Go version to 1.18 ### API Breaking diff --git a/go.mod b/go.mod index 1f3f2227636..de5b84637dc 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alp require ( github.com/armon/go-metrics v0.4.0 github.com/confio/ics23/go v0.7.0 - github.com/cosmos/cosmos-sdk v0.45.5 + github.com/cosmos/cosmos-sdk v0.45.6 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 diff --git a/go.sum b/go.sum index 2634352b610..3d39b9e62c8 100644 --- a/go.sum +++ b/go.sum @@ -226,8 +226,8 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= -github.com/cosmos/cosmos-sdk v0.45.5 h1:GVrZM+lss6y626Pq6loxh/3KLRgK/J6/alTkcKkYmGU= -github.com/cosmos/cosmos-sdk v0.45.5/go.mod h1:WOqtDxN3eCCmnYLVla10xG7lEXkFjpTaqm2a2WasgCc= +github.com/cosmos/cosmos-sdk v0.45.6 h1:bnYLOcDp0cKWMLeUTTJIttq6xxRep52ulPxXC3BCfuQ= +github.com/cosmos/cosmos-sdk v0.45.6/go.mod h1:bPeeVMEtVvH3y3xAGHVbK+/CZlpaazzh77hG8ZrcJpI= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= From 7d181821314d4bc6d0f8a5b885f293f5b975aed0 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 5 Jul 2022 10:49:18 +0200 Subject: [PATCH 204/275] update mergify.yml with new release branches (#1654) --- .github/mergify.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/mergify.yml b/.github/mergify.yml index 6f6464653e1..2dfc4653a7d 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -41,7 +41,15 @@ pull_request_rules: actions: backport: branches: - - release/v2.3.x + - release/v2.3.x + - name: backport patches to v2.4.x branch + conditions: + - base=main + - label=backport-to-v2.4.x + actions: + backport: + branches: + - release/v2.4.x - name: backport patches to v3.0.x branch conditions: - base=main @@ -58,6 +66,14 @@ pull_request_rules: backport: branches: - release/v3.1.x + - name: backport patches to v3.2.x branch + conditions: + - base=main + - label=backport-to-v3.2.x + actions: + backport: + branches: + - release/v3.2.x - name: backport patches to v4.0.x branch conditions: - base=main From 527a11a2bbe59e172649d5c22b87878d86859806 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 6 Jul 2022 11:04:28 +0100 Subject: [PATCH 205/275] Script to dynamically generate list of e2e tests (E2E #1) (#1644) --- .github/scripts/build_test_matrix.go | 130 +++++++++++++++++ .github/scripts/build_test_matrix_test.go | 162 ++++++++++++++++++++++ .github/workflows/test.yml | 2 +- Makefile | 2 +- 4 files changed, 294 insertions(+), 2 deletions(-) create mode 100644 .github/scripts/build_test_matrix.go create mode 100644 .github/scripts/build_test_matrix_test.go diff --git a/.github/scripts/build_test_matrix.go b/.github/scripts/build_test_matrix.go new file mode 100644 index 00000000000..c86324b31f8 --- /dev/null +++ b/.github/scripts/build_test_matrix.go @@ -0,0 +1,130 @@ +package main + +import ( + "encoding/json" + "fmt" + "go/ast" + "go/parser" + "go/token" + "io/fs" + "os" + "path/filepath" + "strings" +) + +const ( + testNamePrefix = "Test" + testFileNameSuffix = "_test.go" + e2eTestDirectory = "e2e" +) + +// GithubActionTestMatrix represents +type GithubActionTestMatrix struct { + Include []TestSuitePair `json:"include"` +} + +type TestSuitePair struct { + Test string `json:"test"` + Suite string `json:"suite"` +} + +func main() { + githubActionMatrix, err := getGithubActionMatrixForTests(e2eTestDirectory) + if err != nil { + fmt.Printf("error generating github action json: %s", err) + os.Exit(1) + } + + ghBytes, err := json.Marshal(githubActionMatrix) + if err != nil { + fmt.Printf("error marshalling github action json: %s", err) + os.Exit(1) + } + fmt.Println(string(ghBytes)) +} + +// getGithubActionMatrixForTests returns a json string representing the contents that should go in the matrix +// field in a github action workflow. This string can be used with `fromJSON(str)` to dynamically build +// the workflow matrix to include all E2E tests under the e2eRootDirectory directory. +func getGithubActionMatrixForTests(e2eRootDirectory string) (GithubActionTestMatrix, error) { + testSuiteMapping := map[string][]string{} + fset := token.NewFileSet() + err := filepath.Walk(e2eRootDirectory, func(path string, info fs.FileInfo, err error) error { + // only look at test files + if !strings.HasSuffix(path, testFileNameSuffix) { + return nil + } + + f, err := parser.ParseFile(fset, path, nil, 0) + if err != nil { + return fmt.Errorf("failed parsing file: %s", err) + } + + suiteNameForFile, testCases, err := extractSuiteAndTestNames(f) + if err != nil { + return fmt.Errorf("failed extracting test suite name and test cases: %s", err) + } + + testSuiteMapping[suiteNameForFile] = testCases + + return nil + }) + + if err != nil { + return GithubActionTestMatrix{}, err + } + + gh := GithubActionTestMatrix{ + Include: []TestSuitePair{}, + } + + for testSuiteName, testCases := range testSuiteMapping { + for _, testCaseName := range testCases { + gh.Include = append(gh.Include, TestSuitePair{ + Test: testCaseName, + Suite: testSuiteName, + }) + } + } + + return gh, nil +} + +// extractSuiteAndTestNames extracts the name of the test suite function as well +// as all tests associated with it in the same file. +func extractSuiteAndTestNames(file *ast.File) (string, []string, error) { + var suiteNameForFile string + var testCases []string + + for _, d := range file.Decls { + if f, ok := d.(*ast.FuncDecl); ok { + functionName := f.Name.Name + if isTestSuiteMethod(f) { + if suiteNameForFile != "" { + return "", nil, fmt.Errorf("found a second test function: %s when %s was already found", f.Name.Name, suiteNameForFile) + } + suiteNameForFile = functionName + continue + } + if isTestFunction(f) { + testCases = append(testCases, functionName) + } + } + } + if suiteNameForFile == "" { + return "", nil, fmt.Errorf("file %s had no test suite test case", file.Name.Name) + } + return suiteNameForFile, testCases, nil +} + +// isTestSuiteMethod returns true if the function is a test suite function. +// e.g. func TestFeeMiddlewareTestSuite(t *testing.T) { ... } +func isTestSuiteMethod(f *ast.FuncDecl) bool { + return strings.HasPrefix(f.Name.Name, testNamePrefix) && len(f.Type.Params.List) == 1 +} + +// isTestFunction returns true if the function name starts with "Test" and has no parameters. +// as test suite functions do not accept a *testing.T. +func isTestFunction(f *ast.FuncDecl) bool { + return strings.HasPrefix(f.Name.Name, testNamePrefix) && len(f.Type.Params.List) == 0 +} diff --git a/.github/scripts/build_test_matrix_test.go b/.github/scripts/build_test_matrix_test.go new file mode 100644 index 00000000000..47de4d981c2 --- /dev/null +++ b/.github/scripts/build_test_matrix_test.go @@ -0,0 +1,162 @@ +package main + +import ( + "os" + "path" + "sort" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +const ( + nonTestFile = "not_test_file.go" + goTestFileNameOne = "first_go_file_test.go" + goTestFileNameTwo = "second_go_file_test.go" +) + +func TestGetGithubActionMatrixForTests(t *testing.T) { + t.Run("empty dir does not fail", func(t *testing.T) { + testingDir := t.TempDir() + _, err := getGithubActionMatrixForTests(testingDir) + assert.NoError(t, err) + }) + + t.Run("only test functions are picked up", func(t *testing.T) { + testingDir := t.TempDir() + createFileWithTestSuiteAndTests(t, "FeeMiddlewareTestSuite", "TestA", "TestB", testingDir, goTestFileNameOne) + + gh, err := getGithubActionMatrixForTests(testingDir) + assert.NoError(t, err) + + expected := GithubActionTestMatrix{ + Include: []TestSuitePair{ + { + Suite: "TestFeeMiddlewareTestSuite", + Test: "TestA", + }, + { + Suite: "TestFeeMiddlewareTestSuite", + Test: "TestB", + }, + }, + } + assertGithubActionTestMatricesEqual(t, expected, gh) + }) + + t.Run("all files are picked up", func(t *testing.T) { + testingDir := t.TempDir() + createFileWithTestSuiteAndTests(t, "FeeMiddlewareTestSuite", "TestA", "TestB", testingDir, goTestFileNameOne) + createFileWithTestSuiteAndTests(t, "TransferTestSuite", "TestC", "TestD", testingDir, goTestFileNameTwo) + + gh, err := getGithubActionMatrixForTests(testingDir) + assert.NoError(t, err) + + expected := GithubActionTestMatrix{ + Include: []TestSuitePair{ + { + Suite: "TestTransferTestSuite", + Test: "TestC", + }, + { + Suite: "TestFeeMiddlewareTestSuite", + Test: "TestA", + }, + { + Suite: "TestFeeMiddlewareTestSuite", + Test: "TestB", + }, + { + Suite: "TestTransferTestSuite", + Test: "TestD", + }, + }, + } + + assertGithubActionTestMatricesEqual(t, expected, gh) + }) + + t.Run("non test files are not picked up", func(t *testing.T) { + testingDir := t.TempDir() + createFileWithTestSuiteAndTests(t, "FeeMiddlewareTestSuite", "TestA", "TestB", testingDir, nonTestFile) + + gh, err := getGithubActionMatrixForTests(testingDir) + assert.NoError(t, err) + assert.Empty(t, gh.Include) + }) + + t.Run("fails when there are multiple suite runs", func(t *testing.T) { + testingDir := t.TempDir() + createFileWithTestSuiteAndTests(t, "FeeMiddlewareTestSuite", "TestA", "TestB", testingDir, nonTestFile) + + fileWithTwoSuites := `package foo +func SuiteOne(t *testing.T) { + suite.Run(t, new(FeeMiddlewareTestSuite)) +} + +func SuiteTwo(t *testing.T) { + suite.Run(t, new(FeeMiddlewareTestSuite)) +} + +type FeeMiddlewareTestSuite struct {} +` + + err := os.WriteFile(path.Join(testingDir, goTestFileNameOne), []byte(fileWithTwoSuites), os.FileMode(777)) + assert.NoError(t, err) + + _, err = getGithubActionMatrixForTests(testingDir) + assert.Error(t, err) + }) +} + +func assertGithubActionTestMatricesEqual(t *testing.T, expected, actual GithubActionTestMatrix) { + // sort by both suite and test as the order of the end result does not matter as + // all tests will be run. + sort.SliceStable(expected.Include, func(i, j int) bool { + memberI := expected.Include[i] + memberJ := expected.Include[j] + if memberI.Suite == memberJ.Suite { + return memberI.Test < memberJ.Test + } + return memberI.Suite < memberJ.Suite + }) + + sort.SliceStable(actual.Include, func(i, j int) bool { + memberI := actual.Include[i] + memberJ := actual.Include[j] + if memberI.Suite == memberJ.Suite { + return memberI.Test < memberJ.Test + } + return memberI.Suite < memberJ.Suite + }) + assert.Equal(t, expected.Include, actual.Include) +} + +func goTestFileContents(suiteName, fnName1, fnName2 string) string { + + replacedSuiteName := strings.ReplaceAll(`package foo + +func TestSuiteName(t *testing.T) { + suite.Run(t, new(SuiteName)) +} + +type SuiteName struct {} + +func (s *SuiteName) fnName1() {} +func (s *SuiteName) fnName2() {} + +func (s *SuiteName) suiteHelper() {} + +func helper() {} +`, "SuiteName", suiteName) + + replacedFn1Name := strings.ReplaceAll(replacedSuiteName, "fnName1", fnName1) + return strings.ReplaceAll(replacedFn1Name, "fnName2", fnName2) +} + +func createFileWithTestSuiteAndTests(t *testing.T, suiteName, fn1Name, fn2Name, dir, filename string) { + goFileContents := goTestFileContents(suiteName, fn1Name, fn2Name) + err := os.WriteFile(path.Join(dir, filename), []byte(goFileContents), os.FileMode(777)) + assert.NoError(t, err) +} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c915db779cd..ff8ed4d65d9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,7 +63,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Create a file with all the pkgs - run: go list ./... > pkgs.txt + run: go list ./... ./.github/scripts > pkgs.txt - name: Split pkgs into 4 files run: split -d -n l/4 pkgs.txt pkgs.txt.part. # cache multiple diff --git a/Makefile b/Makefile index 0ea7f0c10c5..9beb4ab61bc 100644 --- a/Makefile +++ b/Makefile @@ -216,7 +216,7 @@ view-docs: test: test-unit test-all: test-unit test-ledger-mock test-race test-cover -TEST_PACKAGES=./... +TEST_PACKAGES=./... ./.github/scripts TEST_TARGETS := test-unit test-unit-amino test-unit-proto test-ledger-mock test-race test-ledger test-race # Test runs-specific rules. To add a new test target, just add From 6d1fa91db6193df2f314bfa68e5c0502627c7c63 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Fri, 8 Jul 2022 08:46:38 +0100 Subject: [PATCH 206/275] Add GitHub actions for e2e tests (E2E #2) (#1646) --- .github/scripts/determine_simd_tag.go | 34 ++++++++++ .github/workflows/test.yml | 97 ++++++++++++++++++++++++--- Makefile | 10 +++ e2e/fee_middleware_test.go | 29 ++++++++ 4 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 .github/scripts/determine_simd_tag.go create mode 100644 e2e/fee_middleware_test.go diff --git a/.github/scripts/determine_simd_tag.go b/.github/scripts/determine_simd_tag.go new file mode 100644 index 00000000000..3fb4ce6986f --- /dev/null +++ b/.github/scripts/determine_simd_tag.go @@ -0,0 +1,34 @@ +package main + +import ( + "flag" + "fmt" + "os" +) + +var prNum int +var ref string + +func init() { + flag.IntVar(&prNum, "pr", 0, "the number of the pr") + flag.StringVar(&ref, "ref", "", "the github ref") + flag.Parse() +} + +// in the context of a GithubAction workflow, the PR is the event number. So if the ref is not specified +// but the event number is, that means we are running for a PR. If the ref is specified, this means +// we have merged the PR, so we want to use the ref as a tag instead of the PR number. +func main() { + if prNum == 0 && ref == "" { + fmt.Printf("must specify one or bot of [pr, ref]") + os.Exit(1) + } + fmt.Printf(getSimdTag(prNum, ref)) +} + +func getSimdTag(prNum int, ref string) string { + if ref != "" { + return ref + } + return fmt.Sprintf("pr-%d", prNum) +} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ff8ed4d65d9..8482853965a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,11 @@ on: push: branches: - main + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ibc-go-simd-e2e + jobs: cleanup-runs: runs-on: ubuntu-latest @@ -51,13 +56,6 @@ jobs: - name: Build run: GOARCH=${{ matrix.go-arch }} LEDGER_ENABLED=false make build - docker-build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Docker Build - run: docker build . --no-cache - split-test-files: runs-on: ubuntu-latest steps: @@ -108,7 +106,7 @@ jobs: if: env.GIT_DIFF - name: test & coverage report creation run: | - cat pkgs.txt.part.${{ matrix.part }} | xargs go test -race -mod=readonly -timeout 30m -coverprofile=${{ matrix.part }}profile.out -covermode=atomic -tags='ledger test_ledger_mock' + cat pkgs.txt.part.${{ matrix.part }} | xargs go test $(go list ./... | grep -v e2e) -race -mod=readonly -timeout 30m -coverprofile=${{ matrix.part }}profile.out -covermode=atomic -tags='ledger test_ledger_mock' if: env.GIT_DIFF - uses: actions/upload-artifact@v3 with: @@ -161,3 +159,86 @@ jobs: with: file: ./coverage.txt if: env.GIT_DIFF + + + docker-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Log in to the Container registry + uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@69f6fc9d46f2f8bf0d5491e4aabe0bb8c6a4678a + with: + images: ${{ env.REGISTRY }}/cosmos/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + uses: docker/build-push-action@e551b19e49efd4e98792db7592c17c09b89db8d8 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + + # dynamically build a matrix of test/test suite pairs to run + build-test-matrix: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 1.18 + - id: set-matrix + run: echo "::set-output name=matrix::$(go run .github/scripts/build_test_matrix.go)" + + + # the tag of the image will differ if this is a PR or the branch is being merged into main. + # we store the tag as an environment variable and use it in the E2E tests to determine the tag. + determine-image-tag: + runs-on: ubuntu-latest + outputs: + simd-tag: ${{ steps.get-tag.outputs.simd-tag }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 1.18 + - id: get-tag + run: | + tag=$(go run .github/scripts/determine_simd_tag.go -ref "${{ github.event.push.ref }}" -pr "${{ github.event.pull_request.number }}" ) + echo "Using tag $tag" + echo "::set-output name=simd-tag::$tag" + + + e2e: + runs-on: ubuntu-latest + needs: + - build-test-matrix + - determine-image-tag + - docker-build + env: + SIMD_TAG: ${{ needs.determine-image-tag.outputs.simd-tag }} + SIMD_IMAGE: ghcr.io/cosmos/ibc-go-simd-e2e + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.build-test-matrix.outputs.matrix) }} + steps: + - uses: actions/checkout@v3 + - name: Log in to the Container registry + uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Run e2e Test + run: | + make e2e-test suite=${{ matrix.suite }} test=${{ matrix.test }} diff --git a/Makefile b/Makefile index 9beb4ab61bc..df259c5a477 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ MOCKS_DIR = $(CURDIR)/tests/mocks HTTPS_GIT := https://github.com/cosmos/ibc-go.git DOCKER := $(shell which docker) DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf:1.0.0-rc8 +TEST_CONTAINERS=$(shell docker ps --filter "label=ibc-test" -a -q) export GO111MODULE = on @@ -324,6 +325,15 @@ benchmark: @go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION) .PHONY: benchmark +cleanup-ibc-test-containers: + for id in $(TEST_CONTAINERS) ; do \ + $(DOCKER) stop $$id ; \ + $(DOCKER) rm $$id ; \ + done + +e2e-test: cleanup-ibc-test-containers + @go test -v ./e2e --run $(suite) -testify.m ^$(test)$$ + ############################################################################### ### Linting ### ############################################################################### diff --git a/e2e/fee_middleware_test.go b/e2e/fee_middleware_test.go new file mode 100644 index 00000000000..33327ecfb15 --- /dev/null +++ b/e2e/fee_middleware_test.go @@ -0,0 +1,29 @@ +package e2e + +import ( + "os" + "testing" + + "github.com/stretchr/testify/suite" +) + +func TestFeeMiddlewareTestSuite(t *testing.T) { + suite.Run(t, new(FeeMiddlewareTestSuite)) +} + +type FeeMiddlewareTestSuite struct { + suite.Suite +} + +func (s *FeeMiddlewareTestSuite) TestPlaceholder() { + tag, ok := os.LookupEnv("SIMD_TAG") + s.Require().True(ok) + s.T().Logf("SIMD_TAG=%s", tag) + + image, ok := os.LookupEnv("SIMD_IMAGE") + s.Require().True(ok) + s.T().Logf("SIMD_IMAGE=%s", image) + + s.T().Logf("Placeholder test") + s.Require().True(true) +} From 7370a8b438b5a7d9e3982673bcfbfc550145b1f2 Mon Sep 17 00:00:00 2001 From: vuong <56973102+vuong177@users.noreply.github.com> Date: Mon, 11 Jul 2022 21:54:56 +0700 Subject: [PATCH 207/275] Remove crossings hello (#1317) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove crossing hellos from ChanOpenTry * remove crossing hellos testcase * revert single connectionHops check * add comment in MsgChannelOpenTry tx proto about deprecate field * Update proto/ibc/core/channel/v1/tx.proto Co-authored-by: Aditya * minor fixes && UPDATE CHANGELOG.md * Update proto/ibc/core/channel/v1/tx.proto Co-authored-by: Carlos Rodriguez * Update proto/ibc/core/channel/v1/tx.proto Co-authored-by: Damian Nolan * apply remaining changes for crossing hello removal Deprecate previous channel id with proto tag Remove unnecessary test cases from 04-channel Remove crossing hello check in transfer application and the associated test case * remove previous channel check in WriteChannelOpenTry * regenerate proto files * update documentation * add migration documentation * remove unnecessary doc * remove crossing hello notion from ChanOpenAck * apply review suggestions Co-authored-by: Aditya Co-authored-by: Carlos Rodriguez Co-authored-by: Damian Nolan Co-authored-by: Jacob Gadikian Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> --- CHANGELOG.md | 2 + docs/ibc/apps.md | 12 +- docs/ibc/proto-docs.md | 2 +- docs/migrations/v3-to-v4.md | 10 ++ modules/apps/29-fee/ibc_middleware_test.go | 22 +-- modules/apps/transfer/ibc_module.go | 12 +- modules/apps/transfer/ibc_module_test.go | 4 +- modules/core/04-channel/keeper/handshake.go | 72 ++------ .../core/04-channel/keeper/handshake_test.go | 40 +---- modules/core/04-channel/types/tx.pb.go | 169 +++++++++--------- modules/core/keeper/msg_server.go | 2 +- proto/ibc/core/channel/v1/tx.proto | 5 +- testing/coordinator.go | 21 --- 13 files changed, 128 insertions(+), 245 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0c9dcfe094..e1fdccd2092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (modules/core/04-channel) [\#1317](https://github.com/cosmos/ibc-go/pull/1317) Remove crossing hellos from channel handshakes. The `PreviousChannelId` in `MsgChannelOpenTry` has been deprecated. * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) The `OnChanOpenInit` application callback now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). * (modules/29-fee)[\#1338](https://github.com/cosmos/ibc-go/pull/1338) Renaming `Result` field in `IncentivizedAcknowledgement` to `AppAcknowledgement`. @@ -62,6 +63,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (modules/core/04-channel) [\#1232](https://github.com/cosmos/ibc-go/pull/1232) Updating params on `NewPacketId` and moving to bottom of file. * (app/29-fee) [\#1305](https://github.com/cosmos/ibc-go/pull/1305) Change version string for fee module to `ics29-1` * (app/29-fee) [\#1341](https://github.com/cosmos/ibc-go/pull/1341) Check if the fee module is locked and if the fee module is enabled before refunding all fees +* (transfer) [\#1414](https://github.com/cosmos/ibc-go/pull/1414) Emitting Sender address from `fungible_token_packet` events in `OnRecvPacket` and `OnAcknowledgementPacket`. * (testing/simapp) [\#1397](https://github.com/cosmos/ibc-go/pull/1397) Adding mock module to maccperms and adding check to ensure mock module is not a blocked account address. * (core/02-client) [\#1570](https://github.com/cosmos/ibc-go/pull/1570) Emitting an event when handling an upgrade client proposal. diff --git a/docs/ibc/apps.md b/docs/ibc/apps.md index 267a2e5ca55..11fa1e84b7e 100644 --- a/docs/ibc/apps.md +++ b/docs/ibc/apps.md @@ -73,15 +73,9 @@ OnChanOpenTry( counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { - // 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 the module can already authenticate the capability then the 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 !k.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 := k.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return err - } + // OpenTry must claim the channelCapability that IBC passes into the callback + if err := k.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return err } // ... do custom initialization logic diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index 30c6d350bd1..ced55cfbc75 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -2949,7 +2949,7 @@ value will be ignored by core IBC. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `port_id` | [string](#string) | | | -| `previous_channel_id` | [string](#string) | | in the case of crossing hello's, when both chains call OpenInit, we need the channel identifier of the previous channel in state INIT | +| `previous_channel_id` | [string](#string) | | **Deprecated.** Deprecated: this field is unused. Crossing hello's are no longer supported in core IBC. | | `channel` | [Channel](#ibc.core.channel.v1.Channel) | | NOTE: the version field within the channel has been deprecated. Its value will be ignored by core IBC. | | `counterparty_version` | [string](#string) | | | | `proof_init` | [bytes](#bytes) | | | diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 903c027ce4b..9d6a1fb3f31 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -18,6 +18,10 @@ No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-g ## Chains +- No relevant changes were made in this release. + +## IBC Apps + ### ICS04 - Channel The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. @@ -30,6 +34,10 @@ The `NewErrorAcknowledgement` method signature has changed. It now accepts an `error` rather than a `string`. This was done in order to prevent accidental state changes. All error acknowledgements now contain a deterministic ABCI code and error message. It is the responsibility of the application developer to emit error details in events. +Crossing hellos have been removed from 04-channel handshake negotiation. +IBC Applications no longer need to account from already claimed capabilities in the `OnChanOpenTry` callback. The capability provided by core IBC must be able to be claimed with error. +`PreviousChannelId` in `MsgChannelOpenTry` has been deprecated and is no longer used by core IBC. + ### ICS27 - Interchain Accounts The `RegisterInterchainAccount` API has been modified to include an additional `version` argument. This change has been made in order to support ICS29 fee middleware, for relayer incentivization of ICS27 packets. @@ -91,3 +99,5 @@ if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, ## Relayers When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. + +Crossing hellos are no longer supported by core IBC. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 6f0de4b1971..ea7cdcae8b6 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -141,38 +141,27 @@ func (suite *FeeTestSuite) TestOnChanOpenTry() { testCases := []struct { name string cpVersion string - crossing bool expPass bool }{ { "success - valid fee middleware version", string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), - false, true, }, { "success - valid mock version", ibcmock.Version, - false, - true, - }, - { - "success - crossing hellos: valid fee middleware", - string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), - true, true, }, { "invalid fee middleware version", string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: "invalid-ics29-1", AppVersion: ibcmock.Version})), false, - false, }, { "invalid mock version", string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: "invalid-mock-version"})), false, - false, }, } @@ -201,14 +190,9 @@ func (suite *FeeTestSuite) TestOnChanOpenTry() { ok bool err error ) - if tc.crossing { - suite.path.EndpointA.ChanOpenInit() - chanCap, ok = suite.chainA.GetSimApp().ScopedFeeMockKeeper.GetCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) - suite.Require().True(ok) - } else { - chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) - suite.Require().NoError(err) - } + + chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) + suite.Require().NoError(err) suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 7b87b33408c..6472c2998b0 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -111,15 +111,9 @@ func (im IBCModule) OnChanOpenTry( return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: got: %s, expected %s", counterpartyVersion, types.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 !im.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 := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } + // OpenTry must claim the channelCapability that IBC passes into the callback + if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", err } return types.Version, nil diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 3b8e0175517..3ff7b25679e 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -124,10 +124,10 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { }, false, }, { - "capability already claimed in INIT should pass", func() { + "capability already claimed", func() { err := suite.chainA.GetSimApp().ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) suite.Require().NoError(err) - }, true, + }, false, }, { "invalid order - ORDERED", func() { diff --git a/modules/core/04-channel/keeper/handshake.go b/modules/core/04-channel/keeper/handshake.go index 25937c78d6e..1d9cfd6382c 100644 --- a/modules/core/04-channel/keeper/handshake.go +++ b/modules/core/04-channel/keeper/handshake.go @@ -98,51 +98,20 @@ func (k Keeper) ChanOpenTry( ctx sdk.Context, order types.Order, connectionHops []string, - portID, - previousChannelID string, + portID string, portCap *capabilitytypes.Capability, counterparty types.Counterparty, counterpartyVersion string, proofInit []byte, proofHeight exported.Height, ) (string, *capabilitytypes.Capability, error) { - var ( - previousChannel types.Channel - previousChannelFound bool - ) - - channelID := previousChannelID - // connection hops only supports a single connection if len(connectionHops) != 1 { return "", nil, sdkerrors.Wrapf(types.ErrTooManyConnectionHops, "expected 1, got %d", len(connectionHops)) } - // empty channel identifier indicates continuing a previous channel handshake - if previousChannelID != "" { - // channel identifier and connection hop length checked on msg.ValidateBasic() - // ensure that the previous channel exists - previousChannel, previousChannelFound = k.GetChannel(ctx, portID, previousChannelID) - if !previousChannelFound { - return "", nil, sdkerrors.Wrapf(types.ErrInvalidChannel, "previous channel does not exist for supplied previous channelID %s", previousChannelID) - } - // previous channel must use the same fields - if !(previousChannel.Ordering == order && - previousChannel.Counterparty.PortId == counterparty.PortId && - previousChannel.Counterparty.ChannelId == "" && - previousChannel.ConnectionHops[0] == connectionHops[0] && // ChanOpenInit will only set a single connection hop - previousChannel.Version == counterpartyVersion) { - return "", nil, sdkerrors.Wrap(types.ErrInvalidChannel, "channel fields mismatch previous channel fields") - } - - if previousChannel.State != types.INIT { - return "", nil, sdkerrors.Wrapf(types.ErrInvalidChannelState, "previous channel state is in %s, expected INIT", previousChannel.State) - } - - } else { - // generate a new channel - channelID = k.GenerateChannelIdentifier(ctx) - } + // generate a new channel + channelID := k.GenerateChannelIdentifier(ctx) if !k.portKeeper.Authenticate(ctx, portCap, portID) { return "", nil, sdkerrors.Wrapf(porttypes.ErrInvalidPort, "caller does not own port capability for port ID %s", portID) @@ -199,20 +168,9 @@ func (k Keeper) ChanOpenTry( err error ) - if !previousChannelFound { - capKey, err = k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) - if err != nil { - return "", nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID) - } - - } else { - // capability initialized in ChanOpenInit - capKey, found = k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) - if !found { - return "", nil, sdkerrors.Wrapf(types.ErrChannelCapabilityNotFound, - "capability not found for existing channel, portID (%s) channelID (%s)", portID, channelID, - ) - } + capKey, err = k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) + if err != nil { + return "", nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID) } return channelID, capKey, nil @@ -230,18 +188,15 @@ func (k Keeper) WriteOpenTryChannel( counterparty types.Counterparty, version string, ) { - previousChannel, previousChannelFound := k.GetChannel(ctx, portID, channelID) - if !previousChannelFound { - k.SetNextSequenceSend(ctx, portID, channelID, 1) - k.SetNextSequenceRecv(ctx, portID, channelID, 1) - k.SetNextSequenceAck(ctx, portID, channelID, 1) - } + k.SetNextSequenceSend(ctx, portID, channelID, 1) + k.SetNextSequenceRecv(ctx, portID, channelID, 1) + k.SetNextSequenceAck(ctx, portID, channelID, 1) channel := types.NewChannel(types.TRYOPEN, order, counterparty, connectionHops, version) k.SetChannel(ctx, portID, channelID, channel) - k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", previousChannel.State.String(), "new-state", "TRYOPEN") + k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", "NONE", "new-state", "TRYOPEN") defer func() { telemetry.IncrCounter(1, "ibc", "channel", "open-try") @@ -267,11 +222,8 @@ func (k Keeper) ChanOpenAck( return sdkerrors.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) } - if !(channel.State == types.INIT || channel.State == types.TRYOPEN) { - return sdkerrors.Wrapf( - types.ErrInvalidChannelState, - "channel state should be INIT or TRYOPEN (got %s)", channel.State.String(), - ) + if channel.State != types.INIT { + return sdkerrors.Wrapf(types.ErrInvalidChannelState, "channel state should be INIT (got %s)", channel.State.String()) } if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { diff --git a/modules/core/04-channel/keeper/handshake_test.go b/modules/core/04-channel/keeper/handshake_test.go index 498b46d119b..88ca88887b4 100644 --- a/modules/core/04-channel/keeper/handshake_test.go +++ b/modules/core/04-channel/keeper/handshake_test.go @@ -143,10 +143,9 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { // ChanOpenTry can succeed. func (suite *KeeperTestSuite) TestChanOpenTry() { var ( - path *ibctesting.Path - previousChannelID string - portCap *capabilitytypes.Capability - heightDiff uint64 + path *ibctesting.Path + portCap *capabilitytypes.Capability + heightDiff uint64 ) testCases := []testCase{ @@ -158,34 +157,6 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) }, true}, - {"success with crossing hello", func() { - suite.coordinator.SetupConnections(path) - path.SetChannelOrdered() - err := suite.coordinator.ChanOpenInitOnBothChains(path) - suite.Require().NoError(err) - - previousChannelID = path.EndpointB.ChannelID - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) - }, true}, - {"previous channel with invalid version, crossing hello", func() { - suite.coordinator.SetupConnections(path) - path.SetChannelOrdered() - - // modify channel version - path.EndpointA.ChannelConfig.Version = "invalid version" - - err := suite.coordinator.ChanOpenInitOnBothChains(path) - suite.Require().NoError(err) - - previousChannelID = path.EndpointB.ChannelID - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) - }, false}, - {"previous channel with invalid state", func() { - suite.coordinator.SetupConnections(path) - - // make previous channel have wrong ordering - path.EndpointA.ChanOpenInit() - }, false}, {"connection doesn't exist", func() { path.EndpointA.ConnectionID = ibctesting.FirstConnectionID path.EndpointB.ConnectionID = ibctesting.FirstConnectionID @@ -268,7 +239,6 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset heightDiff = 0 // must be explicitly changed in malleate - previousChannelID = "" path = ibctesting.NewPath(suite.chainA, suite.chainB) tc.malleate() @@ -286,7 +256,7 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { channelID, cap, err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanOpenTry( suite.chainB.GetContext(), types.ORDERED, []string{path.EndpointB.ConnectionID}, - path.EndpointB.ChannelConfig.PortID, previousChannelID, portCap, counterparty, path.EndpointA.ChannelConfig.Version, + path.EndpointB.ChannelConfig.PortID, portCap, counterparty, path.EndpointA.ChannelConfig.Version, proof, malleateHeight(proofHeight, heightDiff), ) @@ -352,7 +322,7 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"channel doesn't exist", func() {}, false}, - {"channel state is not INIT or TRYOPEN", func() { + {"channel state is not INIT", func() { // create fully open channels on both chains suite.coordinator.Setup(path) channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) diff --git a/modules/core/04-channel/types/tx.pb.go b/modules/core/04-channel/types/tx.pb.go index 4c8d176bd15..6ad733decee 100644 --- a/modules/core/04-channel/types/tx.pb.go +++ b/modules/core/04-channel/types/tx.pb.go @@ -160,9 +160,8 @@ func (m *MsgChannelOpenInitResponse) GetVersion() string { // value will be ignored by core IBC. type MsgChannelOpenTry struct { PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty" yaml:"port_id"` - // in the case of crossing hello's, when both chains call OpenInit, we need - // the channel identifier of the previous channel in state INIT - PreviousChannelId string `protobuf:"bytes,2,opt,name=previous_channel_id,json=previousChannelId,proto3" json:"previous_channel_id,omitempty" yaml:"previous_channel_id"` + // Deprecated: this field is unused. Crossing hello's are no longer supported in core IBC. + PreviousChannelId string `protobuf:"bytes,2,opt,name=previous_channel_id,json=previousChannelId,proto3" json:"previous_channel_id,omitempty" yaml:"previous_channel_id"` // Deprecated: Do not use. // NOTE: the version field within the channel has been deprecated. Its value will be ignored by core IBC. Channel Channel `protobuf:"bytes,3,opt,name=channel,proto3" json:"channel"` CounterpartyVersion string `protobuf:"bytes,4,opt,name=counterparty_version,json=counterpartyVersion,proto3" json:"counterparty_version,omitempty" yaml:"counterparty_version"` @@ -918,88 +917,88 @@ func init() { func init() { proto.RegisterFile("ibc/core/channel/v1/tx.proto", fileDescriptor_bc4637e0ac3fc7b7) } var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ - // 1294 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4d, 0x6f, 0xe2, 0x56, - 0x17, 0xc6, 0x40, 0x20, 0x39, 0xe4, 0x4d, 0x88, 0x49, 0x32, 0xc4, 0x24, 0x98, 0xd7, 0x8b, 0x49, - 0x94, 0x2a, 0x30, 0xc9, 0x64, 0x54, 0x4d, 0x54, 0xa9, 0x0a, 0x94, 0x51, 0xa3, 0x36, 0x1f, 0x32, - 0xa4, 0x52, 0xd3, 0xaa, 0x08, 0xcc, 0x1d, 0x62, 0x01, 0x36, 0xb5, 0x0d, 0x33, 0xfc, 0x83, 0x51, - 0x56, 0xb3, 0x1e, 0x29, 0xd2, 0x54, 0x5d, 0x55, 0x5d, 0x4c, 0x7f, 0xc6, 0x2c, 0x67, 0xd5, 0x56, - 0x5d, 0xa0, 0x2a, 0xd9, 0x74, 0xcd, 0x2f, 0xa8, 0x7c, 0x7d, 0x6d, 0x0c, 0xd8, 0x8a, 0x33, 0x93, - 0x64, 0xba, 0xf3, 0xbd, 0xe7, 0xb9, 0xe7, 0x9c, 0xfb, 0x9c, 0xe7, 0x7e, 0x19, 0x96, 0xc5, 0x8a, - 0x90, 0x11, 0x64, 0x05, 0x65, 0x84, 0xd3, 0xb2, 0x24, 0xa1, 0x46, 0xa6, 0xb3, 0x99, 0xd1, 0x9e, - 0xa7, 0x5b, 0x8a, 0xac, 0xc9, 0x74, 0x4c, 0xac, 0x08, 0x69, 0xdd, 0x9a, 0x26, 0xd6, 0x74, 0x67, - 0x93, 0x99, 0xaf, 0xc9, 0x35, 0x19, 0xdb, 0x33, 0xfa, 0x97, 0x01, 0x65, 0xd8, 0x81, 0xa3, 0x86, - 0x88, 0x24, 0x4d, 0xf7, 0x63, 0x7c, 0x11, 0xc0, 0xff, 0x9d, 0x22, 0x99, 0x6e, 0x31, 0x84, 0xfb, - 0x89, 0x02, 0x7a, 0x5f, 0xad, 0xe5, 0x8c, 0xce, 0xc3, 0x16, 0x92, 0xf6, 0x24, 0x51, 0xa3, 0x3f, - 0x81, 0x70, 0x4b, 0x56, 0xb4, 0x92, 0x58, 0x8d, 0x53, 0x29, 0x6a, 0x6d, 0x2a, 0x4b, 0xf7, 0x7b, - 0xec, 0x4c, 0xb7, 0xdc, 0x6c, 0xec, 0x70, 0xc4, 0xc0, 0xf1, 0x21, 0xfd, 0x6b, 0xaf, 0x4a, 0x7f, - 0x06, 0x61, 0xe2, 0x34, 0xee, 0x4f, 0x51, 0x6b, 0x91, 0xad, 0xe5, 0xb4, 0xc3, 0x24, 0xd2, 0x24, - 0x46, 0x36, 0xf8, 0xb6, 0xc7, 0xfa, 0x78, 0x73, 0x08, 0xbd, 0x08, 0x21, 0x55, 0xac, 0x49, 0x48, - 0x89, 0x07, 0xf4, 0x48, 0x3c, 0x69, 0xed, 0x4c, 0xbe, 0x78, 0xcd, 0xfa, 0xfe, 0x79, 0xcd, 0xfa, - 0xb8, 0x06, 0x30, 0xe3, 0x29, 0xf2, 0x48, 0x6d, 0xc9, 0x92, 0x8a, 0xe8, 0x6d, 0x00, 0xe2, 0x6a, - 0x90, 0xed, 0x42, 0xbf, 0xc7, 0xce, 0x19, 0xd9, 0x0e, 0x6c, 0x1c, 0x3f, 0x45, 0x1a, 0x7b, 0x55, - 0x3a, 0x0e, 0xe1, 0x0e, 0x52, 0x54, 0x51, 0x96, 0x70, 0xce, 0x53, 0xbc, 0xd9, 0xe4, 0x7e, 0x0f, - 0xc0, 0xdc, 0x70, 0xb8, 0xa2, 0xd2, 0xbd, 0x1e, 0x21, 0x07, 0x10, 0x6b, 0x29, 0xa8, 0x23, 0xca, - 0x6d, 0xb5, 0x64, 0xcb, 0x0d, 0x07, 0xca, 0x26, 0xfb, 0x3d, 0x96, 0x21, 0x03, 0xc7, 0x41, 0x1c, - 0x3f, 0x67, 0xf6, 0xe6, 0xac, 0x64, 0x6d, 0x04, 0x07, 0xae, 0x4f, 0x30, 0x0f, 0xf3, 0x82, 0xdc, - 0x96, 0x34, 0xa4, 0xb4, 0xca, 0x8a, 0xd6, 0x2d, 0x99, 0xf3, 0x0e, 0xe2, 0x74, 0xd8, 0x7e, 0x8f, - 0x4d, 0x10, 0xaa, 0x1c, 0x50, 0x1c, 0x1f, 0xb3, 0x77, 0x7f, 0x63, 0xf4, 0xea, 0xa4, 0xb7, 0x14, - 0x59, 0x7e, 0x5a, 0x12, 0x25, 0x51, 0x8b, 0x4f, 0xa4, 0xa8, 0xb5, 0x69, 0x3b, 0xe9, 0x03, 0x1b, - 0xc7, 0x4f, 0xe1, 0x06, 0x56, 0xd5, 0x09, 0x4c, 0x1b, 0x96, 0x53, 0x24, 0xd6, 0x4e, 0xb5, 0x78, - 0x08, 0x4f, 0x86, 0xb1, 0x4d, 0xc6, 0x50, 0x6f, 0x67, 0x33, 0xfd, 0x25, 0x46, 0x64, 0x13, 0xfa, - 0x54, 0xfa, 0x3d, 0x36, 0x66, 0xf7, 0x6b, 0x8c, 0xe6, 0xf8, 0x08, 0x6e, 0x1a, 0x48, 0x9b, 0x8c, - 0xc2, 0x2e, 0x32, 0x7a, 0x04, 0x4b, 0x63, 0x75, 0xb5, 0x54, 0x64, 0xd3, 0x03, 0x35, 0xac, 0x87, - 0x3f, 0xc6, 0xf4, 0xb0, 0x2b, 0xd4, 0xaf, 0xa7, 0x87, 0x61, 0x89, 0xfa, 0x3d, 0x4a, 0xf4, 0x04, - 0xee, 0x0d, 0x55, 0xc4, 0xe6, 0x02, 0xaf, 0x94, 0x2c, 0xd7, 0xef, 0xb1, 0x49, 0x87, 0xd2, 0xd9, - 0xfd, 0x2d, 0xd8, 0x2d, 0x03, 0x45, 0xdd, 0x86, 0x26, 0x36, 0xc1, 0x28, 0x75, 0x49, 0x53, 0xba, - 0x44, 0x12, 0xf3, 0xfd, 0x1e, 0x1b, 0xb5, 0x97, 0x4e, 0x53, 0xba, 0x1c, 0x3f, 0x89, 0xbf, 0xf5, - 0x55, 0xf5, 0x71, 0x05, 0x91, 0x18, 0x15, 0xc4, 0xae, 0x50, 0x37, 0x05, 0xc1, 0xfd, 0xea, 0x87, - 0x85, 0x61, 0x6b, 0x4e, 0x96, 0x9e, 0x8a, 0x4a, 0xf3, 0x2e, 0x4a, 0x6f, 0x51, 0x59, 0x16, 0xea, - 0xb8, 0xd8, 0x0e, 0x54, 0x96, 0x85, 0xba, 0x49, 0xa5, 0x2e, 0xc8, 0x51, 0x2a, 0x83, 0xb7, 0x42, - 0xe5, 0x84, 0x0b, 0x95, 0x2c, 0xac, 0x38, 0x92, 0x65, 0xd1, 0xf9, 0x8a, 0x82, 0xd8, 0x00, 0x91, - 0x6b, 0xc8, 0x2a, 0xba, 0xfe, 0x41, 0xf3, 0x7e, 0x64, 0x5e, 0x7d, 0xc0, 0xac, 0x40, 0xc2, 0x21, - 0x37, 0x2b, 0xf7, 0x37, 0x7e, 0x58, 0x1c, 0xb1, 0xdf, 0xa1, 0x16, 0x86, 0xb7, 0xda, 0xc0, 0x7b, - 0x6e, 0xb5, 0x77, 0x2b, 0x87, 0x14, 0x24, 0x9d, 0x09, 0xb3, 0x38, 0x7d, 0xe9, 0x87, 0xff, 0xed, - 0xab, 0x35, 0x1e, 0x09, 0x9d, 0xa3, 0xb2, 0x50, 0x47, 0x1a, 0xfd, 0x18, 0x42, 0x2d, 0xfc, 0x85, - 0x99, 0x8c, 0x6c, 0x25, 0x1c, 0xcf, 0x38, 0x03, 0x4c, 0x8e, 0x38, 0x32, 0x80, 0x7e, 0x02, 0x51, - 0x23, 0x5d, 0x41, 0x6e, 0x36, 0x45, 0xad, 0x89, 0x24, 0x0d, 0xd3, 0x3b, 0x9d, 0x4d, 0xf4, 0x7b, - 0xec, 0x3d, 0xfb, 0x84, 0x06, 0x08, 0x8e, 0x9f, 0xc5, 0x5d, 0x39, 0xab, 0x67, 0x8c, 0xb4, 0xc0, - 0xad, 0x90, 0x16, 0x74, 0x21, 0xed, 0x07, 0xbc, 0xe1, 0x0c, 0x18, 0xb1, 0xce, 0xa6, 0xcf, 0x21, - 0xa4, 0x20, 0xb5, 0xdd, 0x30, 0x98, 0x99, 0xd9, 0x5a, 0x75, 0x64, 0xc6, 0x84, 0xf3, 0x18, 0x5a, - 0xec, 0xb6, 0x10, 0x4f, 0x86, 0xed, 0x04, 0xf5, 0x18, 0xdc, 0x5f, 0x7e, 0x80, 0x7d, 0xb5, 0x56, - 0x14, 0x9b, 0x48, 0x6e, 0xdf, 0x0c, 0xdf, 0x6d, 0x49, 0x41, 0x02, 0x12, 0x3b, 0xa8, 0xea, 0xc6, - 0xf7, 0x00, 0x61, 0xf2, 0x7d, 0x6c, 0xf5, 0xdc, 0x2a, 0xdf, 0x5f, 0x01, 0x2d, 0xa1, 0xe7, 0x5a, - 0x49, 0x45, 0x3f, 0xb6, 0x91, 0x24, 0xa0, 0x92, 0x82, 0x84, 0x0e, 0xe6, 0x3e, 0x98, 0x5d, 0xe9, - 0xf7, 0xd8, 0x25, 0xc3, 0xc3, 0x38, 0x86, 0xe3, 0xa3, 0x7a, 0x67, 0x81, 0xf4, 0xe9, 0xf5, 0xf0, - 0xa0, 0xf8, 0xef, 0xf0, 0x35, 0x9a, 0x70, 0x7b, 0xd3, 0x95, 0x7b, 0x65, 0x5c, 0x41, 0x88, 0xf7, - 0x43, 0x09, 0xaf, 0xa8, 0xff, 0x42, 0x01, 0x3f, 0x85, 0x08, 0x59, 0x56, 0x7a, 0x46, 0x64, 0x73, - 0x5a, 0xec, 0xf7, 0x58, 0x7a, 0x68, 0xcd, 0xe9, 0x46, 0x8e, 0x37, 0xb6, 0x31, 0x23, 0xf7, 0xdb, - 0xdc, 0x9e, 0x9c, 0x2b, 0x3f, 0xf1, 0xa1, 0x95, 0x0f, 0xb9, 0x54, 0xbe, 0x82, 0x6f, 0x11, 0xc3, - 0xb5, 0xb9, 0x69, 0x01, 0xfc, 0xe6, 0xc7, 0xf2, 0xda, 0x15, 0xea, 0x92, 0xfc, 0xac, 0x81, 0xaa, - 0x35, 0x84, 0xf7, 0xab, 0x0f, 0x50, 0xc0, 0x1a, 0xcc, 0x96, 0x87, 0xbd, 0x19, 0x02, 0xe0, 0x47, - 0xbb, 0x07, 0x35, 0xd6, 0x07, 0x56, 0xdd, 0x6a, 0x8c, 0x8d, 0x66, 0x8d, 0x77, 0xf5, 0xc6, 0x47, - 0x3e, 0x82, 0x04, 0xfc, 0x68, 0x1c, 0x61, 0xec, 0x86, 0xeb, 0xb2, 0xfe, 0x0b, 0x05, 0xf4, 0x38, - 0x88, 0x7e, 0x04, 0x29, 0x3e, 0x5f, 0x38, 0x3a, 0x3c, 0x28, 0xe4, 0x4b, 0x7c, 0xbe, 0x70, 0xfc, - 0x75, 0xb1, 0x54, 0xfc, 0xf6, 0x28, 0x5f, 0x3a, 0x3e, 0x28, 0x1c, 0xe5, 0x73, 0x7b, 0x4f, 0xf6, - 0xf2, 0x5f, 0x44, 0x7d, 0xcc, 0xec, 0xd9, 0x79, 0x2a, 0x62, 0xeb, 0xa2, 0x57, 0x61, 0xc9, 0x71, - 0xd8, 0xc1, 0xe1, 0xe1, 0x51, 0x94, 0x62, 0x26, 0xcf, 0xce, 0x53, 0x41, 0xfd, 0x9b, 0xde, 0x80, - 0x65, 0x47, 0x60, 0xe1, 0x38, 0x97, 0xcb, 0x17, 0x0a, 0x51, 0x3f, 0x13, 0x39, 0x3b, 0x4f, 0x85, - 0x49, 0x93, 0x09, 0xbe, 0xf8, 0x39, 0xe9, 0xdb, 0x7a, 0x33, 0x09, 0x81, 0x7d, 0xb5, 0x46, 0xd7, - 0x61, 0x76, 0xf4, 0xb5, 0xef, 0x3c, 0xfb, 0xf1, 0x37, 0x37, 0x93, 0xf1, 0x08, 0xb4, 0x78, 0x3e, - 0x85, 0x99, 0x91, 0x87, 0xf4, 0x7d, 0x0f, 0x2e, 0x8a, 0x4a, 0x97, 0x49, 0x7b, 0xc3, 0xb9, 0x44, - 0xd2, 0x6f, 0xc4, 0x5e, 0x22, 0xed, 0x0a, 0x75, 0x4f, 0x91, 0x6c, 0x2f, 0x03, 0x5a, 0x03, 0xda, - 0xe1, 0x55, 0xb0, 0xee, 0xc1, 0x0b, 0xc1, 0x32, 0x5b, 0xde, 0xb1, 0x56, 0x54, 0x09, 0xa2, 0x63, - 0x97, 0xe7, 0xb5, 0x2b, 0xfc, 0x58, 0x48, 0xe6, 0x81, 0x57, 0xa4, 0x15, 0xef, 0x19, 0xc4, 0x1c, - 0x2f, 0xbc, 0x5e, 0x1c, 0x99, 0xf3, 0x7c, 0x78, 0x0d, 0xb0, 0x15, 0xf8, 0x7b, 0x00, 0xdb, 0xad, - 0x90, 0x73, 0x73, 0x31, 0xc0, 0x30, 0xeb, 0x57, 0x63, 0x2c, 0xef, 0x05, 0x08, 0x9b, 0x17, 0x20, - 0xd6, 0x6d, 0x18, 0x01, 0x30, 0xab, 0x57, 0x00, 0xec, 0xda, 0x1b, 0x39, 0x9b, 0xef, 0x5f, 0x31, - 0x94, 0xe0, 0xdc, 0xb5, 0xe7, 0x72, 0x9e, 0xd4, 0x61, 0x76, 0xf4, 0x10, 0x70, 0xcd, 0x72, 0x04, - 0xe8, 0xbe, 0x78, 0x5d, 0x36, 0xc9, 0x6c, 0xe1, 0xed, 0x45, 0x92, 0x7a, 0x77, 0x91, 0xa4, 0xfe, - 0xbe, 0x48, 0x52, 0x2f, 0x2f, 0x93, 0xbe, 0x77, 0x97, 0x49, 0xdf, 0x9f, 0x97, 0x49, 0xdf, 0xc9, - 0xe3, 0x9a, 0xa8, 0x9d, 0xb6, 0x2b, 0x69, 0x41, 0x6e, 0x66, 0x04, 0x59, 0x6d, 0xca, 0x6a, 0x46, - 0xac, 0x08, 0x1b, 0x35, 0x39, 0xd3, 0xd9, 0xce, 0x34, 0xe5, 0x6a, 0xbb, 0x81, 0x54, 0xe3, 0xc7, - 0xe3, 0x83, 0xed, 0x0d, 0xf3, 0xdf, 0xa3, 0xd6, 0x6d, 0x21, 0xb5, 0x12, 0xc2, 0xff, 0x1d, 0x1f, - 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x4f, 0x1a, 0x39, 0xd7, 0x06, 0x15, 0x00, 0x00, + // 1295 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xdf, 0x6f, 0xda, 0xd6, + 0x17, 0xc7, 0x40, 0x21, 0x39, 0xf4, 0x9b, 0x10, 0x93, 0xa4, 0xc4, 0x24, 0x98, 0xaf, 0x1f, 0x9a, + 0x28, 0x53, 0xa0, 0x49, 0x53, 0x4d, 0x8d, 0x26, 0x4d, 0x81, 0x51, 0x2d, 0xda, 0x92, 0x20, 0x43, + 0x26, 0x2d, 0x9b, 0x86, 0xc0, 0xdc, 0x12, 0x0b, 0xb0, 0x99, 0x6d, 0x68, 0xf9, 0x0f, 0xaa, 0x3c, + 0xf5, 0xb9, 0x52, 0xa4, 0x4e, 0x7b, 0x9a, 0xf6, 0xd0, 0xfd, 0x19, 0x7d, 0xec, 0xdb, 0xaa, 0x3d, + 0xa0, 0x29, 0x79, 0xd9, 0x33, 0x7f, 0xc1, 0xe4, 0xeb, 0x6b, 0x63, 0xc0, 0x56, 0x9c, 0x36, 0x49, + 0xf7, 0xe6, 0x7b, 0xcf, 0xe7, 0x9e, 0x73, 0xee, 0xe7, 0x7c, 0xee, 0x2f, 0xc3, 0xb2, 0x58, 0x15, + 0x32, 0x82, 0xac, 0xa0, 0x8c, 0x70, 0x52, 0x91, 0x24, 0xd4, 0xcc, 0x74, 0x37, 0x33, 0xda, 0xf3, + 0x74, 0x5b, 0x91, 0x35, 0x99, 0x8e, 0x89, 0x55, 0x21, 0xad, 0x5b, 0xd3, 0xc4, 0x9a, 0xee, 0x6e, + 0x32, 0xf3, 0x75, 0xb9, 0x2e, 0x63, 0x7b, 0x46, 0xff, 0x32, 0xa0, 0x0c, 0x3b, 0x74, 0xd4, 0x14, + 0x91, 0xa4, 0xe9, 0x7e, 0x8c, 0x2f, 0x02, 0xf8, 0xbf, 0x53, 0x24, 0xd3, 0x2d, 0x86, 0x70, 0xbf, + 0x50, 0x40, 0xef, 0xab, 0xf5, 0x9c, 0xd1, 0x79, 0xd8, 0x46, 0xd2, 0x9e, 0x24, 0x6a, 0xf4, 0x67, + 0x10, 0x6e, 0xcb, 0x8a, 0x56, 0x16, 0x6b, 0x71, 0x2a, 0x45, 0xad, 0x4d, 0x67, 0xe9, 0x41, 0x9f, + 0x9d, 0xe9, 0x55, 0x5a, 0xcd, 0x1d, 0x8e, 0x18, 0x38, 0x3e, 0xa4, 0x7f, 0xed, 0xd5, 0xe8, 0x2f, + 0x20, 0x4c, 0x9c, 0xc6, 0xfd, 0x29, 0x6a, 0x2d, 0xb2, 0xb5, 0x9c, 0x76, 0x98, 0x44, 0x9a, 0xc4, + 0xc8, 0x06, 0xdf, 0xf6, 0x59, 0x1f, 0x6f, 0x0e, 0xa1, 0x17, 0x21, 0xa4, 0x8a, 0x75, 0x09, 0x29, + 0xf1, 0x80, 0x1e, 0x89, 0x27, 0xad, 0x9d, 0xa9, 0x17, 0xaf, 0x59, 0xdf, 0x3f, 0xaf, 0x59, 0x1f, + 0xd7, 0x04, 0x66, 0x32, 0x45, 0x1e, 0xa9, 0x6d, 0x59, 0x52, 0x11, 0xbd, 0x0d, 0x40, 0x5c, 0x0d, + 0xb3, 0x5d, 0x18, 0xf4, 0xd9, 0x39, 0x23, 0xdb, 0xa1, 0x8d, 0xe3, 0xa7, 0x49, 0x63, 0xaf, 0x46, + 0xc7, 0x21, 0xdc, 0x45, 0x8a, 0x2a, 0xca, 0x12, 0xce, 0x79, 0x9a, 0x37, 0x9b, 0xdc, 0xfb, 0x00, + 0xcc, 0x8d, 0x86, 0x2b, 0x29, 0xbd, 0xab, 0x11, 0x52, 0x80, 0x58, 0x5b, 0x41, 0x5d, 0x51, 0xee, + 0xa8, 0x65, 0x5b, 0x6e, 0x38, 0x50, 0x36, 0x35, 0xe8, 0xb3, 0x0c, 0x19, 0x38, 0x09, 0xe2, 0xe2, + 0x14, 0x3f, 0x67, 0xf6, 0xe7, 0xac, 0x74, 0x6d, 0x14, 0x07, 0xae, 0x4e, 0x31, 0x0f, 0xf3, 0x82, + 0xdc, 0x91, 0x34, 0xa4, 0xb4, 0x2b, 0x8a, 0xd6, 0x2b, 0x9b, 0x33, 0x0f, 0xe2, 0x84, 0xd8, 0x41, + 0x9f, 0x4d, 0x10, 0xb2, 0x1c, 0x50, 0x1c, 0x1f, 0xb3, 0x77, 0x7f, 0x67, 0xf4, 0xea, 0xb4, 0xb7, + 0x15, 0x59, 0x7e, 0x5a, 0x16, 0x25, 0x51, 0x8b, 0xdf, 0x49, 0x51, 0x6b, 0x77, 0xed, 0xb4, 0x0f, + 0x6d, 0x1c, 0x3f, 0x8d, 0x1b, 0x58, 0x57, 0xc7, 0x70, 0xd7, 0xb0, 0x9c, 0x20, 0xb1, 0x7e, 0xa2, + 0xc5, 0x43, 0x78, 0x32, 0x8c, 0x6d, 0x32, 0x86, 0x7e, 0xbb, 0x9b, 0xe9, 0xaf, 0x31, 0x22, 0x9b, + 0xd0, 0xa7, 0x32, 0xe8, 0xb3, 0x31, 0xbb, 0x5f, 0x63, 0x34, 0xc7, 0x47, 0x70, 0xd3, 0x40, 0xda, + 0x84, 0x14, 0x76, 0x11, 0xd2, 0x23, 0x58, 0x9a, 0xa8, 0xac, 0xa5, 0x23, 0x9b, 0x22, 0xa8, 0x51, + 0x45, 0xfc, 0x39, 0xa1, 0x88, 0x5d, 0xa1, 0x71, 0x35, 0x45, 0x8c, 0x8a, 0xd4, 0xef, 0x51, 0xa4, + 0xc7, 0x70, 0x6f, 0xa4, 0x22, 0x36, 0x17, 0x78, 0xad, 0x64, 0xb9, 0x41, 0x9f, 0x4d, 0x3a, 0x94, + 0xce, 0xee, 0x6f, 0xc1, 0x6e, 0x19, 0x2a, 0xea, 0x26, 0x34, 0xb1, 0x09, 0x46, 0xa9, 0xcb, 0x9a, + 0xd2, 0x23, 0x92, 0x98, 0x1f, 0xf4, 0xd9, 0xa8, 0xbd, 0x74, 0x9a, 0xd2, 0xe3, 0xf8, 0x29, 0xfc, + 0xad, 0xaf, 0xab, 0x4f, 0x2b, 0x88, 0xc4, 0xb8, 0x20, 0x76, 0x85, 0x86, 0x29, 0x08, 0xee, 0x77, + 0x3f, 0x2c, 0x8c, 0x5a, 0x73, 0xb2, 0xf4, 0x54, 0x54, 0x5a, 0xb7, 0x51, 0x7a, 0x8b, 0xca, 0x8a, + 0xd0, 0xc0, 0xc5, 0x76, 0xa0, 0xb2, 0x22, 0x34, 0x4c, 0x2a, 0x75, 0x41, 0x8e, 0x53, 0x19, 0xbc, + 0x11, 0x2a, 0xef, 0xb8, 0x50, 0xc9, 0xc2, 0x8a, 0x23, 0x59, 0x16, 0x9d, 0xaf, 0x28, 0x88, 0x0d, + 0x11, 0xb9, 0xa6, 0xac, 0xa2, 0xab, 0x1f, 0x35, 0x1f, 0x46, 0xe6, 0xe5, 0x47, 0xcc, 0x0a, 0x24, + 0x1c, 0x72, 0xb3, 0x72, 0x7f, 0xe3, 0x87, 0xc5, 0x31, 0xfb, 0x2d, 0x6a, 0x61, 0x74, 0xab, 0x0d, + 0x7c, 0xe0, 0x56, 0x7b, 0xbb, 0x72, 0x48, 0x41, 0xd2, 0x99, 0x30, 0x8b, 0xd3, 0x97, 0x7e, 0xf8, + 0xdf, 0xbe, 0x5a, 0xe7, 0x91, 0xd0, 0x2d, 0x54, 0x84, 0x06, 0xd2, 0xe8, 0xc7, 0x10, 0x6a, 0xe3, + 0x2f, 0xcc, 0x64, 0x64, 0x2b, 0xe1, 0x78, 0xc6, 0x19, 0x60, 0x72, 0xc4, 0x91, 0x01, 0xf4, 0x13, + 0x88, 0x1a, 0xe9, 0x0a, 0x72, 0xab, 0x25, 0x6a, 0x2d, 0x24, 0x69, 0x98, 0xde, 0xbb, 0xd9, 0xc4, + 0xa0, 0xcf, 0xde, 0xb3, 0x4f, 0x68, 0x88, 0xe0, 0xf8, 0x59, 0xdc, 0x95, 0xb3, 0x7a, 0x26, 0x48, + 0x0b, 0xdc, 0x08, 0x69, 0x41, 0x17, 0xd2, 0x7e, 0xc2, 0x1b, 0xce, 0x90, 0x11, 0xeb, 0x6c, 0xfa, + 0x12, 0x42, 0x0a, 0x52, 0x3b, 0x4d, 0x83, 0x99, 0x99, 0xad, 0x55, 0x47, 0x66, 0x4c, 0x38, 0x8f, + 0xa1, 0xa5, 0x5e, 0x1b, 0xf1, 0x64, 0xd8, 0x4e, 0x50, 0x8f, 0xc1, 0xfd, 0xe5, 0x07, 0xd8, 0x57, + 0xeb, 0x25, 0xb1, 0x85, 0xe4, 0xce, 0xf5, 0xf0, 0xdd, 0x91, 0x14, 0x24, 0x20, 0xb1, 0x8b, 0x6a, + 0x6e, 0x7c, 0x0f, 0x11, 0x26, 0xdf, 0x47, 0x56, 0xcf, 0x8d, 0xf2, 0xfd, 0x0d, 0xd0, 0x12, 0x7a, + 0xae, 0x95, 0x55, 0xf4, 0x73, 0x07, 0x49, 0x02, 0x2a, 0x2b, 0x48, 0xe8, 0x62, 0xee, 0x83, 0xd9, + 0x95, 0x41, 0x9f, 0x5d, 0x32, 0x3c, 0x4c, 0x62, 0x38, 0x3e, 0xaa, 0x77, 0x16, 0x49, 0x9f, 0x5e, + 0x0f, 0x0f, 0x8a, 0xff, 0x01, 0x5f, 0xa4, 0x09, 0xb7, 0xd7, 0x5d, 0xb9, 0x57, 0xc6, 0x15, 0x84, + 0x78, 0x3f, 0x94, 0xf0, 0x8a, 0xfa, 0x2f, 0x14, 0xf0, 0x73, 0x88, 0x90, 0x65, 0xa5, 0x67, 0x44, + 0x36, 0xa7, 0xc5, 0x41, 0x9f, 0xa5, 0x47, 0xd6, 0x9c, 0x6e, 0xe4, 0x78, 0x63, 0x1b, 0x33, 0x72, + 0xbf, 0xc9, 0xed, 0xc9, 0xb9, 0xf2, 0x77, 0x3e, 0xb6, 0xf2, 0x21, 0x97, 0xca, 0x57, 0xf1, 0x2d, + 0x62, 0xb4, 0x36, 0xd7, 0x2d, 0x80, 0x3f, 0xfc, 0x58, 0x5e, 0xbb, 0x42, 0x43, 0x92, 0x9f, 0x35, + 0x51, 0xad, 0x8e, 0xf0, 0x7e, 0xf5, 0x11, 0x0a, 0x58, 0x83, 0xd9, 0xca, 0xa8, 0x37, 0x43, 0x00, + 0xfc, 0x78, 0xf7, 0xb0, 0xc6, 0xfa, 0xc0, 0x9a, 0x5b, 0x8d, 0xb1, 0xd1, 0xac, 0xf1, 0xae, 0xde, + 0xf8, 0xc4, 0x47, 0x90, 0x80, 0x9f, 0x8d, 0x63, 0x8c, 0x5d, 0x73, 0x5d, 0xd6, 0x7f, 0xa3, 0x80, + 0x9e, 0x04, 0xd1, 0x8f, 0x20, 0xc5, 0xe7, 0x8b, 0x85, 0xc3, 0x83, 0x62, 0xbe, 0xcc, 0xe7, 0x8b, + 0x47, 0xdf, 0x96, 0xca, 0xa5, 0xef, 0x0b, 0xf9, 0xf2, 0xd1, 0x41, 0xb1, 0x90, 0xcf, 0xed, 0x3d, + 0xd9, 0xcb, 0x7f, 0x15, 0xf5, 0x31, 0xb3, 0xa7, 0x67, 0xa9, 0x88, 0xad, 0x8b, 0x5e, 0x85, 0x25, + 0xc7, 0x61, 0x07, 0x87, 0x87, 0x85, 0x28, 0xc5, 0x4c, 0x9d, 0x9e, 0xa5, 0x82, 0xfa, 0x37, 0xbd, + 0x01, 0xcb, 0x8e, 0xc0, 0xe2, 0x51, 0x2e, 0x97, 0x2f, 0x16, 0xa3, 0x7e, 0x26, 0x72, 0x7a, 0x96, + 0x0a, 0x93, 0x26, 0x13, 0x7c, 0xf1, 0x6b, 0xd2, 0xb7, 0xf5, 0x66, 0x0a, 0x02, 0xfb, 0x6a, 0x9d, + 0x6e, 0xc0, 0xec, 0xf8, 0x7b, 0xdf, 0x79, 0xf6, 0x93, 0xaf, 0x6e, 0x26, 0xe3, 0x11, 0x68, 0xf1, + 0x7c, 0x02, 0x33, 0x63, 0x4f, 0xe9, 0xfb, 0x1e, 0x5c, 0x94, 0x94, 0x1e, 0x93, 0xf6, 0x86, 0x73, + 0x89, 0xa4, 0xdf, 0x88, 0xbd, 0x44, 0xda, 0x15, 0x1a, 0x9e, 0x22, 0xd9, 0x5e, 0x06, 0xb4, 0x06, + 0xb4, 0xc3, 0xab, 0x60, 0xdd, 0x83, 0x17, 0x82, 0x65, 0xb6, 0xbc, 0x63, 0xad, 0xa8, 0x12, 0x44, + 0x27, 0x2e, 0xcf, 0x6b, 0x97, 0xf8, 0xb1, 0x90, 0xcc, 0x03, 0xaf, 0x48, 0x2b, 0xde, 0x33, 0x88, + 0x39, 0x5e, 0x78, 0xbd, 0x38, 0x32, 0xe7, 0xf9, 0xf0, 0x0a, 0x60, 0x2b, 0xf0, 0x8f, 0x00, 0xb6, + 0x5b, 0x21, 0xe7, 0xe6, 0x62, 0x88, 0x61, 0xd6, 0x2f, 0xc7, 0x58, 0xde, 0x8b, 0x10, 0x36, 0x2f, + 0x40, 0xac, 0xdb, 0x30, 0x02, 0x60, 0x56, 0x2f, 0x01, 0xd8, 0xb5, 0x37, 0x76, 0x36, 0xdf, 0xbf, + 0x64, 0x28, 0xc1, 0xb9, 0x6b, 0xcf, 0xe5, 0x3c, 0x69, 0xc0, 0xec, 0xf8, 0x21, 0xe0, 0x9a, 0xe5, + 0x18, 0xd0, 0x7d, 0xf1, 0xba, 0x6c, 0x92, 0xd9, 0xe2, 0xdb, 0xf3, 0x24, 0xf5, 0xee, 0x3c, 0x49, + 0xfd, 0x7d, 0x9e, 0xa4, 0x5e, 0x5e, 0x24, 0x7d, 0xef, 0x2e, 0x92, 0xbe, 0xf7, 0x17, 0x49, 0xdf, + 0xf1, 0xe3, 0xba, 0xa8, 0x9d, 0x74, 0xaa, 0x69, 0x41, 0x6e, 0x65, 0x04, 0x59, 0x6d, 0xc9, 0x6a, + 0x46, 0xac, 0x0a, 0x1b, 0x75, 0x39, 0xd3, 0xdd, 0xce, 0xb4, 0xe4, 0x5a, 0xa7, 0x89, 0x54, 0xe3, + 0xd7, 0xe3, 0x83, 0xed, 0x0d, 0xf3, 0xef, 0xa3, 0xd6, 0x6b, 0x23, 0xb5, 0x1a, 0xc2, 0x7f, 0x1e, + 0x1f, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x58, 0xd3, 0x8a, 0x27, 0x08, 0x15, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 335998078b4..3cf28bed750 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -220,7 +220,7 @@ func (k Keeper) ChannelOpenTry(goCtx context.Context, msg *channeltypes.MsgChann } // Perform 04-channel verification - channelID, cap, err := k.ChannelKeeper.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, msg.PreviousChannelId, + channelID, cap, err := k.ChannelKeeper.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, portCap, msg.Channel.Counterparty, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, ) if err != nil { diff --git a/proto/ibc/core/channel/v1/tx.proto b/proto/ibc/core/channel/v1/tx.proto index 5e3ccf32ff0..75248aeb5b1 100644 --- a/proto/ibc/core/channel/v1/tx.proto +++ b/proto/ibc/core/channel/v1/tx.proto @@ -79,9 +79,8 @@ message MsgChannelOpenTry { option (gogoproto.goproto_getters) = false; string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - // in the case of crossing hello's, when both chains call OpenInit, we need - // the channel identifier of the previous channel in state INIT - string previous_channel_id = 2 [(gogoproto.moretags) = "yaml:\"previous_channel_id\""]; + // Deprecated: this field is unused. Crossing hello's are no longer supported in core IBC. + string previous_channel_id = 2 [deprecated = true, (gogoproto.moretags) = "yaml:\"previous_channel_id\""]; // NOTE: the version field within the channel has been deprecated. Its value will be ignored by core IBC. Channel channel = 3 [(gogoproto.nullable) = false]; string counterparty_version = 4 [(gogoproto.moretags) = "yaml:\"counterparty_version\""]; diff --git a/testing/coordinator.go b/testing/coordinator.go index dde3eb56b1a..6aaf2ab748f 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -212,24 +212,3 @@ func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error { return path.EndpointB.UpdateClient() } - -// ChanOpenInitOnBothChains initializes a channel on the source chain and counterparty chain -// with the state INIT using the OpenInit handshake call. -func (coord *Coordinator) ChanOpenInitOnBothChains(path *Path) error { - // NOTE: only creation of a capability for a transfer or mock port is supported - // Other applications must bind to the port in InitGenesis or modify this code. - - if err := path.EndpointA.ChanOpenInit(); err != nil { - return err - } - - if err := path.EndpointB.ChanOpenInit(); err != nil { - return err - } - - if err := path.EndpointA.UpdateClient(); err != nil { - return err - } - - return path.EndpointB.UpdateClient() -} From c449d858e73e3e9de8ded269ebb11d62a8b96d54 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 12 Jul 2022 09:52:52 +0200 Subject: [PATCH 208/275] docs: update roadmap (#1678) * update roadmap * update roadmap * Update roadmap.md Co-authored-by: Carlos Rodriguez --- docs/roadmap/roadmap.md | 53 +++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/docs/roadmap/roadmap.md b/docs/roadmap/roadmap.md index 3ddc67399c7..5385e8a0b38 100644 --- a/docs/roadmap/roadmap.md +++ b/docs/roadmap/roadmap.md @@ -4,55 +4,46 @@ order: 1 # Roadmap ibc-go -_Lastest update: March 31, 2022_ +_Lastest update: July 7, 2022_ This document endeavours to inform the wider IBC community about plans and priorities for work on ibc-go by the team at Interchain GmbH. It is intended to broadly inform all users of ibc-go, including developers and operators of IBC, relayer, chain and wallet applications. This roadmap should be read as a high-level guide, rather than a commitment to schedules and deliverables. The degree of specificity is inversely proportional to the timeline. We will update this document periodically to reflect the status and plans. -## Q2 - 2022 +## Q3 - 2022 At a high level we will focus on: -- Finishing the implementation of [relayer incentivisation](https://github.com/orgs/cosmos/projects/7/views/8). -- Finishing the [refactoring of 02-client](https://github.com/cosmos/ibc-go/milestone/16). -- Finishing the upgrade to Cosmos SDK v0.46 and Tendermint v0.35. -- Implementing and testing the changes needed to support the [transtion to SMT storage](https://github.com/cosmos/ibc-go/milestone/21) in the Cosmos SDK. -- Desiging the implementation and scoping the engineering work for [channel upgradability](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md). -- Improving the project's documentation and writing guides for [light client](https://github.com/cosmos/ibc-go/issues/59) and middleware implementation. -- Working on [core backlog issues](https://github.com/cosmos/ibc-go/milestone/8). -- Spending time on expanding and deepening our knowledge of IBC, but also other parts of the Cosmos stack. -- And last, but not least, onboarding new members to the team. +- Releasing [v4.0.0](https://github.com/cosmos/ibc-go/milestone/26), which includes the ICS-29 Fee Middleware module. +- Finishing and releasing the [refactoring of 02-client](https://github.com/cosmos/ibc-go/milestone/16). This refactor will make the development of light clients easier. +- Finishing and releasing the upgrade to Cosmos SDK v0.46. +- Starting the implementation of channel upgradability (see [epic](https://github.com/cosmos/ibc-go/issues/1599) and [alpha milestone](https://github.com/cosmos/ibc-go/milestone/29)) with the goal of cutting an alpha1 pre-release by the end of the quarter. Channel upgradability will allow chains to renegotiate an existing channel to take advantage of new features without having to create a new channel, thus preserving all existing packet state processed on the channel. +- Implementing the new [`ORDERED_ALLOW_TIMEOUT` channel type](https://github.com/cosmos/ibc-go/milestone/31) and hopefully releasing it as well. This new channel type will allow packets on an ordered channel to timeout without causing the closure of the channel. +- Adding [automated e2e tests](https://github.com/cosmos/ibc-go/milestone/32) to the repo's CI. +- Writing the [light client implementation guide](https://github.com/cosmos/ibc-go/issues/59). +- Working on [core backlog issues](https://github.com/cosmos/ibc-go/milestone/28). +- Depending on the timeline of the Cosmos SDK, implementing and testing the changes needed to support the [transtion to SMT storage](https://github.com/cosmos/ibc-go/milestone/21). + +We have also received a lot of feedback to improve Interchain Accounts and we might also work on a few things, but will depend on priorities and availability. For a detail view of each iteration's planned work, please check out our [project board](https://github.com/orgs/cosmos/projects/7). ### Release schedule -#### **April** - -In the first half of the month we will probably cut: +#### **July** -- Alpha/beta pre-releases with the upgrade to SDK 0.46 and Tendermint v0.35. -- [Alpha](https://github.com/cosmos/ibc-go/milestone/5) pre-release with the implementation of relayer incentivisation. +We will probably cut at least one more release candidate of v4.0.0 before the final release, which should happen around the end of the month. -In the second half, and depending on the date of the final release of Cosmos SDK 0.46, we will probably cut the final release with the upgrade to SDK 0.46 and Tendermint v0.35, and also a [beta](https://github.com/cosmos/ibc-go/milestone/23) pre-release with the implementation of relayer incentivisation. +For the Rho upgrade of the Cosmos Hub we will also release a new minor version of v3 with SDK 0.46. -In the second half of the month we also plan to do a second internal audit of the implementation of relayer incentivisation, and issues will most likely will be created from the audit. Depending on the nature and type of the issues we create, those would be released in a second beta pre-release or in a [release candidate](https://github.com/cosmos/ibc-go/milestone/24). +#### **August** -#### **May** +In the first half we will probably start cutting release candidates for the 02-client refactor. Final release would most likely come out at the end of the month or beginning of September. -In the first half we will probably start cutting release candidates with relayer incentivisation and the 02-client refactor. Final release would most likely come out at the end of the month or beginning of June. +#### **September** -#### **June** +We might cut some pre-releases for the new channel type, and by the end of the month we expect to cut the first alpha pre-release for channel upgradability. -We will probably cut at the end of the month or beginning of Q3 patch or minor releases on all the supported release lines with the [small features and core improvements](https://github.com/cosmos/ibc-go/milestone/8) that we work on during the quarter. - -## Q3 - 2022 - -We will most likely start the implementation of [channel upgradability](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md). At the end of Q2 or maybe beginning of Q3 we might also work on designing the implementation and scoping the engineering work to add support for [ordered channels that can timeout](https://github.com/cosmos/ibc/pull/636), and we could potentially work on this feature also in Q3. - -We will also probably do an audit of the implementation of the [CCV application](https://github.com/cosmos/interchain-security/tree/main/x/ccv) for Interchain Security. - -### Release schedule +## Q4 - 2022 -In this quarter we will make the final release to support the migration to SMT storage. \ No newline at end of file +We will continue the implementation and cut the final release of [channel upgradability](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics/UPGRADES.md). At the end of Q3 or maybe beginning of Q4 we might also work on designing the implementation and scoping the engineering work to add support for [multihop channels](https://github.com/cosmos/ibc/pull/741/files), so that we could start the implementation of this feature during Q4 (but this is still be decided). From 9aab42dca1924868c09c01af173fddf5d05e0b52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Jul 2022 12:23:34 +0200 Subject: [PATCH 209/275] refactor: remove crossing hellos from 03-connection (#1672) * remove crossing hello check from ConnOpenTry and ConnOpenAck * remove unnecessary test cases and fix build * fix tests and add migration docs * fix connection version check in conn open ack * add changelog entry * Update modules/core/03-connection/keeper/handshake.go Co-authored-by: Aditya * remove unnecessary testing function * improve migration documentation as per review suggestion Co-authored-by: Aditya --- CHANGELOG.md | 1 + docs/ibc/proto-docs.md | 2 +- docs/migrations/v3-to-v4.md | 7 +- .../core/03-connection/keeper/handshake.go | 79 ++---------- .../03-connection/keeper/handshake_test.go | 70 +--------- modules/core/03-connection/types/tx.pb.go | 122 +++++++++--------- modules/core/03-connection/types/version.go | 4 +- .../core/03-connection/types/version_test.go | 2 +- modules/core/keeper/msg_server.go | 2 +- proto/ibc/core/connection/v1/tx.proto | 15 +-- testing/coordinator.go | 18 --- 11 files changed, 99 insertions(+), 223 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1fdccd2092..db771acd750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (modules/core/03-connection) [\#1672](https://github.com/cosmos/ibc-go/pull/1672) Remove crossing hellos from connection handshakes. The `PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated. * (modules/core/04-channel) [\#1317](https://github.com/cosmos/ibc-go/pull/1317) Remove crossing hellos from channel handshakes. The `PreviousChannelId` in `MsgChannelOpenTry` has been deprecated. * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) The `OnChanOpenInit` application callback now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). diff --git a/docs/ibc/proto-docs.md b/docs/ibc/proto-docs.md index ced55cfbc75..c612a0180b3 100644 --- a/docs/ibc/proto-docs.md +++ b/docs/ibc/proto-docs.md @@ -4244,7 +4244,7 @@ connection on Chain B. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `client_id` | [string](#string) | | | -| `previous_connection_id` | [string](#string) | | in the case of crossing hello's, when both chains call OpenInit, we need the connection identifier of the previous connection in state INIT | +| `previous_connection_id` | [string](#string) | | **Deprecated.** Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. | | `client_state` | [google.protobuf.Any](#google.protobuf.Any) | | | | `counterparty` | [Counterparty](#ibc.core.connection.v1.Counterparty) | | | | `delay_period` | [uint64](#uint64) | | | diff --git a/docs/migrations/v3-to-v4.md b/docs/migrations/v3-to-v4.md index 9d6a1fb3f31..e88444163c1 100644 --- a/docs/migrations/v3-to-v4.md +++ b/docs/migrations/v3-to-v4.md @@ -22,6 +22,11 @@ No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-g ## IBC Apps +### ICS03 - Connection + +Crossing hellos have been removed from 03-connection handshake negotiation. +`PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated and is no longer used by core IBC. + ### ICS04 - Channel The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly. @@ -100,4 +105,4 @@ if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in. -Crossing hellos are no longer supported by core IBC. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). +Crossing hellos are no longer supported by core IBC for 03-connection and 04-channel. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM). diff --git a/modules/core/03-connection/keeper/handshake.go b/modules/core/03-connection/keeper/handshake.go index 9f809a47a25..faca5c0f74c 100644 --- a/modules/core/03-connection/keeper/handshake.go +++ b/modules/core/03-connection/keeper/handshake.go @@ -1,12 +1,9 @@ package keeper import ( - "bytes" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/gogo/protobuf/proto" clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" @@ -28,7 +25,7 @@ func (k Keeper) ConnOpenInit( ) (string, error) { versions := types.GetCompatibleVersions() if version != nil { - if !types.IsSupportedVersion(version) { + if !types.IsSupportedVersion(types.GetCompatibleVersions(), version) { return "", sdkerrors.Wrap(types.ErrInvalidVersion, "version is not supported") } @@ -63,7 +60,6 @@ func (k Keeper) ConnOpenInit( // - Identifiers are checked on msg validation func (k Keeper) ConnOpenTry( ctx sdk.Context, - previousConnectionID string, // previousIdentifier counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier delayPeriod uint64, clientID string, // clientID of chainA @@ -75,44 +71,9 @@ 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) { - var ( - connectionID string - previousConnection types.ConnectionEnd - found bool - ) - - // empty connection identifier indicates continuing a previous connection handshake - if previousConnectionID != "" { - // ensure that the previous connection exists - previousConnection, found = k.GetConnection(ctx, previousConnectionID) - if !found { - return "", sdkerrors.Wrapf(types.ErrConnectionNotFound, "previous connection does not exist for supplied previous connectionID %s", previousConnectionID) - } - - // ensure that the existing connection's - // counterparty is chainA and connection is on INIT stage. - // Check that existing connection versions for initialized connection is equal to compatible - // versions for this chain. - // ensure that existing connection's delay period is the same as desired delay period. - if !(previousConnection.Counterparty.ConnectionId == "" && - bytes.Equal(previousConnection.Counterparty.Prefix.Bytes(), counterparty.Prefix.Bytes()) && - previousConnection.ClientId == clientID && - previousConnection.Counterparty.ClientId == counterparty.ClientId && - previousConnection.DelayPeriod == delayPeriod) { - return "", sdkerrors.Wrap(types.ErrInvalidConnection, "connection fields mismatch previous connection fields") - } - if !(previousConnection.State == types.INIT) { - return "", sdkerrors.Wrapf(types.ErrInvalidConnectionState, "previous connection state is in state %s, expected INIT", previousConnection.State) - } - - // continue with previous connection - connectionID = previousConnectionID - - } else { - // generate a new connection - connectionID = k.GenerateConnectionIdentifier(ctx) - } + // generate a new connection + connectionID := k.GenerateConnectionIdentifier(ctx) selfHeight := clienttypes.GetSelfHeight(ctx) if consensusHeight.GTE(selfHeight) { @@ -139,15 +100,10 @@ func (k Keeper) ConnOpenTry( expectedCounterparty := types.NewCounterparty(clientID, "", commitmenttypes.NewMerklePrefix(prefix.Bytes())) expectedConnection := types.NewConnectionEnd(types.INIT, counterparty.ClientId, expectedCounterparty, types.ExportedVersionsToProto(counterpartyVersions), delayPeriod) - supportedVersions := types.GetCompatibleVersions() - if len(previousConnection.Versions) != 0 { - supportedVersions = previousConnection.GetVersions() - } - // chain B picks a version from Chain A's available versions that is compatible // with Chain B's supported IBC versions. PickVersion will select the intersection // of the supported versions and the counterparty versions. - version, err := types.PickVersion(supportedVersions, counterpartyVersions) + version, err := types.PickVersion(types.GetCompatibleVersions(), counterpartyVersions) if err != nil { return "", err } @@ -181,7 +137,7 @@ func (k Keeper) ConnOpenTry( } k.SetConnection(ctx, connectionID, connection) - k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", previousConnection.State.String(), "new-state", "TRYOPEN") + k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", "NONE", "new-state", "TRYOPEN") defer func() { telemetry.IncrCounter(1, "ibc", "connection", "open-try") @@ -223,28 +179,19 @@ func (k Keeper) ConnOpenAck( return sdkerrors.Wrap(types.ErrConnectionNotFound, connectionID) } - // Verify the provided version against the previously set connection state - switch { - // connection on ChainA must be in INIT or TRYOPEN - case connection.State != types.INIT && connection.State != types.TRYOPEN: - return sdkerrors.Wrapf( - types.ErrInvalidConnectionState, - "connection state is not INIT or TRYOPEN (got %s)", connection.State.String(), - ) - - // if the connection is INIT then the provided version must be supproted - case connection.State == types.INIT && !types.IsSupportedVersion(version): + // verify the previously set connection state + if connection.State != types.INIT { return sdkerrors.Wrapf( types.ErrInvalidConnectionState, - "connection state is in INIT but the provided version is not supported %s", version, + "connection state is not INIT (got %s)", connection.State.String(), ) + } - // if the connection is in TRYOPEN then the version must be the only set version in the - // retreived connection state. - case connection.State == types.TRYOPEN && (len(connection.Versions) != 1 || !proto.Equal(connection.Versions[0], version)): + // ensure selected version is supported + if !types.IsSupportedVersion(types.ProtoVersionsToExported(connection.Versions), version) { return sdkerrors.Wrapf( types.ErrInvalidConnectionState, - "connection state is in TRYOPEN but the provided version (%s) is not set in the previous connection versions %s", version, connection.Versions, + "the counterparty selected version %s is not supported by versions selected on INIT", version, ) } @@ -283,7 +230,7 @@ func (k Keeper) ConnOpenAck( return err } - k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", connection.State.String(), "new-state", "OPEN") + k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", "INIT", "new-state", "OPEN") defer func() { telemetry.IncrCounter(1, "ibc", "connection", "open-ack") diff --git a/modules/core/03-connection/keeper/handshake_test.go b/modules/core/03-connection/keeper/handshake_test.go index 5f322e4e213..d82a2cf22f5 100644 --- a/modules/core/03-connection/keeper/handshake_test.go +++ b/modules/core/03-connection/keeper/handshake_test.go @@ -80,12 +80,11 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { // connection on chainA is INIT func (suite *KeeperTestSuite) TestConnOpenTry() { var ( - path *ibctesting.Path - delayPeriod uint64 - previousConnectionID string - versions []exported.Version - consensusHeight exported.Height - counterpartyClient exported.ClientState + path *ibctesting.Path + delayPeriod uint64 + versions []exported.Version + consensusHeight exported.Height + counterpartyClient exported.ClientState ) testCases := []struct { @@ -100,15 +99,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { // retrieve client state of chainA to pass as counterpartyClient counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) }, true}, - {"success with crossing hellos", func() { - err := suite.coordinator.ConnOpenInitOnBothChains(path) - suite.Require().NoError(err) - - // retrieve client state of chainA to pass as counterpartyClient - counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - - previousConnectionID = path.EndpointB.ConnectionID - }, true}, {"success with delay period", func() { err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) @@ -227,8 +217,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { // retrieve client state of chainA to pass as counterpartyClient counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - - previousConnectionID = path.EndpointB.ConnectionID }, false}, {"invalid previous connection has invalid versions", func() { // open init chainA @@ -253,8 +241,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { // retrieve client state of chainA to pass as counterpartyClient counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - - previousConnectionID = path.EndpointB.ConnectionID }, false}, } @@ -265,7 +251,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { suite.SetupTest() // reset consensusHeight = clienttypes.ZeroHeight() // must be explicitly changed in malleate versions = types.GetCompatibleVersions() // must be explicitly changed in malleate - previousConnectionID = "" path = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) @@ -292,7 +277,7 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { proofClient, _ := suite.chainA.QueryProof(clientKey) connectionID, err := suite.chainB.App.GetIBCKeeper().ConnectionKeeper.ConnOpenTry( - suite.chainB.GetContext(), previousConnectionID, counterparty, delayPeriod, path.EndpointB.ClientID, counterpartyClient, + suite.chainB.GetContext(), counterparty, delayPeriod, path.EndpointB.ClientID, counterpartyClient, versions, proofInit, proofClient, proofConsensus, proofHeight, consensusHeight, ) @@ -333,27 +318,6 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { // retrieve client state of chainB to pass as counterpartyClient counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID) }, true}, - {"success from tryopen", func() { - // chainA is in TRYOPEN, chainB is in TRYOPEN - err := path.EndpointB.ConnOpenInit() - suite.Require().NoError(err) - - err = path.EndpointA.ConnOpenTry() - suite.Require().NoError(err) - - // set chainB to TRYOPEN - connection := path.EndpointB.GetConnection() - connection.State = types.TRYOPEN - connection.Counterparty.ConnectionId = path.EndpointA.ConnectionID - suite.chainB.App.GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID, connection) - // update path.EndpointB.ClientID so state change is committed - path.EndpointB.UpdateClient() - - path.EndpointA.UpdateClient() - - // retrieve client state of chainB to pass as counterpartyClient - counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID) - }, true}, {"invalid counterparty client", func() { err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) @@ -440,28 +404,6 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { version = types.NewVersion("2.0", nil) }, false}, - {"connection is in TRYOPEN but the set version in the connection is invalid", func() { - // chainA is in TRYOPEN, chainB is in TRYOPEN - err := path.EndpointB.ConnOpenInit() - suite.Require().NoError(err) - - err = path.EndpointA.ConnOpenTry() - suite.Require().NoError(err) - - // set chainB to TRYOPEN - connection := path.EndpointB.GetConnection() - connection.State = types.TRYOPEN - suite.chainB.App.GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID, connection) - - // update path.EndpointB.ClientID so state change is committed - path.EndpointB.UpdateClient() - path.EndpointA.UpdateClient() - - // retrieve client state of chainB to pass as counterpartyClient - counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID) - - version = types.NewVersion("2.0", nil) - }, false}, {"incompatible IBC versions", func() { err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) diff --git a/modules/core/03-connection/types/tx.pb.go b/modules/core/03-connection/types/tx.pb.go index a37505743fb..4862d905716 100644 --- a/modules/core/03-connection/types/tx.pb.go +++ b/modules/core/03-connection/types/tx.pb.go @@ -115,9 +115,8 @@ var xxx_messageInfo_MsgConnectionOpenInitResponse proto.InternalMessageInfo // connection on Chain B. type MsgConnectionOpenTry struct { ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"` - // in the case of crossing hello's, when both chains call OpenInit, we need - // the connection identifier of the previous connection in state INIT - PreviousConnectionId string `protobuf:"bytes,2,opt,name=previous_connection_id,json=previousConnectionId,proto3" json:"previous_connection_id,omitempty" yaml:"previous_connection_id"` + // Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. + PreviousConnectionId string `protobuf:"bytes,2,opt,name=previous_connection_id,json=previousConnectionId,proto3" json:"previous_connection_id,omitempty" yaml:"previous_connection_id"` // Deprecated: Do not use. ClientState *types.Any `protobuf:"bytes,3,opt,name=client_state,json=clientState,proto3" json:"client_state,omitempty" yaml:"client_state"` Counterparty Counterparty `protobuf:"bytes,4,opt,name=counterparty,proto3" json:"counterparty"` DelayPeriod uint64 `protobuf:"varint,5,opt,name=delay_period,json=delayPeriod,proto3" json:"delay_period,omitempty" yaml:"delay_period"` @@ -388,65 +387,66 @@ func init() { func init() { proto.RegisterFile("ibc/core/connection/v1/tx.proto", fileDescriptor_5d00fde5fc97399e) } var fileDescriptor_5d00fde5fc97399e = []byte{ - // 927 bytes of a gzipped FileDescriptorProto + // 929 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x31, 0x73, 0xe3, 0x44, - 0x14, 0xb6, 0x62, 0x27, 0xb1, 0xd7, 0x86, 0xbb, 0x5b, 0x9c, 0x44, 0x98, 0x3b, 0xcb, 0xa7, 0x81, - 0x21, 0x05, 0x91, 0xce, 0x77, 0x61, 0x06, 0x32, 0x50, 0xc4, 0x6e, 0x48, 0x71, 0x70, 0x23, 0x6e, - 0x8e, 0x99, 0x6b, 0x3c, 0xf6, 0x7a, 0xa3, 0xec, 0xd8, 0xd6, 0x6a, 0xb4, 0xb2, 0x41, 0xb4, 0x34, - 0x0c, 0x15, 0x0d, 0xfd, 0xfd, 0x07, 0xfe, 0xc4, 0x95, 0x57, 0x52, 0x69, 0x20, 0x69, 0xa8, 0xd5, - 0xd1, 0x31, 0xda, 0x95, 0xe4, 0xb5, 0x23, 0x0f, 0x31, 0xce, 0x75, 0xfb, 0xf6, 0x7d, 0xef, 0xbd, - 0xdd, 0xf7, 0xbe, 0x6f, 0x67, 0x81, 0x46, 0x06, 0xc8, 0x44, 0xd4, 0xc3, 0x26, 0xa2, 0x8e, 0x83, - 0x91, 0x4f, 0xa8, 0x63, 0xce, 0xda, 0xa6, 0xff, 0x83, 0xe1, 0x7a, 0xd4, 0xa7, 0x70, 0x9f, 0x0c, - 0x90, 0x11, 0x03, 0x8c, 0x39, 0xc0, 0x98, 0xb5, 0x1b, 0x75, 0x9b, 0xda, 0x94, 0x43, 0xcc, 0x78, - 0x25, 0xd0, 0x8d, 0xf7, 0x6d, 0x4a, 0xed, 0x31, 0x36, 0xb9, 0x35, 0x98, 0x9e, 0x9b, 0x7d, 0x27, - 0x48, 0x5c, 0x52, 0xa5, 0x31, 0xc1, 0x8e, 0x1f, 0x57, 0x11, 0xab, 0x04, 0xf0, 0xf1, 0x8a, 0xa3, - 0x48, 0x75, 0x39, 0x50, 0xff, 0x7d, 0x0b, 0xec, 0x3d, 0x65, 0x76, 0x37, 0xdb, 0xff, 0xc6, 0xc5, - 0xce, 0x99, 0x43, 0x7c, 0xd8, 0x06, 0x15, 0x91, 0xb2, 0x47, 0x86, 0xaa, 0xd2, 0x52, 0x0e, 0x2b, - 0x9d, 0x7a, 0x14, 0x6a, 0x77, 0x83, 0xfe, 0x64, 0x7c, 0xa2, 0x67, 0x2e, 0xdd, 0x2a, 0x8b, 0xf5, - 0xd9, 0x10, 0x7e, 0x0d, 0x6a, 0x88, 0x4e, 0x1d, 0x1f, 0x7b, 0x6e, 0xdf, 0xf3, 0x03, 0x75, 0xab, - 0xa5, 0x1c, 0x56, 0x1f, 0x7f, 0x68, 0xe4, 0x5f, 0xdb, 0xe8, 0x4a, 0xd8, 0x4e, 0xe9, 0x75, 0xa8, - 0x15, 0xac, 0x85, 0x78, 0xf8, 0x39, 0xd8, 0x9d, 0x61, 0x8f, 0x11, 0xea, 0xa8, 0x45, 0x9e, 0x4a, - 0x5b, 0x95, 0xea, 0x85, 0x80, 0x59, 0x29, 0x1e, 0x9e, 0x80, 0xda, 0x10, 0x8f, 0xfb, 0x41, 0xcf, - 0xc5, 0x1e, 0xa1, 0x43, 0xb5, 0xd4, 0x52, 0x0e, 0x4b, 0x9d, 0x83, 0x28, 0xd4, 0xde, 0x13, 0x17, - 0x90, 0xbd, 0xba, 0x55, 0xe5, 0xe6, 0x33, 0x6e, 0xc1, 0x7d, 0xb0, 0xc3, 0x88, 0xed, 0x60, 0x4f, - 0xdd, 0x8e, 0xaf, 0x6d, 0x25, 0xd6, 0x49, 0xf9, 0xe7, 0x57, 0x5a, 0xe1, 0xef, 0x57, 0x5a, 0x41, - 0xd7, 0xc0, 0x83, 0xdc, 0xa6, 0x59, 0x98, 0xb9, 0xd4, 0x61, 0x58, 0xff, 0x6d, 0x17, 0xd4, 0xaf, - 0x21, 0x9e, 0x7b, 0xc1, 0xff, 0xe9, 0xea, 0x77, 0x60, 0xdf, 0xf5, 0xf0, 0x8c, 0xd0, 0x29, 0xeb, - 0xcd, 0x6f, 0x1d, 0xc7, 0x6f, 0xf1, 0xf8, 0x87, 0x51, 0xa8, 0x3d, 0x10, 0xf1, 0xf9, 0x38, 0xdd, - 0xaa, 0xa7, 0x8e, 0xf9, 0x81, 0xce, 0x86, 0xf0, 0x19, 0xa8, 0x25, 0x05, 0x99, 0xdf, 0xf7, 0x71, - 0xd2, 0xe3, 0xba, 0x21, 0x78, 0x67, 0xa4, 0xbc, 0x33, 0x4e, 0x9d, 0x40, 0xee, 0x9c, 0x1c, 0xa3, - 0x5b, 0x55, 0x61, 0x7e, 0x1b, 0x5b, 0xd7, 0x08, 0x50, 0xda, 0x90, 0x00, 0xcb, 0x53, 0xdc, 0x5e, - 0x63, 0x8a, 0x33, 0xb0, 0x27, 0xe7, 0xea, 0x25, 0xcc, 0x60, 0xea, 0x4e, 0xab, 0x78, 0x03, 0x2a, - 0x75, 0x5a, 0x51, 0xa8, 0xdd, 0x4f, 0x6e, 0x9c, 0x97, 0x47, 0xb7, 0xea, 0xf2, 0x7e, 0x12, 0xc6, - 0xe0, 0x4b, 0x50, 0x73, 0x3d, 0x4a, 0xcf, 0x7b, 0x17, 0x98, 0xd8, 0x17, 0xbe, 0xba, 0xcb, 0x7b, - 0xd0, 0x90, 0xca, 0x09, 0xa1, 0xce, 0xda, 0xc6, 0x57, 0x1c, 0xd1, 0xf9, 0x20, 0xbe, 0xf9, 0xfc, - 0x4e, 0x72, 0xb4, 0x6e, 0x55, 0xb9, 0x29, 0x90, 0xf0, 0x18, 0x00, 0xe1, 0x25, 0x0e, 0xf1, 0xd5, - 0x72, 0x4b, 0x39, 0xac, 0x75, 0xf6, 0xa2, 0x50, 0xbb, 0x27, 0x47, 0xc6, 0x3e, 0xdd, 0xaa, 0x70, - 0x83, 0x2b, 0xf9, 0x24, 0x3d, 0x91, 0xa8, 0xac, 0x56, 0x78, 0xdc, 0xc1, 0x72, 0x45, 0xe1, 0x4d, - 0x2b, 0x76, 0xb9, 0x05, 0xbb, 0xe0, 0x4e, 0xe2, 0x8d, 0x79, 0xed, 0xb0, 0x29, 0x53, 0x01, 0x0f, - 0x6f, 0x44, 0xa1, 0xb6, 0xbf, 0x10, 0x9e, 0x02, 0x74, 0xeb, 0x5d, 0x91, 0x21, 0xdd, 0x80, 0xe7, - 0xe0, 0x6e, 0xe6, 0x4d, 0xdb, 0x52, 0xfd, 0xcf, 0xb6, 0x68, 0x49, 0x5b, 0x0e, 0xd2, 0x21, 0x2c, - 0x66, 0xd0, 0xad, 0x3b, 0xd9, 0x56, 0xd2, 0x9e, 0xb9, 0x70, 0x6b, 0x2b, 0x84, 0xdb, 0x04, 0xf7, - 0xf3, 0x64, 0x99, 0xe9, 0xf6, 0xaf, 0xed, 0x1c, 0xdd, 0x9e, 0xa2, 0x11, 0xfc, 0x12, 0xbc, 0xb3, - 0xa8, 0x3d, 0xa1, 0x5d, 0x35, 0x0a, 0xb5, 0x7a, 0x76, 0x3e, 0x59, 0x72, 0x35, 0x24, 0x4b, 0x0d, - 0x81, 0xc6, 0x02, 0x89, 0xf2, 0x74, 0xfc, 0x51, 0x14, 0x6a, 0x0f, 0x73, 0x08, 0xb7, 0x94, 0x58, - 0x95, 0x9d, 0x0b, 0x7a, 0xde, 0xe0, 0xb9, 0x5c, 0x7e, 0x0a, 0x4a, 0x1b, 0x3f, 0x05, 0xcb, 0x32, - 0xd8, 0xbe, 0x45, 0x19, 0xb4, 0x81, 0x60, 0x77, 0xcf, 0xf7, 0x02, 0x75, 0x87, 0xd3, 0x51, 0x7a, - 0x44, 0x33, 0x97, 0x6e, 0x95, 0xf9, 0x3a, 0x7e, 0x77, 0x97, 0x35, 0xb0, 0xbb, 0x99, 0x06, 0xca, - 0xb7, 0xa2, 0x81, 0xca, 0x5b, 0xd5, 0x00, 0x58, 0x43, 0x03, 0xa7, 0x68, 0x94, 0x69, 0xe0, 0x97, - 0x2d, 0xa0, 0x5e, 0x03, 0x74, 0xa9, 0x73, 0x4e, 0xbc, 0xc9, 0xa6, 0x3a, 0xc8, 0x26, 0xd7, 0x47, - 0x23, 0x4e, 0xfb, 0x9c, 0xc9, 0xf5, 0xd1, 0x28, 0x9d, 0x5c, 0xac, 0xbc, 0x65, 0x22, 0x15, 0x6f, - 0x91, 0x48, 0xf3, 0x66, 0x95, 0x56, 0x34, 0x4b, 0x07, 0xad, 0x55, 0xbd, 0x48, 0x1b, 0xf6, 0xf8, - 0x9f, 0x22, 0x28, 0x3e, 0x65, 0x36, 0xfc, 0x11, 0xc0, 0x9c, 0x7f, 0xd4, 0xd1, 0x2a, 0x11, 0xe6, - 0xfe, 0x20, 0x1a, 0x9f, 0xae, 0x05, 0x4f, 0xcf, 0x00, 0xbf, 0x07, 0xf7, 0xae, 0x7f, 0x36, 0x3e, - 0xb9, 0x71, 0xae, 0xe7, 0x5e, 0xd0, 0x38, 0x5e, 0x07, 0xbd, 0xba, 0x70, 0x3c, 0xb3, 0x9b, 0x17, - 0x3e, 0x45, 0xa3, 0x35, 0x0a, 0x4b, 0x34, 0x85, 0x3f, 0x29, 0x60, 0x2f, 0x9f, 0xa3, 0x8f, 0x6e, - 0x9c, 0x2f, 0x89, 0x68, 0x7c, 0xb6, 0x6e, 0x44, 0x7a, 0x8a, 0xce, 0x8b, 0xd7, 0x97, 0x4d, 0xe5, - 0xcd, 0x65, 0x53, 0xf9, 0xf3, 0xb2, 0xa9, 0xfc, 0x7a, 0xd5, 0x2c, 0xbc, 0xb9, 0x6a, 0x16, 0xfe, - 0xb8, 0x6a, 0x16, 0x5e, 0x7e, 0x61, 0x13, 0xff, 0x62, 0x3a, 0x30, 0x10, 0x9d, 0x98, 0x88, 0xb2, - 0x09, 0x65, 0x26, 0x19, 0xa0, 0x23, 0x9b, 0x9a, 0xb3, 0x63, 0x73, 0x42, 0x87, 0xd3, 0x31, 0x66, - 0xe2, 0x8b, 0xfe, 0xe8, 0xc9, 0x91, 0xf4, 0x4b, 0xf7, 0x03, 0x17, 0xb3, 0xc1, 0x0e, 0x7f, 0x72, - 0x9f, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x63, 0x2e, 0xb2, 0x54, 0x0c, 0x00, 0x00, + 0x14, 0xb6, 0x62, 0x27, 0xb1, 0xd7, 0x86, 0xbb, 0x5b, 0x9c, 0x44, 0x88, 0x3b, 0xcb, 0x08, 0x18, + 0x52, 0x10, 0xe9, 0x7c, 0x17, 0x66, 0x20, 0x03, 0x45, 0xec, 0x86, 0x14, 0x07, 0x37, 0xe2, 0xe6, + 0x66, 0xb8, 0xc6, 0x63, 0xcb, 0x1b, 0x65, 0xc7, 0xb6, 0x56, 0xa3, 0x95, 0x0d, 0xa2, 0xa5, 0x61, + 0xa8, 0xe8, 0x68, 0xef, 0x3f, 0xf0, 0x27, 0xae, 0xbc, 0x92, 0x4a, 0x03, 0x49, 0x43, 0xad, 0x8e, + 0x8e, 0xd1, 0xae, 0x24, 0xaf, 0x6d, 0x79, 0xb0, 0x71, 0xae, 0xdb, 0xb7, 0xef, 0x7b, 0xef, 0xed, + 0xbe, 0xf7, 0x7d, 0x3b, 0x0b, 0x54, 0xdc, 0xb7, 0x0c, 0x8b, 0x78, 0xc8, 0xb0, 0x88, 0xe3, 0x20, + 0xcb, 0xc7, 0xc4, 0x31, 0xa6, 0x2d, 0xc3, 0xff, 0x41, 0x77, 0x3d, 0xe2, 0x13, 0x78, 0x88, 0xfb, + 0x96, 0x1e, 0x03, 0xf4, 0x19, 0x40, 0x9f, 0xb6, 0x94, 0xba, 0x4d, 0x6c, 0xc2, 0x20, 0x46, 0xbc, + 0xe2, 0x68, 0xe5, 0x5d, 0x9b, 0x10, 0x7b, 0x84, 0x0c, 0x66, 0xf5, 0x27, 0x97, 0x46, 0xcf, 0x09, + 0x12, 0x97, 0x50, 0x69, 0x84, 0x91, 0xe3, 0xc7, 0x55, 0xf8, 0x2a, 0x01, 0x7c, 0xbc, 0xe2, 0x28, + 0x42, 0x5d, 0x06, 0xd4, 0x7e, 0xdf, 0x01, 0x07, 0x4f, 0xa8, 0xdd, 0xc9, 0xf6, 0xbf, 0x71, 0x91, + 0x73, 0xe1, 0x60, 0x1f, 0xb6, 0x40, 0x85, 0xa7, 0xec, 0xe2, 0x81, 0x2c, 0x35, 0xa5, 0xe3, 0x4a, + 0xbb, 0x1e, 0x85, 0xea, 0xdd, 0xa0, 0x37, 0x1e, 0x9d, 0x69, 0x99, 0x4b, 0x33, 0xcb, 0x7c, 0x7d, + 0x31, 0x80, 0x5f, 0x83, 0x9a, 0x45, 0x26, 0x8e, 0x8f, 0x3c, 0xb7, 0xe7, 0xf9, 0x81, 0xbc, 0xd3, + 0x94, 0x8e, 0xab, 0x8f, 0x3e, 0xd4, 0xf3, 0xaf, 0xad, 0x77, 0x04, 0x6c, 0xbb, 0xf4, 0x2a, 0x54, + 0x0b, 0xe6, 0x5c, 0x3c, 0xfc, 0x1c, 0xec, 0x4f, 0x91, 0x47, 0x31, 0x71, 0xe4, 0x22, 0x4b, 0xa5, + 0xae, 0x4a, 0xf5, 0x9c, 0xc3, 0xcc, 0x14, 0x0f, 0xcf, 0x40, 0x6d, 0x80, 0x46, 0xbd, 0xa0, 0xeb, + 0x22, 0x0f, 0x93, 0x81, 0x5c, 0x6a, 0x4a, 0xc7, 0xa5, 0xf6, 0x51, 0x14, 0xaa, 0xef, 0xf0, 0x0b, + 0x88, 0x5e, 0xcd, 0xac, 0x32, 0xf3, 0x29, 0xb3, 0xe0, 0x21, 0xd8, 0xa3, 0xd8, 0x76, 0x90, 0x27, + 0xef, 0xc6, 0xd7, 0x36, 0x13, 0xeb, 0xac, 0xfc, 0xf3, 0x4b, 0xb5, 0xf0, 0xf7, 0x4b, 0xb5, 0xa0, + 0xa9, 0xe0, 0x41, 0x6e, 0xd3, 0x4c, 0x44, 0x5d, 0xe2, 0x50, 0xa4, 0xfd, 0xb6, 0x0f, 0xea, 0x4b, + 0x88, 0x67, 0x5e, 0xf0, 0x7f, 0xba, 0xfa, 0x1d, 0x38, 0x74, 0x3d, 0x34, 0xc5, 0x64, 0x42, 0xbb, + 0xb3, 0x5b, 0xc7, 0xf1, 0x3b, 0x2c, 0xfe, 0x83, 0x28, 0x54, 0x1f, 0xf0, 0xf8, 0x7c, 0x9c, 0x26, + 0x4b, 0x66, 0x3d, 0x75, 0xcd, 0x8e, 0x74, 0x31, 0x80, 0x4f, 0x41, 0x2d, 0x29, 0x49, 0xfd, 0x9e, + 0x8f, 0x92, 0x2e, 0xd7, 0x75, 0xce, 0x3c, 0x3d, 0x65, 0x9e, 0x7e, 0xee, 0x04, 0x62, 0xef, 0xc4, + 0x18, 0xcd, 0xac, 0x72, 0xf3, 0xdb, 0xd8, 0x5a, 0xa2, 0x40, 0x69, 0x4b, 0x0a, 0x2c, 0xce, 0x71, + 0x77, 0x83, 0x39, 0x4e, 0xc1, 0x81, 0x98, 0xab, 0x9b, 0x70, 0x83, 0xca, 0x7b, 0xcd, 0xe2, 0x1a, + 0x64, 0x6a, 0x37, 0xa3, 0x50, 0xbd, 0x9f, 0xdc, 0x38, 0x2f, 0x8f, 0x66, 0xd6, 0xc5, 0xfd, 0x24, + 0x8c, 0xc2, 0x17, 0xa0, 0xe6, 0x7a, 0x84, 0x5c, 0x76, 0xaf, 0x10, 0xb6, 0xaf, 0x7c, 0x79, 0x9f, + 0xf5, 0x40, 0x11, 0xca, 0x71, 0xa9, 0x4e, 0x5b, 0xfa, 0x57, 0x0c, 0xd1, 0x7e, 0x2f, 0xbe, 0xf9, + 0xec, 0x4e, 0x62, 0xb4, 0x66, 0x56, 0x99, 0xc9, 0x91, 0xf0, 0x14, 0x00, 0xee, 0xc5, 0x0e, 0xf6, + 0xe5, 0x72, 0x53, 0x3a, 0xae, 0xb5, 0x0f, 0xa2, 0x50, 0xbd, 0x27, 0x46, 0xc6, 0x3e, 0xcd, 0xac, + 0x30, 0x83, 0x69, 0xf9, 0x2c, 0x3d, 0x11, 0xaf, 0x2c, 0x57, 0x58, 0xdc, 0xd1, 0x62, 0x45, 0xee, + 0x4d, 0x2b, 0x76, 0x98, 0x05, 0x3b, 0xe0, 0x4e, 0xe2, 0x8d, 0x99, 0xed, 0xd0, 0x09, 0x95, 0x01, + 0x0b, 0x57, 0xa2, 0x50, 0x3d, 0x9c, 0x0b, 0x4f, 0x01, 0x9a, 0xf9, 0x36, 0xcf, 0x90, 0x6e, 0xc0, + 0x4b, 0x70, 0x37, 0xf3, 0xa6, 0x6d, 0xa9, 0xfe, 0x67, 0x5b, 0xd4, 0xa4, 0x2d, 0x47, 0xe9, 0x10, + 0xe6, 0x33, 0x68, 0xe6, 0x9d, 0x6c, 0x2b, 0x69, 0xcf, 0x4c, 0xba, 0xb5, 0x15, 0xd2, 0x6d, 0x80, + 0xfb, 0x79, 0xc2, 0xcc, 0x94, 0xfb, 0xd7, 0x6e, 0x8e, 0x72, 0xcf, 0xad, 0x21, 0xfc, 0x12, 0xbc, + 0x35, 0xaf, 0x3e, 0xae, 0x5e, 0x39, 0x0a, 0xd5, 0x7a, 0x76, 0x3e, 0x41, 0x74, 0x31, 0x91, 0x05, + 0xa9, 0x59, 0x40, 0x99, 0x23, 0x51, 0x9e, 0x92, 0x3f, 0x8a, 0x42, 0xf5, 0xfd, 0x1c, 0xc2, 0x2d, + 0x24, 0x96, 0x45, 0xe7, 0x9c, 0x9e, 0xb7, 0x78, 0x30, 0x17, 0x9f, 0x82, 0xd2, 0xd6, 0x4f, 0xc1, + 0xa2, 0x0c, 0x76, 0x6f, 0x51, 0x06, 0x2d, 0xc0, 0xd9, 0xdd, 0xf5, 0xbd, 0x40, 0xde, 0x63, 0x74, + 0x14, 0x9e, 0xd1, 0xcc, 0xa5, 0x99, 0x65, 0xb6, 0x8e, 0x5f, 0xde, 0x45, 0x0d, 0xec, 0x6f, 0xa7, + 0x81, 0xf2, 0xad, 0x68, 0xa0, 0xf2, 0x46, 0x35, 0x00, 0x36, 0xd0, 0xc0, 0xb9, 0x35, 0xcc, 0x34, + 0xf0, 0xcb, 0x0e, 0x90, 0x97, 0x00, 0x1d, 0xe2, 0x5c, 0x62, 0x6f, 0xbc, 0xad, 0x0e, 0xb2, 0xc9, + 0xf5, 0xac, 0x21, 0xa3, 0x7d, 0xce, 0xe4, 0x7a, 0xd6, 0x30, 0x9d, 0x5c, 0xac, 0xbc, 0x45, 0x22, + 0x15, 0x6f, 0x91, 0x48, 0xb3, 0x66, 0x95, 0x56, 0x34, 0x4b, 0x03, 0xcd, 0x55, 0xbd, 0x48, 0x1b, + 0xf6, 0xe8, 0x9f, 0x22, 0x28, 0x3e, 0xa1, 0x36, 0xfc, 0x11, 0xc0, 0x9c, 0x9f, 0xd4, 0xc9, 0x2a, + 0x11, 0xe6, 0xfe, 0x21, 0x94, 0x4f, 0x37, 0x82, 0xa7, 0x67, 0x80, 0xdf, 0x83, 0x7b, 0xcb, 0xdf, + 0x8d, 0x4f, 0xd6, 0xce, 0xf5, 0xcc, 0x0b, 0x94, 0xd3, 0x4d, 0xd0, 0xab, 0x0b, 0xc7, 0x33, 0x5b, + 0xbf, 0xf0, 0xb9, 0x35, 0xdc, 0xa0, 0xb0, 0x40, 0x53, 0xf8, 0x93, 0x04, 0x0e, 0xf2, 0x39, 0xfa, + 0x70, 0xed, 0x7c, 0x49, 0x84, 0xf2, 0xd9, 0xa6, 0x11, 0xe9, 0x29, 0xda, 0xcf, 0x5f, 0x5d, 0x37, + 0xa4, 0xd7, 0xd7, 0x0d, 0xe9, 0xcf, 0xeb, 0x86, 0xf4, 0xeb, 0x4d, 0xa3, 0xf0, 0xfa, 0xa6, 0x51, + 0xf8, 0xe3, 0xa6, 0x51, 0x78, 0xf1, 0x85, 0x8d, 0xfd, 0xab, 0x49, 0x5f, 0xb7, 0xc8, 0xd8, 0xb0, + 0x08, 0x1d, 0x13, 0x6a, 0xe0, 0xbe, 0x75, 0x62, 0x13, 0x63, 0x7a, 0x6a, 0x8c, 0xc9, 0x60, 0x32, + 0x42, 0x94, 0x7f, 0xd2, 0x1f, 0x3e, 0x3e, 0x11, 0xfe, 0xe9, 0x7e, 0xe0, 0x22, 0xda, 0xdf, 0x63, + 0x4f, 0xee, 0xe3, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xdd, 0x12, 0x14, 0x2b, 0x56, 0x0c, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/core/03-connection/types/version.go b/modules/core/03-connection/types/version.go index 7ae9e0b98b6..15ffc49d577 100644 --- a/modules/core/03-connection/types/version.go +++ b/modules/core/03-connection/types/version.go @@ -117,8 +117,8 @@ func GetCompatibleVersions() []exported.Version { // IsSupportedVersion returns true if the proposed version has a matching version // identifier and its entire feature set is supported or the version identifier // supports an empty feature set. -func IsSupportedVersion(proposedVersion *Version) bool { - supportedVersion, found := FindSupportedVersion(proposedVersion, GetCompatibleVersions()) +func IsSupportedVersion(supportedVersions []exported.Version, proposedVersion *Version) bool { + supportedVersion, found := FindSupportedVersion(proposedVersion, supportedVersions) if !found { return false } diff --git a/modules/core/03-connection/types/version_test.go b/modules/core/03-connection/types/version_test.go index 29838291dd8..2958c55fa38 100644 --- a/modules/core/03-connection/types/version_test.go +++ b/modules/core/03-connection/types/version_test.go @@ -57,7 +57,7 @@ func TestIsSupportedVersion(t *testing.T) { } for _, tc := range testCases { - require.Equal(t, tc.expPass, types.IsSupportedVersion(tc.version)) + require.Equal(t, tc.expPass, types.IsSupportedVersion(types.GetCompatibleVersions(), tc.version)) } } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 3cf28bed750..d71794e7a6f 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -117,7 +117,7 @@ func (k Keeper) ConnectionOpenTry(goCtx context.Context, msg *connectiontypes.Ms } if _, err := k.ConnectionKeeper.ConnOpenTry( - ctx, msg.PreviousConnectionId, msg.Counterparty, msg.DelayPeriod, msg.ClientId, targetClient, + ctx, msg.Counterparty, msg.DelayPeriod, msg.ClientId, targetClient, connectiontypes.ProtoVersionsToExported(msg.CounterpartyVersions), msg.ProofInit, msg.ProofClient, msg.ProofConsensus, msg.ProofHeight, msg.ConsensusHeight, ); err != nil { diff --git a/proto/ibc/core/connection/v1/tx.proto b/proto/ibc/core/connection/v1/tx.proto index 1ca0b404000..b2fea632c36 100644 --- a/proto/ibc/core/connection/v1/tx.proto +++ b/proto/ibc/core/connection/v1/tx.proto @@ -49,14 +49,13 @@ message MsgConnectionOpenTry { option (gogoproto.goproto_getters) = false; string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - // in the case of crossing hello's, when both chains call OpenInit, we need - // the connection identifier of the previous connection in state INIT - string previous_connection_id = 2 [(gogoproto.moretags) = "yaml:\"previous_connection_id\""]; - google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""]; - Counterparty counterparty = 4 [(gogoproto.nullable) = false]; - uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; - repeated Version counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""]; - ibc.core.client.v1.Height proof_height = 7 + // Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. + string previous_connection_id = 2 [deprecated = true, (gogoproto.moretags) = "yaml:\"previous_connection_id\""]; + google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""]; + Counterparty counterparty = 4 [(gogoproto.nullable) = false]; + uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; + repeated Version counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""]; + ibc.core.client.v1.Height proof_height = 7 [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; // proof of the initialization the connection on Chain A: `UNITIALIZED -> // INIT` diff --git a/testing/coordinator.go b/testing/coordinator.go index 6aaf2ab748f..f2cc49f9a91 100644 --- a/testing/coordinator.go +++ b/testing/coordinator.go @@ -194,21 +194,3 @@ func (coord *Coordinator) CommitNBlocks(chain *TestChain, n uint64) { coord.IncrementTime() } } - -// ConnOpenInitOnBothChains initializes a connection on both endpoints with the state INIT -// using the OpenInit handshake call. -func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error { - if err := path.EndpointA.ConnOpenInit(); err != nil { - return err - } - - if err := path.EndpointB.ConnOpenInit(); err != nil { - return err - } - - if err := path.EndpointA.UpdateClient(); err != nil { - return err - } - - return path.EndpointB.UpdateClient() -} From ef4eaf9d6064d777ff55a8d179e50dd4d41f01f2 Mon Sep 17 00:00:00 2001 From: rene <41963722+renaynay@users.noreply.github.com> Date: Tue, 12 Jul 2022 16:21:33 +0200 Subject: [PATCH 210/275] (core/23-commitment/types) doc: fix typo (#1694) --- modules/core/23-commitment/types/merkle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/23-commitment/types/merkle.go b/modules/core/23-commitment/types/merkle.go index 133c5277771..b661855935f 100644 --- a/modules/core/23-commitment/types/merkle.go +++ b/modules/core/23-commitment/types/merkle.go @@ -128,7 +128,7 @@ func ApplyPrefix(prefix exported.Prefix, path MerklePath) (MerklePath, error) { var _ exported.Proof = (*MerkleProof)(nil) -// VerifyMembership verifies the membership pf a merkle proof against the given root, path, and value. +// VerifyMembership verifies the membership of a merkle proof against the given root, path, and value. func (proof MerkleProof) VerifyMembership(specs []*ics23.ProofSpec, root exported.Root, path exported.Path, value []byte) error { if err := proof.validateVerificationArgs(specs, root); err != nil { return err From 1e6af489ed57450f8fa187816cfdd61d4fd4f19e Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 13 Jul 2022 11:08:43 +0200 Subject: [PATCH 211/275] remove spurious `TestABCICodeDeterminism` tests (#1695) ## Description Thanks @colin-axner for noticing this. closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- .../host/ibc_module_test.go | 63 --------------- .../host/types/ack_test.go | 81 ------------------- 2 files changed, 144 deletions(-) delete mode 100644 modules/apps/27-interchain-accounts/host/types/ack_test.go diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index df563082f91..b3e19a00ad2 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -9,10 +9,7 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" - abcitypes "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" - tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" - tmstate "github.com/tendermint/tendermint/state" "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" @@ -692,63 +689,3 @@ func (suite *InterchainAccountsTestSuite) TestControlAccountAfterChannelClose() hasBalance = suite.chainB.GetSimApp().BankKeeper.HasBalance(suite.chainB.GetContext(), icaAddr, sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(0)}) suite.Require().True(hasBalance) } - -// The safety of including SDK MsgResponses in the acknowledgement rests -// on the inclusion of the abcitypes.ResponseDeliverTx.Data in the -// abcitypes.ResposneDeliverTx hash. If the abcitypes.ResponseDeliverTx.Data -// gets removed from consensus they must no longer be used in the packet -// acknowledgement. -// -// This test acts as an indicator that the abcitypes.ResponseDeliverTx.Data -// may no longer be deterministic. -func (suite *InterchainAccountsTestSuite) TestABCICodeDeterminism() { - msgResponseBz, err := proto.Marshal(&channeltypes.MsgChannelOpenInitResponse{}) - suite.Require().NoError(err) - - msgData := &sdk.MsgData{ - MsgType: sdk.MsgTypeURL(&channeltypes.MsgChannelOpenInit{}), - Data: msgResponseBz, - } - - txResponse, err := proto.Marshal(&sdk.TxMsgData{ - Data: []*sdk.MsgData{msgData}, - }) - suite.Require().NoError(err) - - deliverTx := abcitypes.ResponseDeliverTx{ - Data: txResponse, - } - responses := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTx, - }, - } - - differentMsgResponseBz, err := proto.Marshal(&channeltypes.MsgRecvPacketResponse{}) - suite.Require().NoError(err) - - differentMsgData := &sdk.MsgData{ - MsgType: sdk.MsgTypeURL(&channeltypes.MsgRecvPacket{}), - Data: differentMsgResponseBz, - } - - differentTxResponse, err := proto.Marshal(&sdk.TxMsgData{ - Data: []*sdk.MsgData{differentMsgData}, - }) - suite.Require().NoError(err) - - differentDeliverTx := abcitypes.ResponseDeliverTx{ - Data: differentTxResponse, - } - - differentResponses := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &differentDeliverTx, - }, - } - - hash := tmstate.ABCIResponsesResultsHash(&responses) - differentHash := tmstate.ABCIResponsesResultsHash(&differentResponses) - - suite.Require().NotEqual(hash, differentHash) -} diff --git a/modules/apps/27-interchain-accounts/host/types/ack_test.go b/modules/apps/27-interchain-accounts/host/types/ack_test.go deleted file mode 100644 index f0484efe695..00000000000 --- a/modules/apps/27-interchain-accounts/host/types/ack_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package types_test - -import ( - "testing" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/stretchr/testify/suite" - abcitypes "github.com/tendermint/tendermint/abci/types" - tmprotostate "github.com/tendermint/tendermint/proto/tendermint/state" - tmstate "github.com/tendermint/tendermint/state" - - ibctesting "github.com/cosmos/ibc-go/v4/testing" -) - -const ( - gasUsed = uint64(100) - gasWanted = uint64(100) -) - -type TypesTestSuite struct { - suite.Suite - - coordinator *ibctesting.Coordinator - - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain -} - -func (suite *TypesTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) - - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) -} - -func TestTypesTestSuite(t *testing.T) { - suite.Run(t, new(TypesTestSuite)) -} - -// The safety of including ABCI error codes in the acknowledgement rests -// on the inclusion of these ABCI error codes in the abcitypes.ResposneDeliverTx -// hash. If the ABCI codes get removed from consensus they must no longer be used -// in the packet acknowledgement. -// -// This test acts as an indicator that the ABCI error codes may no longer be deterministic. -func (suite *TypesTestSuite) TestABCICodeDeterminism() { - // same ABCI error code used - err := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 1") - errSameABCICode := sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "error string 2") - - // different ABCI error code used - errDifferentABCICode := sdkerrors.ErrNotFound - - deliverTx := sdkerrors.ResponseDeliverTx(err, gasUsed, gasWanted, false) - responses := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTx, - }, - } - - deliverTxSameABCICode := sdkerrors.ResponseDeliverTx(errSameABCICode, gasUsed, gasWanted, false) - responsesSameABCICode := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTxSameABCICode, - }, - } - - deliverTxDifferentABCICode := sdkerrors.ResponseDeliverTx(errDifferentABCICode, gasUsed, gasWanted, false) - responsesDifferentABCICode := tmprotostate.ABCIResponses{ - DeliverTxs: []*abcitypes.ResponseDeliverTx{ - &deliverTxDifferentABCICode, - }, - } - - hash := tmstate.ABCIResponsesResultsHash(&responses) - hashSameABCICode := tmstate.ABCIResponsesResultsHash(&responsesSameABCICode) - hashDifferentABCICode := tmstate.ABCIResponsesResultsHash(&responsesDifferentABCICode) - - suite.Require().Equal(hash, hashSameABCICode) - suite.Require().NotEqual(hash, hashDifferentABCICode) -} From da45cad5b9592e208554513ae37ca3b5c52a8f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Jul 2022 12:38:12 +0200 Subject: [PATCH 212/275] update bug report issue template (#1693) --- .github/ISSUE_TEMPLATE/bug-report.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 5bdfad7c29a..9cb089d1f23 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -20,6 +20,10 @@ through the appropriate channels won't receive any bounty. +## Expected Behaviour + + + ## Version From b9e35ebcc1108ef3f101ed720eb3fd3c0070f84d Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 13 Jul 2022 12:41:09 +0200 Subject: [PATCH 213/275] fix codeowners for 02-client (#1696) ## Description Thanks again @colin-axner for signaling this! closes: #XXXX --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [x] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [x] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f6569b64ddd..05a43ba6f55 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -18,8 +18,8 @@ ## CODEOWNERS for core/02-client -/modules/core/02-client @seantking @damiannolan -/proto/ibc/core/client @seantking @damiannolan +/modules/core/02-client @colin-axner @fedekunze @AdityaSripal @seantking @damiannolan +/proto/ibc/core/client @colin-axner @fedekunze @AdityaSripal @seantking @damiannolan # CODEOWNERS for the light-clients From e8dd1a8cec15e704dcd2b8fdd37c377ebe7d1057 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Jul 2022 16:52:32 +0200 Subject: [PATCH 214/275] build(deps): bump google.golang.org/grpc from 1.47.0 to 1.48.0 (#1699) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.47.0 to 1.48.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.47.0...v1.48.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index de5b84637dc..91efbb05ebe 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd - google.golang.org/grpc v1.47.0 + google.golang.org/grpc v1.48.0 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 3d39b9e62c8..1f3bf1db967 100644 --- a/go.sum +++ b/go.sum @@ -1551,8 +1551,8 @@ google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 419c3c4d8ffba65d8f61201559689b17c4d3a996 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 14 Jul 2022 10:18:39 +0200 Subject: [PATCH 215/275] docs: update middleware documentation (#1639) * docs: update middleware documentation * remove old text and add func keyword * alignment * fix alignment * Update develop.md * review comments * remove empty line * docs: add links in middleware docs to fee middleware implementation (#1641) * docs: add links in middleware docs to fee middleware implementation * add extra line for better readability * fix typos --- docs/ibc/middleware/develop.md | 244 ++++++++++++++++++++------ docs/ibc/middleware/integration.md | 14 +- modules/apps/29-fee/ibc_middleware.go | 2 +- 3 files changed, 199 insertions(+), 61 deletions(-) diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index 705040b1db7..9adc5a8cfa7 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -2,7 +2,7 @@ order: 1 --> -# IBC Middleware +# 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}. @@ -12,7 +12,7 @@ IBC applications are designed to be self-contained modules that implement their 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 +## Pre-requisite readings - [IBC Overview](../overview.md) {prereq} - [IBC Integration](../integration.md) {prereq} @@ -28,9 +28,9 @@ Middleware allows developers to define the extensions as separate modules that c `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 +## 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. +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. #### Interfaces @@ -48,22 +48,28 @@ type Middleware interface { // which will call the next middleware until it reaches the core IBC handler. 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 - GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) + WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet exported.Packet, ack exported.Acknowledgement) error + GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) } ``` ### Implement `IBCModule` interface and callbacks -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 `IBCModule` is a struct that implements the [ICS-26 interface (`porttypes.IBCModule`)](https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/module.go#L11-L106). It is recommended to separate these callbacks into a separate file `ibc_module.go`. As will be mentioned in the [integration section](./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. +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}`. +Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following: -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. +```json +{"":"","app_version":""} +``` + +The `` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `fee_version`). + +During the handshake callbacks, the middleware can unmarshal the version string and retrieve the middleware and application versions. It can do its negotiation logic on ``, and pass the `` 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. @@ -71,8 +77,11 @@ In the case where the middleware wishes to send a packet or acknowledgment witho ### Handshake callbacks +#### `OnChanOpenInit` + ```go -func (im IBCModule) OnChanOpenInit(ctx sdk.Context, +func (im IBCModule) OnChanOpenInit( + ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, @@ -80,11 +89,32 @@ func (im IBCModule) OnChanOpenInit(ctx sdk.Context, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, -) error { - // core/04-channel/types contains a helper function to split middleware and underlying app version - middlewareVersion, appVersion = channeltypes.SplitChannelVersion(version) +) (string, error) { + // try to unmarshal JSON-encoded version string and pass + // the app-specific version to app callback. + // otherwise, pass version directly to app callback. + metadata, err := Unmarshal(version) + if err != nil { + // Since it is valid for fee version to not be specified, + // the above middleware version may be for another middleware. + // Pass the entire version string onto the underlying application. + return im.app.OnChanOpenInit( + ctx, + order, + connectionHops, + portID, + channelID, + channelCap, + counterparty, + version, + ) + } + doCustomLogic() - im.app.OnChanOpenInit( + + // if the version string is empty, OnChanOpenInit is expected to return + // a default version string representing the version(s) it supports + appVersion, err := im.app.OnChanOpenInit( ctx, order, connectionHops, @@ -92,10 +122,23 @@ func (im IBCModule) OnChanOpenInit(ctx sdk.Context, channelID, channelCap, counterparty, - appVersion, // note we only pass app version here + metadata.AppVersion, // note we only pass app version here ) + if err != nil { + return "", err + } + + version := constructVersion(metadata.MiddlewareVersion, appVersion) + + return version, nil } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L34-L82) an example implementation of this callback for the ICS29 Fee Middleware module. + +#### `OnChanOpenTry` +```go func OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, @@ -108,10 +151,25 @@ func OnChanOpenTry( ) (string, error) { doCustomLogic() - // core/04-channel/types contains a helper function to split middleware and underlying app version - cpMiddlewareVersion, cpAppVersion = channeltypes.SplitChannelVersion(counterpartyVersion) + // try to unmarshal JSON-encoded version string and pass + // the app-specific version to app callback. + // otherwise, pass version directly to app callback. + cpMetadata, err := Unmarshal(counterpartyVersion) + if err != nil { + return app.OnChanOpenTry( + ctx, + order, + connectionHops, + portID, + channelID, + channelCap, + counterparty, + counterpartyVersion, + ) + } - // call the underlying applications OnChanOpenTry callback + // Call the underlying application's OnChanOpenTry callback. + // The try callback must select the final app-specific version string and return it. appVersion, err := app.OnChanOpenTry( ctx, order, @@ -120,35 +178,55 @@ func OnChanOpenTry( channelID, channelCap, counterparty, - cpAppVersion, // note we only pass counterparty app version here + cpMetadata.AppVersion, // note we only pass counterparty app version here ) if err != nil { - return err + return "", err } - middlewareVersion := negotiateMiddlewareVersion(cpMiddlewareVersion) + // negotiate final middleware version + middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) version := constructVersion(middlewareVersion, appVersion) - return version + return version, nil } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L84-L124) an example implementation of this callback for the ICS29 Fee Middleware module. +#### `OnChanOpenAck` + +```go func OnChanOpenAck( ctx sdk.Context, portID, channelID string, + counterpartyChannelID string, counterpartyVersion string, ) error { - // core/04-channel/types contains a helper function to split middleware and underlying app version - middlewareVersion, appVersion = channeltypes.SplitChannelVersion(version) - if !isCompatible(middlewareVersion) { + // try to unmarshal JSON-encoded version string and pass + // the app-specific version to app callback. + // otherwise, pass version directly to app callback. + cpMetadata, err = UnmarshalJSON(counterpartyVersion) + if err != nil { + return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) + } + + if !isCompatible(cpMetadata.MiddlewareVersion) { return error } doCustomLogic() - // call the underlying applications OnChanOpenTry callback - app.OnChanOpenAck(ctx, portID, channelID, appVersion) + // call the underlying application's OnChanOpenTry callback + return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion) } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L126-L152) an example implementation of this callback for the ICS29 Fee Middleware module. +### `OnChanOpenConfirm` + +```go func OnChanOpenConfirm( ctx sdk.Context, portID, @@ -156,93 +234,151 @@ func OnChanOpenConfirm( ) error { doCustomLogic() - app.OnChanOpenConfirm(ctx, portID, channelID) + return app.OnChanOpenConfirm(ctx, portID, channelID) } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L154-L162) an example implementation of this callback for the ICS29 Fee Middleware module. -OnChanCloseInit( +#### `OnChanCloseInit` + +```go +func OnChanCloseInit( ctx sdk.Context, portID, channelID string, ) error { doCustomLogic() - app.OnChanCloseInit(ctx, portID, channelID) + return app.OnChanCloseInit(ctx, portID, channelID) } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L164-L187) an example implementation of this callback for the ICS29 Fee Middleware module. + +#### `OnChanCloseConfirm` -OnChanCloseConfirm( +```go +func OnChanCloseConfirm( ctx sdk.Context, portID, channelID string, ) error { doCustomLogic() - app.OnChanCloseConfirm(ctx, portID, channelID) + return app.OnChanCloseConfirm(ctx, portID, channelID) } ``` -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. +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L189-L212) an example implementation of this callback for the ICS29 Fee Middleware module. + +**NOTE**: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version unmarshalling 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. +#### `OnRecvPacket` + ```go -OnRecvPacket( +func OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, + relayer sdk.AccAddress, ) ibcexported.Acknowledgement { doCustomLogic(packet) - ack := app.OnRecvPacket(ctx, packet) + ack := app.OnRecvPacket(ctx, packet, relayer) doCustomLogic(ack) // middleware may modify outgoing ack return ack } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L214-L237) an example implementation of this callback for the ICS29 Fee Middleware module. + +#### `OnAcknowledgementPacket` -OnAcknowledgementPacket( +```go +func OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte, -) (*sdk.Result, error) { + relayer sdk.AccAddress, +) error { doCustomLogic(packet, ack) - app.OnAcknowledgementPacket(ctx, packet, ack) + return app.OnAcknowledgementPacket(ctx, packet, ack, relayer) } +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L239-L292) an example implementation of this callback for the ICS29 Fee Middleware module. + +#### `OnTimeoutPacket` -OnTimeoutPacket( +```go +func OnTimeoutPacket( ctx sdk.Context, packet channeltypes.Packet, -) (*sdk.Result, error) { + relayer sdk.AccAddress, +) error { doCustomLogic(packet) - app.OnTimeoutPacket(ctx, packet) + return app.OnTimeoutPacket(ctx, packet, relayer) +} +``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L294-L334) an example implementation of this callback for the ICS29 Fee Middleware module. + +### 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. + +#### `SendPacket` + +```go +func SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + appPacket exported.PacketI, +) { + // middleware may modify packet + packet = doCustomLogic(appPacket) + + return ics4Keeper.SendPacket(ctx, chanCap, packet) } ``` -### ICS-4 Wrappers +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L336-L343) an example implementation of this function for the ICS29 Fee Middleware module. -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. +#### `WriteAcknowledgement` ```go // only called for async acks func WriteAcknowledgement( - packet channeltypes.Packet, - acknowledgement []bytes) { + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + packet exported.PacketI, + ack exported.Acknowledgement, +) { // middleware may modify acknowledgement - ack_bytes = doCustomLogic(acknowledgement) + ack_bytes = doCustomLogic(ack) return ics4Keeper.WriteAcknowledgement(packet, ack_bytes) } +``` -func SendPacket(appPacket channeltypes.Packet) { - // middleware may modify packet - packet = doCustomLogic(app_packet) +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L345-L353) an example implementation of this function for the ICS29 Fee Middleware module. - return ics4Keeper.SendPacket(packet) -} +#### `GetAppVersion` +```go // middleware must return the underlying application version -func GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { +func GetAppVersion( + ctx sdk.Context, + portID, + channelID string, +) (string, bool) { version, found := ics4Keeper.GetAppVersion(ctx, portID, channelID) if !found { return "", false @@ -261,3 +397,5 @@ func GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { return metadata.AppVersion, true } ``` + +See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f50645591a2/modules/apps/29-fee/ibc_middleware.go#L355-L358) an example implementation of this function for the ICS29 Fee Middleware module. diff --git a/docs/ibc/middleware/integration.md b/docs/ibc/middleware/integration.md index 68a8de00899..12eb447f8ea 100644 --- a/docs/ibc/middleware/integration.md +++ b/docs/ibc/middleware/integration.md @@ -2,7 +2,7 @@ order: 2 --> -# Integrating IBC Middleware into a Chain +# 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 Cosmos SDK chains. @@ -46,18 +46,18 @@ scopedKeeperCustom2 := capabilityKeeper.NewScopedKeeper("custom2") // 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") +transferIBCModule := transfer.NewIBCModule(transferKeeper) +customIBCModule1 := custom.NewIBCModule(customKeeper, "portCustom1") +customIBCModule2 := custom.NewIBCModule(customKeeper, "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)) +stack1 := mw1.NewIBCMiddleware(mw3.NewIBCMiddleware(transferIBCModule, mw3Keeper), mw1Keeper) // stack 2 contains mw3 -> mw2 -> custom1 -stack2 := mw3.NewIBCModule(mw3Keeper, mw3.NewIBCModule(customIBCModule1)) +stack2 := mw3.NewIBCMiddleware(mw2.NewIBCMiddleware(customIBCModule1), mw3Keeper) // stack 3 contains mw2 -> mw1 -> custom2 -stack3 := mw2.NewIBCModule(mw1.NewIBCModule(mw1Keeper, customIBCModule2)) +stack3 := mw2.NewIBCMiddleware(mw1.NewIBCMiddleware(customIBCModule2, mw1Keeper)) // associate each stack with the moduleName provided by the underlying scopedKeeper ibcRouter := porttypes.NewRouter() diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 315b5ded3d2..2cbce3d2f9d 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -224,7 +224,7 @@ func (im IBCMiddleware) OnRecvPacket( ack := im.app.OnRecvPacket(ctx, packet, relayer) - // incase of async aknowledgement (ack == nil) store the relayer address for use later during async WriteAcknowledgement + // in case of async aknowledgement (ack == nil) store the relayer address for use later during async WriteAcknowledgement if ack == nil { im.keeper.SetRelayerAddressForAsyncAck(ctx, channeltypes.NewPacketId(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()), relayer.String()) return nil From b0b1810266a16bdc375dabf7d3ad3b418b949ce7 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Thu, 14 Jul 2022 10:20:23 +0100 Subject: [PATCH 216/275] Adding github action to run goimports (#1673) --- .github/scripts/go-imports.sh | 20 +++++++++++++++++++ .github/workflows/goimports.yaml | 9 +++++++++ Makefile | 8 ++++++++ modules/apps/29-fee/client/cli/query.go | 3 ++- modules/apps/29-fee/keeper/msg_server_test.go | 2 +- modules/apps/29-fee/types/expected_keepers.go | 1 + modules/apps/29-fee/types/msgs_test.go | 1 + modules/core/keeper/keeper_test.go | 1 + testing/chain_test.go | 1 + testing/simapp/app.go | 5 +++-- 10 files changed, 47 insertions(+), 4 deletions(-) create mode 100755 .github/scripts/go-imports.sh create mode 100644 .github/workflows/goimports.yaml diff --git a/.github/scripts/go-imports.sh b/.github/scripts/go-imports.sh new file mode 100755 index 00000000000..bc5e6db3f86 --- /dev/null +++ b/.github/scripts/go-imports.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +formatted_files="$(docker run -v "$(pwd)":/ibc-go --rm -w "/ibc-go" --entrypoint="" cytopia/goimports goimports -l -local 'github.com/cosmos/ibc-go' /ibc-go)" + +exit_code=0 +for f in $formatted_files +do + # we don't care about formatting in pb.go files. + if [ "${f: -5}" == "pb.go" ]; then + continue + fi + exit_code=1 + echo "formatted file ${f}..." +done + +if [ "${exit_code}" == 1 ]; then + echo "not all files were correctly formated, run the following:" + echo "make goimports" +fi + +exit $exit_code diff --git a/.github/workflows/goimports.yaml b/.github/workflows/goimports.yaml new file mode 100644 index 00000000000..b951b17aa1d --- /dev/null +++ b/.github/workflows/goimports.yaml @@ -0,0 +1,9 @@ +name: Goimports +on: pull_request +jobs: + goimports: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: "Go Imports" + run: .github/scripts/go-imports.sh diff --git a/Makefile b/Makefile index df259c5a477..e14171fcec9 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ PACKAGES_NOSIMULATION=$(shell go list ./... | grep -v '/simulation') PACKAGES_SIMTEST=$(shell go list ./... | grep '/simulation') +CHANGED_GO_FILES := $(shell git diff --name-only | grep .go$$ | grep -v pb.go) +ALL_GO_FILES := $(shell find . -regex ".*\.go$$" | grep -v pb.go) VERSION := $(shell echo $(shell git describe --always) | sed 's/^v//') COMMIT := $(shell git log -1 --format='%H') LEDGER_ENABLED ?= true @@ -351,6 +353,12 @@ format: find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/docs/statik/statik.go" -not -path "./tests/mocks/*" -not -name '*.pb.go' | xargs goimports -w -local github.com/cosmos/cosmos-sdk .PHONY: format +goimports: + $(DOCKER) run -v $(CURDIR):/ibc-go --rm -w "/ibc-go" cytopia/goimports -w -local 'github.com/cosmos/ibc-go' "$(CHANGED_GO_FILES)" &> /dev/null || echo "No changed go files to format" + +goimports-all: + $(DOCKER) run -v $(CURDIR):/ibc-go --rm -w "/ibc-go" cytopia/goimports -w -local 'github.com/cosmos/ibc-go' "$(ALL_GO_FILES)" + ############################################################################### ### Devdoc ### ############################################################################### diff --git a/modules/apps/29-fee/client/cli/query.go b/modules/apps/29-fee/client/cli/query.go index bb6ef67a5d8..815eec4d35b 100644 --- a/modules/apps/29-fee/client/cli/query.go +++ b/modules/apps/29-fee/client/cli/query.go @@ -8,9 +8,10 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" + "github.com/spf13/cobra" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - "github.com/spf13/cobra" ) // GetCmdIncentivizedPacket returns the unrelayed incentivized packet for a given packetID diff --git a/modules/apps/29-fee/keeper/msg_server_test.go b/modules/apps/29-fee/keeper/msg_server_test.go index 73c7caadc9c..e0c84d62c9b 100644 --- a/modules/apps/29-fee/keeper/msg_server_test.go +++ b/modules/apps/29-fee/keeper/msg_server_test.go @@ -3,7 +3,7 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" diff --git a/modules/apps/29-fee/types/expected_keepers.go b/modules/apps/29-fee/types/expected_keepers.go index 7fb564f0d9d..9e6abfd358b 100644 --- a/modules/apps/29-fee/types/expected_keepers.go +++ b/modules/apps/29-fee/types/expected_keepers.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) diff --git a/modules/apps/29-fee/types/msgs_test.go b/modules/apps/29-fee/types/msgs_test.go index bf12f95784b..93573e354a8 100644 --- a/modules/apps/29-fee/types/msgs_test.go +++ b/modules/apps/29-fee/types/msgs_test.go @@ -4,6 +4,7 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v4/testing" diff --git a/modules/core/keeper/keeper_test.go b/modules/core/keeper/keeper_test.go index ef00da59032..ec808bdc0e0 100644 --- a/modules/core/keeper/keeper_test.go +++ b/modules/core/keeper/keeper_test.go @@ -11,6 +11,7 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" diff --git a/testing/chain_test.go b/testing/chain_test.go index 595609ce4ac..5edb189c2f8 100644 --- a/testing/chain_test.go +++ b/testing/chain_test.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/staking/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 744e8c96b01..312de2eb624 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -80,6 +80,7 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" icacontroller "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller" icacontrollerkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/keeper" @@ -102,7 +103,7 @@ import ( ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" - simappparams "github.com/cosmos/ibc-go/v4/testing/simapp/params" + simappparams "github.com/cosmos/ibc-go/v4/testing/simapp/params" authz "github.com/cosmos/cosmos-sdk/x/authz" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" @@ -164,7 +165,7 @@ var ( ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, ibcfeetypes.ModuleName: nil, icatypes.ModuleName: nil, - ibcmock.ModuleName: nil, + ibcmock.ModuleName: nil, } ) From 81d10d4af1e5dedd9b3d5e7a22ea8cfc6719cfd7 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Thu, 14 Jul 2022 16:48:16 +0100 Subject: [PATCH 217/275] Add E2ETestSuite Type (E2E #3) (#1650) --- .github/scripts/determine_simd_tag.go | 26 +-- .github/workflows/test.yml | 5 +- Dockerfile | 3 +- e2e/fee_middleware_test.go | 28 +-- e2e/testconfig/testconfig.go | 83 +++++++++ e2e/testsuite/relayer.go | 22 +++ e2e/testsuite/testsuite.go | 242 ++++++++++++++++++++++++++ go.mod | 36 +++- go.sum | 96 +++++++++- 9 files changed, 503 insertions(+), 38 deletions(-) create mode 100644 e2e/testconfig/testconfig.go create mode 100644 e2e/testsuite/relayer.go create mode 100644 e2e/testsuite/testsuite.go diff --git a/.github/scripts/determine_simd_tag.go b/.github/scripts/determine_simd_tag.go index 3fb4ce6986f..af3a6281268 100644 --- a/.github/scripts/determine_simd_tag.go +++ b/.github/scripts/determine_simd_tag.go @@ -3,32 +3,24 @@ package main import ( "flag" "fmt" - "os" ) -var prNum int -var ref string +var prNum string func init() { - flag.IntVar(&prNum, "pr", 0, "the number of the pr") - flag.StringVar(&ref, "ref", "", "the github ref") + flag.StringVar(&prNum, "pr", "", "the number of the pr") flag.Parse() } -// in the context of a GithubAction workflow, the PR is the event number. So if the ref is not specified -// but the event number is, that means we are running for a PR. If the ref is specified, this means -// we have merged the PR, so we want to use the ref as a tag instead of the PR number. +// in the context of a GithubAction workflow, the PR is non empty if it is a pr. When +// code is merged to main, it will be empty. In this case we just use the "main" tag. func main() { - if prNum == 0 && ref == "" { - fmt.Printf("must specify one or bot of [pr, ref]") - os.Exit(1) - } - fmt.Printf(getSimdTag(prNum, ref)) + fmt.Printf(getSimdTag(prNum)) } -func getSimdTag(prNum int, ref string) string { - if ref != "" { - return ref +func getSimdTag(prNum string) string { + if prNum == "" { + return "main" } - return fmt.Sprintf("pr-%d", prNum) + return fmt.Sprintf("pr-%s", prNum) } diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8482853965a..3e2e3c11cb1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -214,7 +214,7 @@ jobs: go-version: 1.18 - id: get-tag run: | - tag=$(go run .github/scripts/determine_simd_tag.go -ref "${{ github.event.push.ref }}" -pr "${{ github.event.pull_request.number }}" ) + tag=$(go run .github/scripts/determine_simd_tag.go -pr "${{ github.event.pull_request.number }}" ) echo "Using tag $tag" echo "::set-output name=simd-tag::$tag" @@ -233,6 +233,9 @@ jobs: matrix: ${{ fromJSON(needs.build-test-matrix.outputs.matrix) }} steps: - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 1.18 - name: Log in to the Container registry uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b with: diff --git a/Dockerfile b/Dockerfile index a193f54906e..b5a6414de25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,4 +20,5 @@ FROM ubuntu:20.04 COPY --from=builder /go/build/simd /bin/simd -ENTRYPOINT ["simd"] +# TODO(chatton): uncomment once https://github.com/strangelove-ventures/ibctest/issues/183 is resolved. +#ENTRYPOINT ["simd"] diff --git a/e2e/fee_middleware_test.go b/e2e/fee_middleware_test.go index 33327ecfb15..b911d781021 100644 --- a/e2e/fee_middleware_test.go +++ b/e2e/fee_middleware_test.go @@ -1,10 +1,13 @@ package e2e import ( - "os" + "context" "testing" + "github.com/strangelove-ventures/ibctest/ibc" "github.com/stretchr/testify/suite" + + "github.com/cosmos/ibc-go/v4/e2e/testsuite" ) func TestFeeMiddlewareTestSuite(t *testing.T) { @@ -12,18 +15,23 @@ func TestFeeMiddlewareTestSuite(t *testing.T) { } type FeeMiddlewareTestSuite struct { - suite.Suite + testsuite.E2ETestSuite } func (s *FeeMiddlewareTestSuite) TestPlaceholder() { - tag, ok := os.LookupEnv("SIMD_TAG") - s.Require().True(ok) - s.T().Logf("SIMD_TAG=%s", tag) + ctx := context.Background() + r := s.SetupChainsRelayerAndChannel(ctx, feeMiddlewareChannelOptions()) + s.T().Run("start relayer", func(t *testing.T) { + s.StartRelayer(r) + }) - image, ok := os.LookupEnv("SIMD_IMAGE") - s.Require().True(ok) - s.T().Logf("SIMD_IMAGE=%s", image) +} - s.T().Logf("Placeholder test") - s.Require().True(true) +// feeMiddlewareChannelOptions configures both of the chains to have fee middleware enabled. +func feeMiddlewareChannelOptions() func(options *ibc.CreateChannelOptions) { + return func(opts *ibc.CreateChannelOptions) { + opts.Version = "{\"fee_version\":\"ics29-1\",\"app_version\":\"ics20-1\"}" + opts.DestPortName = "transfer" + opts.SourcePortName = "transfer" + } } diff --git a/e2e/testconfig/testconfig.go b/e2e/testconfig/testconfig.go new file mode 100644 index 00000000000..c043712b4e4 --- /dev/null +++ b/e2e/testconfig/testconfig.go @@ -0,0 +1,83 @@ +package testconfig + +import ( + "fmt" + "os" + + "github.com/strangelove-ventures/ibctest/ibc" +) + +const ( + DefaultSimdImage = "ghcr.io/cosmos/ibc-go-simd-e2e" + SimdImageEnv = "SIMD_IMAGE" + SimdTagEnv = "SIMD_TAG" +) + +// TestConfig holds various fields used in the E2E tests. +type TestConfig struct { + SimdImage string + SimdTag string +} + +// FromEnv returns a TestConfig constructed from environment variables. +func FromEnv() TestConfig { + simdImage, ok := os.LookupEnv(SimdImageEnv) + if !ok { + simdImage = DefaultSimdImage + } + + simdTag, ok := os.LookupEnv(SimdTagEnv) + if !ok { + panic(fmt.Sprintf("must specify simd version for test with environment variable [%s]", SimdTagEnv)) + } + + return TestConfig{ + SimdImage: simdImage, + SimdTag: simdTag, + } +} + +// ChainOptions stores chain configurations for the chains that will be +// created for the tests. They can be modified by passing ChainOptionConfiguration +// to E2ETestSuite.GetChains. +type ChainOptions struct { + ChainAConfig *ibc.ChainConfig + ChainBConfig *ibc.ChainConfig +} + +// ChainOptionConfiguration enables arbitrary configuration of ChainOptions. +type ChainOptionConfiguration func(options *ChainOptions) + +// DefaultChainOptions returns the default configuration for the chains. +// These options can be configured by passing configuration functions to E2ETestSuite.GetChains. +func DefaultChainOptions() ChainOptions { + tc := FromEnv() + chainACfg := newDefaultSimappConfig(tc, "simapp-a", "chain-a", "atoma") + chainBCfg := newDefaultSimappConfig(tc, "simapp-b", "chain-b", "atomb") + return ChainOptions{ + ChainAConfig: &chainACfg, + ChainBConfig: &chainBCfg, + } +} + +// newDefaultSimappConfig creates an ibc configuration for simd. +func newDefaultSimappConfig(tc TestConfig, name, chainID, denom string) ibc.ChainConfig { + return ibc.ChainConfig{ + Type: "cosmos", + Name: name, + ChainID: chainID, + Images: []ibc.DockerImage{ + { + Repository: tc.SimdImage, + Version: tc.SimdTag, + }, + }, + Bin: "simd", + Bech32Prefix: "cosmos", + Denom: denom, + GasPrices: fmt.Sprintf("0.01%s", denom), + GasAdjustment: 1.3, + TrustingPeriod: "508h", + NoHostMount: false, + } +} diff --git a/e2e/testsuite/relayer.go b/e2e/testsuite/relayer.go new file mode 100644 index 00000000000..4e4f5e95bba --- /dev/null +++ b/e2e/testsuite/relayer.go @@ -0,0 +1,22 @@ +package testsuite + +import ( + "testing" + + dockerclient "github.com/docker/docker/client" + "github.com/strangelove-ventures/ibctest" + "github.com/strangelove-ventures/ibctest/ibc" + "github.com/strangelove-ventures/ibctest/relayer" + "go.uber.org/zap" +) + +const ( + cosmosRelayerRepository = "ghcr.io/cosmos/relayer" +) + +// newCosmosRelayer returns an instance of the go relayer. +func newCosmosRelayer(t *testing.T, logger *zap.Logger, dockerClient *dockerclient.Client, network string, home string) ibc.Relayer { + return ibctest.NewBuiltinRelayerFactory(ibc.CosmosRly, logger, relayer.CustomDockerImage(cosmosRelayerRepository, "main")).Build( + t, dockerClient, network, home, + ) +} diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go new file mode 100644 index 00000000000..b4aca09a83b --- /dev/null +++ b/e2e/testsuite/testsuite.go @@ -0,0 +1,242 @@ +package testsuite + +import ( + "context" + "fmt" + "io/ioutil" + "strings" + "time" + + dockerclient "github.com/docker/docker/client" + "github.com/strangelove-ventures/ibctest" + "github.com/strangelove-ventures/ibctest/chain/cosmos" + "github.com/strangelove-ventures/ibctest/ibc" + "github.com/strangelove-ventures/ibctest/testreporter" + "github.com/stretchr/testify/suite" + "go.uber.org/zap" + "go.uber.org/zap/zaptest" + + "github.com/cosmos/ibc-go/v4/e2e/testconfig" +) + +const ( + // ChainARelayerName is the name given to the relayer wallet on ChainA + ChainARelayerName = "rlyA" + // ChainBRelayerName is the name given to the relayer wallet on ChainB + ChainBRelayerName = "rlyB" +) + +// E2ETestSuite has methods and functionality which can be shared among all test suites. +type E2ETestSuite struct { + suite.Suite + paths map[string]path + logger *zap.Logger + DockerClient *dockerclient.Client + network string + startRelayerFn func(relayer ibc.Relayer) +} + +// path is a pairing of two chains which will be used in a test. +type path struct { + chainA, chainB *cosmos.CosmosChain +} + +// newPath returns a path built from the given chains. +func newPath(chainA, chainB *cosmos.CosmosChain) path { + return path{ + chainA: chainA, + chainB: chainB, + } +} + +// SetupChainsRelayerAndChannel create two chains, a relayer, establishes a connection and creates a channel +// using the given channel options. The relayer returned by this function has not yet started. It should be started +// with E2ETestSuite.StartRelayer if needed. +// This should be called at the start of every test, unless fine grained control is required. +func (s *E2ETestSuite) SetupChainsRelayerAndChannel(ctx context.Context, channelOpts ...func(*ibc.CreateChannelOptions)) ibc.Relayer { + chainA, chainB := s.GetChains() + home, err := ioutil.TempDir("", "") + s.Require().NoError(err) + + r := newCosmosRelayer(s.T(), s.logger, s.DockerClient, s.network, home) + + pathName := fmt.Sprintf("%s-path", s.T().Name()) + pathName = strings.ReplaceAll(pathName, "/", "-") + + ic := ibctest.NewInterchain(). + AddChain(chainA). + AddChain(chainB). + AddRelayer(r, "r"). + AddLink(ibctest.InterchainLink{ + Chain1: chainA, + Chain2: chainB, + Relayer: r, + Path: pathName, + }) + + channelOptions := ibc.DefaultChannelOpts() + for _, opt := range channelOpts { + opt(&channelOptions) + } + + eRep := s.getRelayerExecReporter() + s.Require().NoError(ic.Build(ctx, eRep, ibctest.InterchainBuildOptions{ + TestName: s.T().Name(), + HomeDir: home, + Client: s.DockerClient, + NetworkID: s.network, + CreateChannelOpts: channelOptions, + })) + + s.startRelayerFn = func(relayer ibc.Relayer) { + err := relayer.StartRelayer(ctx, eRep, pathName) + s.Require().NoError(err, fmt.Sprintf("failed to start relayer: %s", err)) + s.T().Cleanup(func() { + if !s.T().Failed() { + if err := relayer.StopRelayer(ctx, eRep); err != nil { + s.T().Logf("error stopping relayer: %v", err) + } + } + }) + // wait for relayer to start. + time.Sleep(time.Second * 10) + } + + return r +} + +// GetChains returns two chains that can be used in a test. The pair returned +// is unique to the current test being run. Note: this function does not create containers. +func (s *E2ETestSuite) GetChains(chainOpts ...testconfig.ChainOptionConfiguration) (*cosmos.CosmosChain, *cosmos.CosmosChain) { + if s.paths == nil { + s.paths = map[string]path{} + } + + path, ok := s.paths[s.T().Name()] + if ok { + return path.chainA, path.chainB + } + + chainOptions := testconfig.DefaultChainOptions() + for _, opt := range chainOpts { + opt(&chainOptions) + } + + chainA, chainB := s.createCosmosChains(chainOptions) + path = newPath(chainA, chainB) + s.paths[s.T().Name()] = path + + return path.chainA, path.chainB +} + +// GetRelayerWallets returns the relayer wallets associated with the chains. +func (s *E2ETestSuite) GetRelayerWallets(relayer ibc.Relayer) (ibc.RelayerWallet, ibc.RelayerWallet, error) { + chainA, chainB := s.GetChains() + chainARelayerWallet, ok := relayer.GetWallet(chainA.Config().ChainID) + if !ok { + return ibc.RelayerWallet{}, ibc.RelayerWallet{}, fmt.Errorf("unable to find chain A relayer wallet") + } + + chainBRelayerWallet, ok := relayer.GetWallet(chainB.Config().ChainID) + if !ok { + return ibc.RelayerWallet{}, ibc.RelayerWallet{}, fmt.Errorf("unable to find chain B relayer wallet") + } + return chainARelayerWallet, chainBRelayerWallet, nil +} + +// RecoverRelayerWallets adds the corresponding relayer address to the keychain of the chain. +// This is useful if commands executed on the chains expect the relayer information to present in the keychain. +func (s *E2ETestSuite) RecoverRelayerWallets(ctx context.Context, relayer ibc.Relayer) error { + chainARelayerWallet, chainBRelayerWallet, err := s.GetRelayerWallets(relayer) + if err != nil { + return err + } + + chainA, chainB := s.GetChains() + + if err := chainA.RecoverKey(ctx, ChainARelayerName, chainARelayerWallet.Mnemonic); err != nil { + return fmt.Errorf("could not recover relayer wallet on chain A: %s", err) + } + if err := chainB.RecoverKey(ctx, ChainBRelayerName, chainBRelayerWallet.Mnemonic); err != nil { + return fmt.Errorf("could not recover relayer wallet on chain B: %s", err) + } + return nil +} + +// StartRelayer starts the given relayer. +func (s *E2ETestSuite) StartRelayer(relayer ibc.Relayer) { + if s.startRelayerFn == nil { + panic("cannot start relayer before it is created!") + } + + s.startRelayerFn(relayer) +} + +// CreateUserOnChainA creates a user with the given amount of funds on chain A. +func (s *E2ETestSuite) CreateUserOnChainA(ctx context.Context, amount int64) *ibctest.User { + chainA, _ := s.GetChains() + return ibctest.GetAndFundTestUsers(s.T(), ctx, strings.ReplaceAll(s.T().Name(), " ", "-"), amount, chainA)[0] +} + +// CreateUserOnChainB creates a user with the given amount of funds on chain B. +func (s *E2ETestSuite) CreateUserOnChainB(ctx context.Context, amount int64) *ibctest.User { + _, chainB := s.GetChains() + return ibctest.GetAndFundTestUsers(s.T(), ctx, strings.ReplaceAll(s.T().Name(), " ", "-"), amount, chainB)[0] +} + +// GetChainANativeBalance gets the balance of a given user on chain A. +func (s *E2ETestSuite) GetChainANativeBalance(ctx context.Context, user *ibctest.User) (int64, error) { + chainA, _ := s.GetChains() + return GetNativeChainBalance(ctx, chainA, user) +} + +// GetChainBNativeBalance gets the balance of a given user on chain B. +func (s *E2ETestSuite) GetChainBNativeBalance(ctx context.Context, user *ibctest.User) (int64, error) { + _, chainB := s.GetChains() + return GetNativeChainBalance(ctx, chainB, user) +} + +// createCosmosChains creates two separate chains in docker containers. +// test and can be retrieved with GetChains. +func (s *E2ETestSuite) createCosmosChains(chainOptions testconfig.ChainOptions) (*cosmos.CosmosChain, *cosmos.CosmosChain) { + ctx := context.Background() + client, network := ibctest.DockerSetup(s.T()) + + s.logger = zap.NewExample() + s.DockerClient = client + s.network = network + + logger := zaptest.NewLogger(s.T()) + + // TODO(chatton): allow for controller over number of validators and full nodes. + chainA := cosmos.NewCosmosChain(s.T().Name(), *chainOptions.ChainAConfig, 1, 0, logger) + chainB := cosmos.NewCosmosChain(s.T().Name(), *chainOptions.ChainBConfig, 1, 0, logger) + + s.T().Cleanup(func() { + if !s.T().Failed() { + for _, c := range []*cosmos.CosmosChain{chainA, chainB} { + if err := c.Cleanup(ctx); err != nil { + s.T().Logf("Chain cleanup for %s failed: %v", c.Config().ChainID, err) + } + } + } + }) + + return chainA, chainB +} + +// getRelayerExecReporter returns a testreporter.RelayerExecReporter instances +// using the current test's testing.T. +func (s *E2ETestSuite) getRelayerExecReporter() *testreporter.RelayerExecReporter { + rep := testreporter.NewNopReporter() + return rep.RelayerExecReporter(s.T()) +} + +// GetNativeChainBalance returns the balance of a specific user on a chain using the native denom. +func GetNativeChainBalance(ctx context.Context, chain ibc.Chain, user *ibctest.User) (int64, error) { + bal, err := chain.GetBalance(ctx, user.Bech32Address(chain.Config().Bech32Prefix), chain.Config().Denom) + if err != nil { + return -1, err + } + return bal, nil +} diff --git a/go.mod b/go.mod index 91efbb05ebe..484d8074671 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/armon/go-metrics v0.4.0 github.com/confio/ics23/go v0.7.0 github.com/cosmos/cosmos-sdk v0.45.6 + github.com/docker/docker v20.10.17+incompatible github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 @@ -17,9 +18,11 @@ require ( github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.12.0 + github.com/strangelove-ventures/ibctest v0.0.0-20220701220145-b783e516bff0 github.com/stretchr/testify v1.8.0 github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 + go.uber.org/zap v1.21.0 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd google.golang.org/grpc v1.48.0 google.golang.org/protobuf v1.28.0 @@ -31,7 +34,10 @@ require ( github.com/99designs/keyring v1.1.6 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/DataDog/zstd v1.4.5 // indirect + github.com/Microsoft/go-winio v0.5.1 // indirect github.com/Workiva/go-datastructures v1.0.53 // indirect + github.com/avast/retry-go/v4 v4.0.4 // indirect + github.com/benbjohnson/clock v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect @@ -41,6 +47,7 @@ require ( github.com/cosmos/btcutil v1.0.4 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/iavl v0.17.3 // indirect + github.com/cosmos/ibc-go/v3 v3.0.0 // indirect github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect github.com/cosmos/ledger-go v0.9.2 // indirect github.com/danieljoos/wincred v1.0.2 // indirect @@ -49,6 +56,9 @@ require ( github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect github.com/felixge/httpsnoop v1.0.1 // indirect @@ -62,6 +72,7 @@ require ( github.com/golang/snappy v0.0.3 // indirect github.com/google/btree v1.0.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -75,18 +86,21 @@ require ( github.com/improbable-eng/grpc-web v0.14.1 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/lib/pq v1.10.4 // indirect github.com/libp2p/go-buffer-pool v0.0.2 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mattn/go-isatty v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect @@ -97,9 +111,11 @@ require ( github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/rs/cors v1.8.2 // indirect - github.com/rs/zerolog v1.23.0 // indirect + github.com/rs/zerolog v1.26.1 // indirect github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect + github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -111,12 +127,28 @@ require ( github.com/tendermint/go-amino v0.16.0 // indirect github.com/zondax/hid v0.9.0 // indirect go.etcd.io/bbolt v1.3.6 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.7.0 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect + golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + lukechampine.com/uint128 v1.1.1 // indirect + modernc.org/cc/v3 v3.36.0 // indirect + modernc.org/ccgo/v3 v3.16.6 // indirect + modernc.org/libc v1.16.7 // indirect + modernc.org/mathutil v1.4.1 // indirect + modernc.org/memory v1.1.1 // indirect + modernc.org/opt v0.1.1 // indirect + modernc.org/sqlite v1.17.3 // indirect + modernc.org/strutil v1.1.1 // indirect + modernc.org/token v1.0.0 // indirect nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/go.sum b/go.sum index 1f3bf1db967..3f3e59d7dc9 100644 --- a/go.sum +++ b/go.sum @@ -130,6 +130,8 @@ github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/avast/retry-go/v4 v4.0.4 h1:38hLf0DsRXh+hOF6HbTni0+5QGTNdw9zbaMD7KAO830= +github.com/avast/retry-go/v4 v4.0.4/go.mod h1:HqmLvS2VLdStPCGDFjSuZ9pzlTqVRldCI4w2dO4m1Ms= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -138,6 +140,7 @@ github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZw github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -233,6 +236,8 @@ github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/iavl v0.17.3 h1:s2N819a2olOmiauVa0WAhoIJq9EhSXE9HDBAoR9k+8Y= github.com/cosmos/iavl v0.17.3/go.mod h1:prJoErZFABYZGDHka1R6Oay4z9PrNeFFiMKHDAMOi4w= +github.com/cosmos/ibc-go/v3 v3.0.0 h1:XUNplHVS51Q2gMnTFsFsH9QJ7flsovMamnltKbEgPQ4= +github.com/cosmos/ibc-go/v3 v3.0.0/go.mod h1:Mb+1NXiPOLd+CPFlOC6BKeAUaxXlhuWenMmRiUiSmwY= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= @@ -268,7 +273,11 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE= +github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= @@ -331,8 +340,8 @@ github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -466,6 +475,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -599,6 +610,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -661,8 +674,11 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= +github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -688,6 +704,7 @@ github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -696,6 +713,7 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= @@ -719,7 +737,6 @@ github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1t github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -788,6 +805,7 @@ github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCr github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrre/gotestcover v0.0.0-20160517101806-924dca7d15f0/go.mod h1:4xpMLz7RBWyB+ElzHu8Llua96TRCB3YwX+l5EP1wmHk= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -853,7 +871,10 @@ github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzy github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -863,9 +884,9 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.23.0 h1:UskrK+saS9P9Y789yNNulYKdARjPZuS35B8gJF2x60g= -github.com/rs/zerolog v1.23.0/go.mod h1:6c7hFfxPOy7TacJc4Fcdi24/J0NKYGzjG8FWRI916Qo= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= +github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -927,6 +948,8 @@ github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiu github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= +github.com/strangelove-ventures/ibctest v0.0.0-20220701220145-b783e516bff0 h1:NjImCG4wNpDbi1LQ7AtUHWx4Jlo6OCqaMtw2qDWu7EM= +github.com/strangelove-ventures/ibctest v0.0.0-20220701220145-b783e516bff0/go.mod h1:UjhKi/BLudic8IAvfFMNqBRzJC0wm1EVRAZTRZjR6+c= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -999,6 +1022,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -1028,17 +1052,23 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1067,6 +1097,7 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1113,6 +1144,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1170,6 +1203,7 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1204,6 +1238,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1293,6 +1329,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1300,6 +1337,7 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1326,6 +1364,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1381,6 +1420,7 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1393,10 +1433,15 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1574,8 +1619,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1605,7 +1650,9 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1614,6 +1661,41 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0 h1:0kmRkTmqNidmu3c7BNDSdVHCxXCkWLmWmCIVX4LUboo= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6 h1:3l18poV+iUemQ98O3X5OMr97LOqlzis+ytivU4NqGhA= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.7 h1:qzQtHhsZNpVPpeCu+aMIQldXeV1P0vRhSqCL0nOIJOA= +modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.17.3 h1:iE+coC5g17LtByDYDWKpR6m2Z9022YrSh3bumwOnIrI= +modernc.org/sqlite v1.17.3/go.mod h1:10hPVYar9C0kfXuTWGz8s0XtB8uAGymUy51ZzStYe3k= +modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 0fd565645a833974f1cb697f3ffb521599fe5578 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Fri, 15 Jul 2022 10:32:23 +0100 Subject: [PATCH 218/275] Separate go mod for e2e (E2E #4) (#1701) --- .github/workflows/test.yml | 1 + Dockerfile | 3 +- Makefile | 10 - e2e/Makefile | 13 + e2e/fee_middleware_test.go | 2 +- e2e/go.mod | 142 ++++ e2e/go.sum | 1556 ++++++++++++++++++++++++++++++++++++ e2e/testsuite/relayer.go | 4 +- e2e/testsuite/testsuite.go | 4 +- go.mod | 35 +- go.sum | 79 +- 11 files changed, 1722 insertions(+), 127 deletions(-) create mode 100644 e2e/Makefile create mode 100644 e2e/go.mod create mode 100644 e2e/go.sum diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3e2e3c11cb1..b4f4e721539 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -244,4 +244,5 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Run e2e Test run: | + cd e2e make e2e-test suite=${{ matrix.suite }} test=${{ matrix.test }} diff --git a/Dockerfile b/Dockerfile index b5a6414de25..a193f54906e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,5 +20,4 @@ FROM ubuntu:20.04 COPY --from=builder /go/build/simd /bin/simd -# TODO(chatton): uncomment once https://github.com/strangelove-ventures/ibctest/issues/183 is resolved. -#ENTRYPOINT ["simd"] +ENTRYPOINT ["simd"] diff --git a/Makefile b/Makefile index e14171fcec9..912d0e4e879 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,6 @@ MOCKS_DIR = $(CURDIR)/tests/mocks HTTPS_GIT := https://github.com/cosmos/ibc-go.git DOCKER := $(shell which docker) DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf:1.0.0-rc8 -TEST_CONTAINERS=$(shell docker ps --filter "label=ibc-test" -a -q) export GO111MODULE = on @@ -327,15 +326,6 @@ benchmark: @go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION) .PHONY: benchmark -cleanup-ibc-test-containers: - for id in $(TEST_CONTAINERS) ; do \ - $(DOCKER) stop $$id ; \ - $(DOCKER) rm $$id ; \ - done - -e2e-test: cleanup-ibc-test-containers - @go test -v ./e2e --run $(suite) -testify.m ^$(test)$$ - ############################################################################### ### Linting ### ############################################################################### diff --git a/e2e/Makefile b/e2e/Makefile new file mode 100644 index 00000000000..cad92172af9 --- /dev/null +++ b/e2e/Makefile @@ -0,0 +1,13 @@ +DOCKER := $(shell which docker) +TEST_CONTAINERS=$(shell docker ps --filter "label=ibc-test" -a -q) + +cleanup-ibc-test-containers: + for id in $(TEST_CONTAINERS) ; do \ + $(DOCKER) stop $$id ; \ + $(DOCKER) rm $$id ; \ + done + +e2e-test: cleanup-ibc-test-containers + @go test -v ./ --run $(suite) -testify.m ^$(test)$$ + +.PHONY: cleanup-ibc-test-containers e2e-test diff --git a/e2e/fee_middleware_test.go b/e2e/fee_middleware_test.go index b911d781021..03017ab22e2 100644 --- a/e2e/fee_middleware_test.go +++ b/e2e/fee_middleware_test.go @@ -7,7 +7,7 @@ import ( "github.com/strangelove-ventures/ibctest/ibc" "github.com/stretchr/testify/suite" - "github.com/cosmos/ibc-go/v4/e2e/testsuite" + "e2e/testsuite" ) func TestFeeMiddlewareTestSuite(t *testing.T) { diff --git a/e2e/go.mod b/e2e/go.mod new file mode 100644 index 00000000000..5b80823e0f3 --- /dev/null +++ b/e2e/go.mod @@ -0,0 +1,142 @@ +module e2e + +go 1.18 + +replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 + +require ( + github.com/docker/docker v20.10.17+incompatible + github.com/strangelove-ventures/ibctest v0.0.0-20220713213153-930886d8db30 + github.com/stretchr/testify v1.8.0 + go.uber.org/zap v1.21.0 +) + +require ( + filippo.io/edwards25519 v1.0.0-beta.2 // indirect + github.com/99designs/keyring v1.1.6 // indirect + github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect + github.com/DataDog/zstd v1.4.5 // indirect + github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/armon/go-metrics v0.4.0 // indirect + github.com/avast/retry-go/v4 v4.0.4 // indirect + github.com/benbjohnson/clock v1.1.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/btcsuite/btcd v0.22.0-beta // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/confio/ics23/go v0.7.0 // indirect + github.com/cosmos/btcutil v1.0.4 // indirect + github.com/cosmos/cosmos-sdk v0.45.6 // indirect + github.com/cosmos/go-bip39 v1.0.0 // indirect + github.com/cosmos/iavl v0.17.3 // indirect + github.com/cosmos/ibc-go/v4 v4.0.0-rc0 // indirect + github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect + github.com/cosmos/ledger-go v0.9.2 // indirect + github.com/danieljoos/wincred v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgraph-io/badger/v2 v2.2007.2 // indirect + github.com/dgraph-io/ristretto v0.0.3 // indirect + github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect + github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/log v0.2.0 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect + github.com/gogo/gateway v1.1.0 // indirect + github.com/gogo/protobuf v1.3.3 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/google/btree v1.0.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/handlers v1.5.1 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/gtank/merlin v0.1.1 // indirect + github.com/gtank/ristretto255 v0.1.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect + github.com/libp2p/go-buffer-pool v0.0.2 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mtibben/percent v0.2.1 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.1 // indirect + github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.12.1 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.32.1 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/rakyll/statik v0.1.7 // indirect + github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect + github.com/regen-network/cosmos-proto v0.3.1 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect + github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + github.com/spf13/afero v1.8.2 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cobra v1.5.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.12.0 // indirect + github.com/subosito/gotenv v1.3.0 // indirect + github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect + github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect + github.com/tendermint/btcd v0.1.1 // indirect + github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect + github.com/tendermint/go-amino v0.16.0 // indirect + github.com/tendermint/tendermint v0.34.19 // indirect + github.com/tendermint/tm-db v0.6.6 // indirect + github.com/zondax/hid v0.9.0 // indirect + go.etcd.io/bbolt v1.3.6 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.7.0 // indirect + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect + golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect + google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect + google.golang.org/grpc v1.47.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect + gopkg.in/ini.v1 v1.66.4 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + lukechampine.com/uint128 v1.1.1 // indirect + modernc.org/cc/v3 v3.36.0 // indirect + modernc.org/ccgo/v3 v3.16.6 // indirect + modernc.org/libc v1.16.7 // indirect + modernc.org/mathutil v1.4.1 // indirect + modernc.org/memory v1.1.1 // indirect + modernc.org/opt v0.1.1 // indirect + modernc.org/sqlite v1.17.3 // indirect + modernc.org/strutil v1.1.1 // indirect + modernc.org/token v1.0.0 // indirect +) diff --git a/e2e/go.sum b/e2e/go.sum new file mode 100644 index 00000000000..6d00db2a409 --- /dev/null +++ b/e2e/go.sum @@ -0,0 +1,1556 @@ +bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.0.0-beta.2 h1:/BZRNzm8N4K4eWfK28dL4yescorxtO7YG1yun8fy+pI= +filippo.io/edwards25519 v1.0.0-beta.2/go.mod h1:X+pm78QAUPtFLi1z9PYIlS/bdDnvbCOGKtZ+ACWEf7o= +github.com/99designs/keyring v1.1.6 h1:kVDC2uCgVwecxCk+9zoCt2uEL6dt+dfVzMvGgnVcIuM= +github.com/99designs/keyring v1.1.6/go.mod h1:16e0ds7LGQQcT59QqkTg72Hh5ShM51Byv5PEmW6uoRU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= +github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= +github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= +github.com/adlio/schema v1.1.13/go.mod h1:L5Z7tw+7lRK1Fnpi/LT/ooCP1elkXn0krMWBQHUhEDE= +github.com/adlio/schema v1.3.0/go.mod h1:51QzxkpeFs6lRY11kPye26IaFPOV+HqEj01t5aXXKfs= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/avast/retry-go/v4 v4.0.4 h1:38hLf0DsRXh+hOF6HbTni0+5QGTNdw9zbaMD7KAO830= +github.com/avast/retry-go/v4 v4.0.4/go.mod h1:HqmLvS2VLdStPCGDFjSuZ9pzlTqVRldCI4w2dO4m1Ms= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= +github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= +github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg= +github.com/confio/ics23/go v0.6.6/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= +github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8= +github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.2.1/go.mod h1:wCYX+dRqZdImhGucXOqTQn05AhX6EUDaGEMUzTFFpLg= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= +github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= +github.com/cosmos/cosmos-sdk v0.45.6 h1:bnYLOcDp0cKWMLeUTTJIttq6xxRep52ulPxXC3BCfuQ= +github.com/cosmos/cosmos-sdk v0.45.6/go.mod h1:bPeeVMEtVvH3y3xAGHVbK+/CZlpaazzh77hG8ZrcJpI= +github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= +github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= +github.com/cosmos/iavl v0.17.3 h1:s2N819a2olOmiauVa0WAhoIJq9EhSXE9HDBAoR9k+8Y= +github.com/cosmos/iavl v0.17.3/go.mod h1:prJoErZFABYZGDHka1R6Oay4z9PrNeFFiMKHDAMOi4w= +github.com/cosmos/ibc-go/v4 v4.0.0-rc0 h1:zeMr6PNE7L300AcGkrMwRvtp62/RpGc7qU1LwhUcPKc= +github.com/cosmos/ibc-go/v4 v4.0.0-rc0/go.mod h1:4LK+uPycPhebJrJ8ebIqvsMEZ0lVRVNTiEyeI9zfB0U= +github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= +github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= +github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= +github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= +github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI= +github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE= +github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b h1:HBah4D48ypg3J7Np4N+HY/ZR76fx3HEUGxDU6Uk39oQ= +github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= +github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= +github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= +github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM= +github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87/go.mod h1:XGsKKeXxeRr95aEOgipvluMPlgjr7dGlk9ZTWOjcUcg= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/improbable-eng/grpc-web v0.14.1 h1:NrN4PY71A6tAz2sKDvC5JCauENWp0ykG8Oq1H3cpFvw= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= +github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= +github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= +github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q= +github.com/nats-io/jwt/v2 v2.0.3/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nats.go v1.12.1/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= +github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrre/gotestcover v0.0.0-20160517101806-924dca7d15f0/go.mod h1:4xpMLz7RBWyB+ElzHu8Llua96TRCB3YwX+l5EP1wmHk= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= +github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= +github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzywPxOvwMdxcg= +github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= +github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= +github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= +github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/strangelove-ventures/ibctest v0.0.0-20220713213153-930886d8db30 h1:pMhrxU1tY220nxDu6t/gb0H30NG+WYiSJFS5OrcxLFs= +github.com/strangelove-ventures/ibctest v0.0.0-20220713213153-930886d8db30/go.mod h1:aWBeEKU4lGfvJ9qO543zJbQGtB2fK2ffrJh6jbtowEM= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= +github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= +github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= +github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= +github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI= +github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= +github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= +github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/tendermint/tendermint v0.34.14/go.mod h1:FrwVm3TvsVicI9Z7FlucHV6Znfd5KBc/Lpp69cCwtk0= +github.com/tendermint/tendermint v0.34.19 h1:y0P1qI5wSa9IRuhKnTDA6IUcOrLi1hXJuALR+R7HFEk= +github.com/tendermint/tendermint v0.34.19/go.mod h1:R5+wgIwSxMdKQcmOaeudL0Cjkr3HDkhpcdum6VeU3R4= +github.com/tendermint/tm-db v0.6.4/go.mod h1:dptYhIpJ2M5kUuenLr+Yyf3zQOv1SgBZcl8/BmWlMBw= +github.com/tendermint/tm-db v0.6.6 h1:EzhaOfR0bdKyATqcd5PNeyeq8r+V4bRPHBfyFdD9kGM= +github.com/tendermint/tm-db v0.6.6/go.mod h1:wP8d49A85B7/erz/r4YbKssKw6ylsO/hKtFk7E1aWZI= +github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= +github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201119123407-9b1e624d6bc4/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= +gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= +lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.36.0 h1:0kmRkTmqNidmu3c7BNDSdVHCxXCkWLmWmCIVX4LUboo= +modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6 h1:3l18poV+iUemQ98O3X5OMr97LOqlzis+ytivU4NqGhA= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= +modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= +modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +modernc.org/libc v1.16.7 h1:qzQtHhsZNpVPpeCu+aMIQldXeV1P0vRhSqCL0nOIJOA= +modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= +modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= +modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.17.3 h1:iE+coC5g17LtByDYDWKpR6m2Z9022YrSh3bumwOnIrI= +modernc.org/sqlite v1.17.3/go.mod h1:10hPVYar9C0kfXuTWGz8s0XtB8uAGymUy51ZzStYe3k= +modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= +modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= +modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM= +modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/e2e/testsuite/relayer.go b/e2e/testsuite/relayer.go index 4e4f5e95bba..f71ef586ed9 100644 --- a/e2e/testsuite/relayer.go +++ b/e2e/testsuite/relayer.go @@ -15,8 +15,8 @@ const ( ) // newCosmosRelayer returns an instance of the go relayer. -func newCosmosRelayer(t *testing.T, logger *zap.Logger, dockerClient *dockerclient.Client, network string, home string) ibc.Relayer { +func newCosmosRelayer(t *testing.T, logger *zap.Logger, dockerClient *dockerclient.Client, network string) ibc.Relayer { return ibctest.NewBuiltinRelayerFactory(ibc.CosmosRly, logger, relayer.CustomDockerImage(cosmosRelayerRepository, "main")).Build( - t, dockerClient, network, home, + t, dockerClient, network, ) } diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index b4aca09a83b..b99d150e255 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -16,7 +16,7 @@ import ( "go.uber.org/zap" "go.uber.org/zap/zaptest" - "github.com/cosmos/ibc-go/v4/e2e/testconfig" + "e2e/testconfig" ) const ( @@ -58,7 +58,7 @@ func (s *E2ETestSuite) SetupChainsRelayerAndChannel(ctx context.Context, channel home, err := ioutil.TempDir("", "") s.Require().NoError(err) - r := newCosmosRelayer(s.T(), s.logger, s.DockerClient, s.network, home) + r := newCosmosRelayer(s.T(), s.logger, s.DockerClient, s.network) pathName := fmt.Sprintf("%s-path", s.T().Name()) pathName = strings.ReplaceAll(pathName, "/", "-") diff --git a/go.mod b/go.mod index 484d8074671..70baed8d7ef 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/armon/go-metrics v0.4.0 github.com/confio/ics23/go v0.7.0 github.com/cosmos/cosmos-sdk v0.45.6 - github.com/docker/docker v20.10.17+incompatible github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 @@ -18,11 +17,9 @@ require ( github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.12.0 - github.com/strangelove-ventures/ibctest v0.0.0-20220701220145-b783e516bff0 github.com/stretchr/testify v1.8.0 github.com/tendermint/tendermint v0.34.19 github.com/tendermint/tm-db v0.6.6 - go.uber.org/zap v1.21.0 google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd google.golang.org/grpc v1.48.0 google.golang.org/protobuf v1.28.0 @@ -34,10 +31,7 @@ require ( github.com/99designs/keyring v1.1.6 // indirect github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect github.com/DataDog/zstd v1.4.5 // indirect - github.com/Microsoft/go-winio v0.5.1 // indirect github.com/Workiva/go-datastructures v1.0.53 // indirect - github.com/avast/retry-go/v4 v4.0.4 // indirect - github.com/benbjohnson/clock v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect @@ -47,7 +41,6 @@ require ( github.com/cosmos/btcutil v1.0.4 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/iavl v0.17.3 // indirect - github.com/cosmos/ibc-go/v3 v3.0.0 // indirect github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect github.com/cosmos/ledger-go v0.9.2 // indirect github.com/danieljoos/wincred v1.0.2 // indirect @@ -56,23 +49,19 @@ require ( github.com/dgraph-io/badger/v2 v2.2007.2 // indirect github.com/dgraph-io/ristretto v0.0.3 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect - github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.4.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/gin-gonic/gin v1.7.0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.0 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect - github.com/go-playground/validator/v10 v10.4.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/gateway v1.1.0 // indirect github.com/golang/snappy v0.0.3 // indirect github.com/google/btree v1.0.0 // indirect github.com/google/orderedcode v0.0.1 // indirect - github.com/google/uuid v1.3.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -86,7 +75,6 @@ require ( github.com/improbable-eng/grpc-web v0.14.1 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/lib/pq v1.10.4 // indirect @@ -99,8 +87,6 @@ require ( github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect @@ -111,11 +97,9 @@ require ( github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/rs/cors v1.8.2 // indirect github.com/rs/zerolog v1.26.1 // indirect github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect - github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -127,28 +111,13 @@ require ( github.com/tendermint/go-amino v0.16.0 // indirect github.com/zondax/hid v0.9.0 // indirect go.etcd.io/bbolt v1.3.6 // indirect - go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.7.0 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect - golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.10 // indirect - golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/uint128 v1.1.1 // indirect - modernc.org/cc/v3 v3.36.0 // indirect - modernc.org/ccgo/v3 v3.16.6 // indirect - modernc.org/libc v1.16.7 // indirect - modernc.org/mathutil v1.4.1 // indirect - modernc.org/memory v1.1.1 // indirect - modernc.org/opt v0.1.1 // indirect - modernc.org/sqlite v1.17.3 // indirect - modernc.org/strutil v1.1.1 // indirect - modernc.org/token v1.0.0 // indirect nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/go.sum b/go.sum index 3f3e59d7dc9..01f587eac52 100644 --- a/go.sum +++ b/go.sum @@ -130,8 +130,6 @@ github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/avast/retry-go/v4 v4.0.4 h1:38hLf0DsRXh+hOF6HbTni0+5QGTNdw9zbaMD7KAO830= -github.com/avast/retry-go/v4 v4.0.4/go.mod h1:HqmLvS2VLdStPCGDFjSuZ9pzlTqVRldCI4w2dO4m1Ms= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -140,7 +138,6 @@ github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZw github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -236,8 +233,6 @@ github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/iavl v0.17.3 h1:s2N819a2olOmiauVa0WAhoIJq9EhSXE9HDBAoR9k+8Y= github.com/cosmos/iavl v0.17.3/go.mod h1:prJoErZFABYZGDHka1R6Oay4z9PrNeFFiMKHDAMOi4w= -github.com/cosmos/ibc-go/v3 v3.0.0 h1:XUNplHVS51Q2gMnTFsFsH9QJ7flsovMamnltKbEgPQ4= -github.com/cosmos/ibc-go/v3 v3.0.0/go.mod h1:Mb+1NXiPOLd+CPFlOC6BKeAUaxXlhuWenMmRiUiSmwY= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= @@ -273,11 +268,7 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE= -github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= @@ -342,6 +333,7 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= +github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -475,8 +467,6 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -610,8 +600,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -674,8 +662,6 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= -github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -704,7 +690,6 @@ github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -713,7 +698,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= @@ -805,7 +789,6 @@ github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCr github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrre/gotestcover v0.0.0-20160517101806-924dca7d15f0/go.mod h1:4xpMLz7RBWyB+ElzHu8Llua96TRCB3YwX+l5EP1wmHk= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -871,10 +854,7 @@ github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzy github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= -github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -948,8 +928,6 @@ github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiu github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= -github.com/strangelove-ventures/ibctest v0.0.0-20220701220145-b783e516bff0 h1:NjImCG4wNpDbi1LQ7AtUHWx4Jlo6OCqaMtw2qDWu7EM= -github.com/strangelove-ventures/ibctest v0.0.0-20220701220145-b783e516bff0/go.mod h1:UjhKi/BLudic8IAvfFMNqBRzJC0wm1EVRAZTRZjR6+c= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1052,23 +1030,17 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1144,8 +1116,6 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1238,8 +1208,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1337,7 +1305,6 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1364,7 +1331,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1420,7 +1386,6 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1434,14 +1399,10 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1621,6 +1582,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1650,9 +1612,7 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1661,41 +1621,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.36.0 h1:0kmRkTmqNidmu3c7BNDSdVHCxXCkWLmWmCIVX4LUboo= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6 h1:3l18poV+iUemQ98O3X5OMr97LOqlzis+ytivU4NqGhA= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.7 h1:qzQtHhsZNpVPpeCu+aMIQldXeV1P0vRhSqCL0nOIJOA= -modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.17.3 h1:iE+coC5g17LtByDYDWKpR6m2Z9022YrSh3bumwOnIrI= -modernc.org/sqlite v1.17.3/go.mod h1:10hPVYar9C0kfXuTWGz8s0XtB8uAGymUy51ZzStYe3k= -modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From c96fe927bf034e471e49c857e008d83f224a1843 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 15 Jul 2022 14:09:02 +0200 Subject: [PATCH 219/275] put back module name in event (#1681) --- modules/apps/transfer/ibc_module.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 6472c2998b0..96505e05ee6 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -189,6 +189,7 @@ func (im IBCModule) OnRecvPacket( } eventAttributes := []sdk.Attribute{ + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), From 95cd1c5300ca2caac44b7a550e3275203122cfd6 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 18 Jul 2022 10:41:45 +0200 Subject: [PATCH 220/275] fix typo --- docs/migrations/support-denoms-with-slashes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/migrations/support-denoms-with-slashes.md b/docs/migrations/support-denoms-with-slashes.md index fdbcfa64209..40fad8272f8 100644 --- a/docs/migrations/support-denoms-with-slashes.md +++ b/docs/migrations/support-denoms-with-slashes.md @@ -1,4 +1,4 @@ -# Migrating from not supporing base denoms with slashes to supporting base denoms with slashes +# Migrating from not supporting base denoms with slashes to supporting base denoms with slashes This document is intended to highlight significant changes which may require more information than presented in the CHANGELOG. Any changes that must be done by a user of ibc-go should be documented here. From 74ed532578e516769e1f5975c10a535686761df5 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Mon, 18 Jul 2022 11:27:25 +0100 Subject: [PATCH 221/275] Extracting e2e tests into two separate workflows (#1719) --- .github/workflows/e2e-fork.yml | 45 +++++++++++++++ .github/workflows/e2e.yaml | 102 +++++++++++++++++++++++++++++++++ .github/workflows/test.yml | 91 ----------------------------- 3 files changed, 147 insertions(+), 91 deletions(-) create mode 100644 .github/workflows/e2e-fork.yml create mode 100644 .github/workflows/e2e.yaml diff --git a/.github/workflows/e2e-fork.yml b/.github/workflows/e2e-fork.yml new file mode 100644 index 00000000000..c7add63f323 --- /dev/null +++ b/.github/workflows/e2e-fork.yml @@ -0,0 +1,45 @@ +name: Tests / E2E Fork +on: + pull_request: + branches: + - main + paths-ignore: + - docs/** +jobs: + # dynamically build a matrix of test/test suite pairs to run + build-test-matrix: + if: ${{ github.event.pull_request.head.repo.fork }} + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 1.18 + - id: set-matrix + run: echo "::set-output name=matrix::$(go run .github/scripts/build_test_matrix.go)" + + e2e: + env: + SIMD_TAG: latest + SIMD_IMAGE: ibc-go-simd-e2e + if: ${{ github.event.pull_request.head.repo.fork }} + needs: + - build-test-matrix + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.build-test-matrix.outputs.matrix) }} + steps: + - uses: actions/checkout@v3 + - name: Docker Build + run: docker build . -t "${SIMD_IMAGE}:${SIMD_TAG}" + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: 1.18 + - name: Run e2e Test + run: | + cd e2e + make e2e-test suite=${{ matrix.suite }} test=${{ matrix.test }} diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml new file mode 100644 index 00000000000..787559f18f3 --- /dev/null +++ b/.github/workflows/e2e.yaml @@ -0,0 +1,102 @@ +name: Tests / E2E +on: + pull_request: + push: + branches: + - main + paths-ignore: + - docs/** + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ibc-go-simd-e2e + +jobs: + docker-build: + if: ${{ !github.event.pull_request.head.repo.fork }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Log in to the Container registry + uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@69f6fc9d46f2f8bf0d5491e4aabe0bb8c6a4678a + with: + images: ${{ env.REGISTRY }}/cosmos/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + uses: docker/build-push-action@e551b19e49efd4e98792db7592c17c09b89db8d8 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + # dynamically build a matrix of test/test suite pairs to run + build-test-matrix: + if: ${{ !github.event.pull_request.head.repo.fork }} + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 1.18 + - id: set-matrix + run: echo "::set-output name=matrix::$(go run .github/scripts/build_test_matrix.go)" + + + # the tag of the image will differ if this is a PR or the branch is being merged into main. + # we store the tag as an environment variable and use it in the E2E tests to determine the tag. + determine-image-tag: + if: ${{ !github.event.pull_request.head.repo.fork }} + runs-on: ubuntu-latest + outputs: + simd-tag: ${{ steps.get-tag.outputs.simd-tag }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 1.18 + - id: get-tag + run: | + tag=$(go run .github/scripts/determine_simd_tag.go -pr "${{ github.event.pull_request.number }}" ) + echo "Using tag $tag" + echo "::set-output name=simd-tag::$tag" + + + e2e: + if: ${{ !github.event.pull_request.head.repo.fork }} + runs-on: ubuntu-latest + needs: + - build-test-matrix + - determine-image-tag + - docker-build + env: + SIMD_TAG: ${{ needs.determine-image-tag.outputs.simd-tag }} + SIMD_IMAGE: ghcr.io/cosmos/ibc-go-simd-e2e + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.build-test-matrix.outputs.matrix) }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 1.18 + - name: Log in to the Container registry + uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Run e2e Test + run: | + cd e2e + make e2e-test suite=${{ matrix.suite }} test=${{ matrix.test }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b4f4e721539..1164a1a1c22 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,10 +7,6 @@ on: branches: - main -env: - REGISTRY: ghcr.io - IMAGE_NAME: ibc-go-simd-e2e - jobs: cleanup-runs: runs-on: ubuntu-latest @@ -159,90 +155,3 @@ jobs: with: file: ./coverage.txt if: env.GIT_DIFF - - - docker-build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Log in to the Container registry - uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@69f6fc9d46f2f8bf0d5491e4aabe0bb8c6a4678a - with: - images: ${{ env.REGISTRY }}/cosmos/${{ env.IMAGE_NAME }} - - - name: Build and push Docker image - uses: docker/build-push-action@e551b19e49efd4e98792db7592c17c09b89db8d8 - with: - context: . - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - # dynamically build a matrix of test/test suite pairs to run - build-test-matrix: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: 1.18 - - id: set-matrix - run: echo "::set-output name=matrix::$(go run .github/scripts/build_test_matrix.go)" - - - # the tag of the image will differ if this is a PR or the branch is being merged into main. - # we store the tag as an environment variable and use it in the E2E tests to determine the tag. - determine-image-tag: - runs-on: ubuntu-latest - outputs: - simd-tag: ${{ steps.get-tag.outputs.simd-tag }} - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: 1.18 - - id: get-tag - run: | - tag=$(go run .github/scripts/determine_simd_tag.go -pr "${{ github.event.pull_request.number }}" ) - echo "Using tag $tag" - echo "::set-output name=simd-tag::$tag" - - - e2e: - runs-on: ubuntu-latest - needs: - - build-test-matrix - - determine-image-tag - - docker-build - env: - SIMD_TAG: ${{ needs.determine-image-tag.outputs.simd-tag }} - SIMD_IMAGE: ghcr.io/cosmos/ibc-go-simd-e2e - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.build-test-matrix.outputs.matrix) }} - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: 1.18 - - name: Log in to the Container registry - uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Run e2e Test - run: | - cd e2e - make e2e-test suite=${{ matrix.suite }} test=${{ matrix.test }} From c7be122e27b658f560c813dd297457d21f7fc93d Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 19 Jul 2022 09:24:59 +0200 Subject: [PATCH 222/275] add categories --- docs/roadmap/roadmap.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/roadmap/roadmap.md b/docs/roadmap/roadmap.md index 5385e8a0b38..eaf416adfb9 100644 --- a/docs/roadmap/roadmap.md +++ b/docs/roadmap/roadmap.md @@ -14,12 +14,20 @@ This roadmap should be read as a high-level guide, rather than a commitment to s At a high level we will focus on: +### Features + - Releasing [v4.0.0](https://github.com/cosmos/ibc-go/milestone/26), which includes the ICS-29 Fee Middleware module. - Finishing and releasing the [refactoring of 02-client](https://github.com/cosmos/ibc-go/milestone/16). This refactor will make the development of light clients easier. -- Finishing and releasing the upgrade to Cosmos SDK v0.46. - Starting the implementation of channel upgradability (see [epic](https://github.com/cosmos/ibc-go/issues/1599) and [alpha milestone](https://github.com/cosmos/ibc-go/milestone/29)) with the goal of cutting an alpha1 pre-release by the end of the quarter. Channel upgradability will allow chains to renegotiate an existing channel to take advantage of new features without having to create a new channel, thus preserving all existing packet state processed on the channel. - Implementing the new [`ORDERED_ALLOW_TIMEOUT` channel type](https://github.com/cosmos/ibc-go/milestone/31) and hopefully releasing it as well. This new channel type will allow packets on an ordered channel to timeout without causing the closure of the channel. + +### Testing and infrastructure + - Adding [automated e2e tests](https://github.com/cosmos/ibc-go/milestone/32) to the repo's CI. + +### Documentation and backlog + +- Finishing and releasing the upgrade to Cosmos SDK v0.46. - Writing the [light client implementation guide](https://github.com/cosmos/ibc-go/issues/59). - Working on [core backlog issues](https://github.com/cosmos/ibc-go/milestone/28). - Depending on the timeline of the Cosmos SDK, implementing and testing the changes needed to support the [transtion to SMT storage](https://github.com/cosmos/ibc-go/milestone/21). From 193e41480dc8a8994902d14b9f13d72a23df2734 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 19 Jul 2022 10:18:43 +0100 Subject: [PATCH 223/275] Add fee middleware test suite functions (E2E #5) (#1710) --- e2e/fee_middleware_test.go | 58 ++++++++++++++++++++++++++++++++- e2e/testsuite/testsuite.go | 66 +++++++++++++++++++++++++++++++++++++- 2 files changed, 122 insertions(+), 2 deletions(-) diff --git a/e2e/fee_middleware_test.go b/e2e/fee_middleware_test.go index 03017ab22e2..a6532a8fd1f 100644 --- a/e2e/fee_middleware_test.go +++ b/e2e/fee_middleware_test.go @@ -4,10 +4,16 @@ import ( "context" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/strangelove-ventures/ibctest/broadcast" + "github.com/strangelove-ventures/ibctest/chain/cosmos" "github.com/strangelove-ventures/ibctest/ibc" "github.com/stretchr/testify/suite" "e2e/testsuite" + + feetypes "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) func TestFeeMiddlewareTestSuite(t *testing.T) { @@ -18,13 +24,63 @@ type FeeMiddlewareTestSuite struct { testsuite.E2ETestSuite } +// RegisterCounterPartyPayee broadcasts a MsgRegisterCounterpartyPayee message. +func (s *FeeMiddlewareTestSuite) RegisterCounterPartyPayee(ctx context.Context, chain *cosmos.CosmosChain, + user broadcast.User, portID, channelID, relayerAddr, counterpartyPayeeAddr string) (sdk.TxResponse, error) { + msg := feetypes.NewMsgRegisterCounterpartyPayee(portID, channelID, relayerAddr, counterpartyPayeeAddr) + return s.BroadcastMessages(ctx, chain, user, msg) +} + +// QueryCounterPartyPayee queries the counterparty payee of the given chain and relayer address on the specified channel. +func (s *FeeMiddlewareTestSuite) QueryCounterPartyPayee(ctx context.Context, chain ibc.Chain, relayerAddress, channelID string) (string, error) { + queryClient := s.GetChainGRCPClients(chain).FeeQueryClient + res, err := queryClient.CounterpartyPayee(ctx, &feetypes.QueryCounterpartyPayeeRequest{ + ChannelId: channelID, + Relayer: relayerAddress, + }) + + if err != nil { + return "", err + } + return res.CounterpartyPayee, nil +} + +// PayPacketFeeAsync broadcasts a MsgPayPacketFeeAsync message. +func (s *FeeMiddlewareTestSuite) PayPacketFeeAsync( + ctx context.Context, + chain *cosmos.CosmosChain, + user broadcast.User, + packetID channeltypes.PacketId, + packetFee feetypes.PacketFee, +) (sdk.TxResponse, error) { + msg := feetypes.NewMsgPayPacketFeeAsync(packetID, packetFee) + return s.BroadcastMessages(ctx, chain, user, msg) +} + +// QueryIncentivizedPacketsForChannel queries the incentivized packets on the specified channel. +func (s *FeeMiddlewareTestSuite) QueryIncentivizedPacketsForChannel( + ctx context.Context, + chain *cosmos.CosmosChain, + portId, + channelId string, +) ([]*feetypes.IdentifiedPacketFees, error) { + queryClient := s.GetChainGRCPClients(chain).FeeQueryClient + res, err := queryClient.IncentivizedPacketsForChannel(ctx, &feetypes.QueryIncentivizedPacketsForChannelRequest{ + PortId: portId, + ChannelId: channelId, + }) + if err != nil { + return nil, err + } + return res.IncentivizedPackets, err +} + func (s *FeeMiddlewareTestSuite) TestPlaceholder() { ctx := context.Background() r := s.SetupChainsRelayerAndChannel(ctx, feeMiddlewareChannelOptions()) s.T().Run("start relayer", func(t *testing.T) { s.StartRelayer(r) }) - } // feeMiddlewareChannelOptions configures both of the chains to have fee middleware enabled. diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index b99d150e255..76307590d9e 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -7,16 +7,23 @@ import ( "strings" "time" + "e2e/testconfig" + + sdk "github.com/cosmos/cosmos-sdk/types" dockerclient "github.com/docker/docker/client" "github.com/strangelove-ventures/ibctest" + "github.com/strangelove-ventures/ibctest/broadcast" "github.com/strangelove-ventures/ibctest/chain/cosmos" "github.com/strangelove-ventures/ibctest/ibc" + "github.com/strangelove-ventures/ibctest/test" "github.com/strangelove-ventures/ibctest/testreporter" "github.com/stretchr/testify/suite" "go.uber.org/zap" "go.uber.org/zap/zaptest" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" - "e2e/testconfig" + feetypes "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" ) const ( @@ -29,6 +36,8 @@ const ( // E2ETestSuite has methods and functionality which can be shared among all test suites. type E2ETestSuite struct { suite.Suite + + grpcClients map[string]GRPCClients paths map[string]path logger *zap.Logger DockerClient *dockerclient.Client @@ -36,6 +45,13 @@ type E2ETestSuite struct { startRelayerFn func(relayer ibc.Relayer) } +// GRPCClients holds a reference to any GRPC clients that are needed by the tests. +// These should typically be used for query clients only. If we need to make changes, we should +// use E2ETestSuite.BroadcastMessages to broadcast transactions instead. +type GRPCClients struct { + FeeQueryClient feetypes.QueryClient +} + // path is a pairing of two chains which will be used in a test. type path struct { chainA, chainB *cosmos.CosmosChain @@ -102,6 +118,9 @@ func (s *E2ETestSuite) SetupChainsRelayerAndChannel(ctx context.Context, channel time.Sleep(time.Second * 10) } + s.initGRPCClients(chainA) + s.initGRPCClients(chainB) + return r } @@ -129,6 +148,20 @@ func (s *E2ETestSuite) GetChains(chainOpts ...testconfig.ChainOptionConfiguratio return path.chainA, path.chainB } +// BroadcastMessages broadcasts the provided messages to the given chain and signs them on behalf of the provided user. +// Once the broadcast response is returned, we wait for a few blocks to be created on both chain A and chain B. +func (s *E2ETestSuite) BroadcastMessages(ctx context.Context, chain *cosmos.CosmosChain, user broadcast.User, msgs ...sdk.Msg) (sdk.TxResponse, error) { + broadcaster := cosmos.NewBroadcaster(s.T(), chain) + resp, err := ibctest.BroadcastTx(ctx, broadcaster, user, msgs...) + if err != nil { + return sdk.TxResponse{}, err + } + + chainA, chainB := s.GetChains() + err = test.WaitForBlocks(ctx, 2, chainA, chainB) + return resp, err +} + // GetRelayerWallets returns the relayer wallets associated with the chains. func (s *E2ETestSuite) GetRelayerWallets(relayer ibc.Relayer) (ibc.RelayerWallet, ibc.RelayerWallet, error) { chainA, chainB := s.GetChains() @@ -196,6 +229,37 @@ func (s *E2ETestSuite) GetChainBNativeBalance(ctx context.Context, user *ibctest return GetNativeChainBalance(ctx, chainB, user) } +// GetChainGRCPClients gets the GRPC clients associated with the given chain. +func (s *E2ETestSuite) GetChainGRCPClients(chain ibc.Chain) GRPCClients { + cs, ok := s.grpcClients[chain.Config().ChainID] + s.Require().True(ok, "chain %s does not have GRPC clients", chain.Config().ChainID) + return cs +} + +// initGRPCClients establishes GRPC clients with the given chain. +// The created GRPCClients can be retrieved with GetChainGRCPClients. +func (s *E2ETestSuite) initGRPCClients(chain *cosmos.CosmosChain) { + // Create a connection to the gRPC server. + grpcConn, err := grpc.Dial( + chain.GetHostGRPCAddress(), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + s.Require().NoError(err) + s.T().Cleanup(func() { + if err := grpcConn.Close(); err != nil { + s.T().Logf("failed closing GRPC connection to chain %s: %s", chain.Config().ChainID, err) + } + }) + + if s.grpcClients == nil { + s.grpcClients = make(map[string]GRPCClients) + } + + s.grpcClients[chain.Config().ChainID] = GRPCClients{ + FeeQueryClient: feetypes.NewQueryClient(grpcConn), + } +} + // createCosmosChains creates two separate chains in docker containers. // test and can be retrieved with GetChains. func (s *E2ETestSuite) createCosmosChains(chainOptions testconfig.ChainOptions) (*cosmos.CosmosChain, *cosmos.CosmosChain) { From 9776639b1a13811191c875c73e185efee577468f Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 19 Jul 2022 11:56:40 +0100 Subject: [PATCH 224/275] Build local image to run tests with make e2e-test (#1722) --- e2e/Makefile | 2 +- e2e/scripts/run-e2e.sh | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100755 e2e/scripts/run-e2e.sh diff --git a/e2e/Makefile b/e2e/Makefile index cad92172af9..95a0fa5b6a2 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -8,6 +8,6 @@ cleanup-ibc-test-containers: done e2e-test: cleanup-ibc-test-containers - @go test -v ./ --run $(suite) -testify.m ^$(test)$$ + ./scripts/run-e2e.sh $(suite) $(test) .PHONY: cleanup-ibc-test-containers e2e-test diff --git a/e2e/scripts/run-e2e.sh b/e2e/scripts/run-e2e.sh new file mode 100755 index 00000000000..1e0875c099f --- /dev/null +++ b/e2e/scripts/run-e2e.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -euo pipefail + +SUITE="${1}" +TEST="${2}" +export SIMD_TAG="${SIMD_TAG:-latest}" +export SIMD_IMAGE="${SIMD_IMAGE:-ibc-go-simd-e2e}" + +# In CI, the docker images will be built separately. +# context for building the image is one directory up. +if [ "${CI:-}" != "true" ] +then + (cd ..; docker build . -t "${SIMD_IMAGE}:${SIMD_TAG}") +fi + +go test -v ./ --run ${SUITE} -testify.m ^${TEST}$ From c809ce356c72b2fc5cc7a7a7f00c5d6928c77790 Mon Sep 17 00:00:00 2001 From: Aditya Date: Tue, 19 Jul 2022 13:53:04 +0200 Subject: [PATCH 225/275] Remove leftover crossing hello tests in connection handshake (#1724) * remove leftover crossing hello tests in connection handshake * fix bug in tests --- .../03-connection/keeper/handshake_test.go | 44 ++----------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/modules/core/03-connection/keeper/handshake_test.go b/modules/core/03-connection/keeper/handshake_test.go index d82a2cf22f5..aeabf5718c2 100644 --- a/modules/core/03-connection/keeper/handshake_test.go +++ b/modules/core/03-connection/keeper/handshake_test.go @@ -203,45 +203,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) }, false}, - {"invalid previous connection is in TRYOPEN", func() { - // open init chainA - err := path.EndpointA.ConnOpenInit() - suite.Require().NoError(err) - - // open try chainB - err = path.EndpointB.ConnOpenTry() - suite.Require().NoError(err) - - err = path.EndpointB.UpdateClient() - suite.Require().NoError(err) - - // retrieve client state of chainA to pass as counterpartyClient - counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - }, false}, - {"invalid previous connection has invalid versions", func() { - // open init chainA - err := path.EndpointA.ConnOpenInit() - suite.Require().NoError(err) - - // open try chainB - err = path.EndpointB.ConnOpenTry() - suite.Require().NoError(err) - - // modify connB to be in INIT with incorrect versions - connection, found := suite.chainB.App.GetIBCKeeper().ConnectionKeeper.GetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID) - suite.Require().True(found) - - connection.State = types.INIT - connection.Versions = []*types.Version{{}} - - suite.chainB.App.GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID, connection) - - err = path.EndpointB.UpdateClient() - suite.Require().NoError(err) - - // retrieve client state of chainA to pass as counterpartyClient - counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID) - }, false}, } for _, tc := range testCases { @@ -249,8 +210,9 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { suite.Run(tc.msg, func() { suite.SetupTest() // reset - consensusHeight = clienttypes.ZeroHeight() // must be explicitly changed in malleate - versions = types.GetCompatibleVersions() // must be explicitly changed in malleate + consensusHeight = clienttypes.ZeroHeight() // may be changed in malleate + versions = types.GetCompatibleVersions() // may be changed in malleate + delayPeriod = 0 // may be changed in malleate path = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.SetupClients(path) From 5b61a5b9d496d9d77231f7759bbc81b35027e285 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 19 Jul 2022 14:02:23 +0100 Subject: [PATCH 226/275] chore: adding environment variable to specify go relayer image (#1727) --- .github/workflows/e2e-fork.yml | 3 +++ .github/workflows/e2e.yaml | 2 ++ e2e/testconfig/testconfig.go | 10 ++++++++++ e2e/testsuite/relayer.go | 6 ++++-- e2e/testsuite/testsuite.go | 2 +- 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-fork.yml b/.github/workflows/e2e-fork.yml index c7add63f323..b3d8aa9b32b 100644 --- a/.github/workflows/e2e-fork.yml +++ b/.github/workflows/e2e-fork.yml @@ -40,6 +40,9 @@ jobs: with: go-version: 1.18 - name: Run e2e Test + env: + # see images here https://github.com/cosmos/relayer/pkgs/container/relayer/versions + RLY_TAG: "v2.0.0-rc2" run: | cd e2e make e2e-test suite=${{ matrix.suite }} test=${{ matrix.test }} diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 787559f18f3..12f52ef098e 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -82,6 +82,8 @@ jobs: env: SIMD_TAG: ${{ needs.determine-image-tag.outputs.simd-tag }} SIMD_IMAGE: ghcr.io/cosmos/ibc-go-simd-e2e + # see images here https://github.com/cosmos/relayer/pkgs/container/relayer/versions + RLY_TAG: "v2.0.0-rc2" strategy: fail-fast: false matrix: ${{ fromJSON(needs.build-test-matrix.outputs.matrix) }} diff --git a/e2e/testconfig/testconfig.go b/e2e/testconfig/testconfig.go index c043712b4e4..50d49edce53 100644 --- a/e2e/testconfig/testconfig.go +++ b/e2e/testconfig/testconfig.go @@ -11,12 +11,16 @@ const ( DefaultSimdImage = "ghcr.io/cosmos/ibc-go-simd-e2e" SimdImageEnv = "SIMD_IMAGE" SimdTagEnv = "SIMD_TAG" + GoRelayerTag = "RLY_TAG" + + defaultRlyTag = "main" ) // TestConfig holds various fields used in the E2E tests. type TestConfig struct { SimdImage string SimdTag string + RlyTag string } // FromEnv returns a TestConfig constructed from environment variables. @@ -31,9 +35,15 @@ func FromEnv() TestConfig { panic(fmt.Sprintf("must specify simd version for test with environment variable [%s]", SimdTagEnv)) } + rlyTag, ok := os.LookupEnv(GoRelayerTag) + if !ok { + rlyTag = defaultRlyTag + } + return TestConfig{ SimdImage: simdImage, SimdTag: simdTag, + RlyTag: rlyTag, } } diff --git a/e2e/testsuite/relayer.go b/e2e/testsuite/relayer.go index f71ef586ed9..123a54465d1 100644 --- a/e2e/testsuite/relayer.go +++ b/e2e/testsuite/relayer.go @@ -3,6 +3,8 @@ package testsuite import ( "testing" + "e2e/testconfig" + dockerclient "github.com/docker/docker/client" "github.com/strangelove-ventures/ibctest" "github.com/strangelove-ventures/ibctest/ibc" @@ -15,8 +17,8 @@ const ( ) // newCosmosRelayer returns an instance of the go relayer. -func newCosmosRelayer(t *testing.T, logger *zap.Logger, dockerClient *dockerclient.Client, network string) ibc.Relayer { - return ibctest.NewBuiltinRelayerFactory(ibc.CosmosRly, logger, relayer.CustomDockerImage(cosmosRelayerRepository, "main")).Build( +func newCosmosRelayer(t *testing.T, tc testconfig.TestConfig, logger *zap.Logger, dockerClient *dockerclient.Client, network string) ibc.Relayer { + return ibctest.NewBuiltinRelayerFactory(ibc.CosmosRly, logger, relayer.CustomDockerImage(cosmosRelayerRepository, tc.RlyTag)).Build( t, dockerClient, network, ) } diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 76307590d9e..d8b5387b305 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -74,7 +74,7 @@ func (s *E2ETestSuite) SetupChainsRelayerAndChannel(ctx context.Context, channel home, err := ioutil.TempDir("", "") s.Require().NoError(err) - r := newCosmosRelayer(s.T(), s.logger, s.DockerClient, s.network) + r := newCosmosRelayer(s.T(), testconfig.FromEnv(), s.logger, s.DockerClient, s.network) pathName := fmt.Sprintf("%s-path", s.T().Name()) pathName = strings.ReplaceAll(pathName, "/", "-") From d1649c029cbbd7b380eafd82d94ad3f8eea34398 Mon Sep 17 00:00:00 2001 From: tmsdkeys <98807841+tmsdkeys@users.noreply.github.com> Date: Tue, 19 Jul 2022 15:20:55 +0200 Subject: [PATCH 227/275] Thomas/1584 update docs apps (#1675) * restructure content according to outline, fix image and syntax highlighting, fix titles and prepare for content updates * rewrite bind port section * restructure applications doc into folder structure * add keeper section, make some minor corrections in bind ports, custom packet and implmenent IBC module sections * update ibcmodule interface to encorporate the simpliefied handshake callbacks and version negotiation * fix broken links * fix remaining broken link * fix some nits, correct for removal of crossing hellos and add some more explanation on portIDs * update middleware docs to resolve merge confilicts --- docs/.vuepress/config.js | 283 +++++++++++++++------------ docs/ibc/apps/apps.md | 51 +++++ docs/ibc/apps/bindports.md | 114 +++++++++++ docs/ibc/apps/ibcmodule.md | 342 +++++++++++++++++++++++++++++++++ docs/ibc/apps/keeper.md | 88 +++++++++ docs/ibc/apps/packets_acks.md | 99 ++++++++++ docs/ibc/apps/routing.md | 36 ++++ docs/ibc/integration.md | 6 +- docs/ibc/middleware/develop.md | 23 ++- 9 files changed, 902 insertions(+), 140 deletions(-) create mode 100644 docs/ibc/apps/apps.md create mode 100644 docs/ibc/apps/bindports.md create mode 100644 docs/ibc/apps/ibcmodule.md create mode 100644 docs/ibc/apps/keeper.md create mode 100644 docs/ibc/apps/packets_acks.md create mode 100644 docs/ibc/apps/routing.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index a15407fd54a..a5841915b3b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -3,19 +3,48 @@ module.exports = { title: "IBC-Go", locales: { "/": { - lang: "en-US" + lang: "en-US", }, }, base: process.env.VUEPRESS_BASE || "/", head: [ - ['link', { rel: "apple-touch-icon", sizes: "180x180", href: "/apple-touch-icon.png" }], - ['link', { rel: "icon", type: "image/png", sizes: "32x32", href: "/favicon-32x32.png" }], - ['link', { rel: "icon", type: "image/png", sizes: "16x16", href: "/favicon-16x16.png" }], - ['link', { rel: "manifest", href: "/site.webmanifest" }], - ['meta', { name: "msapplication-TileColor", content: "#2e3148" }], - ['meta', { name: "theme-color", content: "#ffffff" }], - ['link', { rel: "icon", type: "image/svg+xml", href: "/favicon-svg.svg" }], - ['link', { rel: "apple-touch-icon-precomposed", href: "/apple-touch-icon-precomposed.png" }], + [ + "link", + { + rel: "apple-touch-icon", + sizes: "180x180", + href: "/apple-touch-icon.png", + }, + ], + [ + "link", + { + rel: "icon", + type: "image/png", + sizes: "32x32", + href: "/favicon-32x32.png", + }, + ], + [ + "link", + { + rel: "icon", + type: "image/png", + sizes: "16x16", + href: "/favicon-16x16.png", + }, + ], + ["link", { rel: "manifest", href: "/site.webmanifest" }], + ["meta", { name: "msapplication-TileColor", content: "#2e3148" }], + ["meta", { name: "theme-color", content: "#ffffff" }], + ["link", { rel: "icon", type: "image/svg+xml", href: "/favicon-svg.svg" }], + [ + "link", + { + rel: "apple-touch-icon-precomposed", + href: "/apple-touch-icon-precomposed.png", + }, + ], ], themeConfig: { repo: "cosmos/ibc-go", @@ -32,109 +61,109 @@ module.exports = { //}, versions: [ { - "label": "main", - "key": "main" + label: "main", + key: "main", }, { - "label": "v1.1.0", - "key": "v1.1.0" + label: "v1.1.0", + key: "v1.1.0", }, { - "label": "v1.2.0", - "key": "v1.2.0" + label: "v1.2.0", + key: "v1.2.0", }, { - "label": "v1.3.0", - "key": "v1.3.0" + label: "v1.3.0", + key: "v1.3.0", }, { - "label": "v1.5.0", - "key": "v1.5.0" + label: "v1.5.0", + key: "v1.5.0", }, { - "label": "v1.4.0", - "key": "v1.4.0" + label: "v1.4.0", + key: "v1.4.0", }, { - "label": "v2.0.0", - "key": "v2.0.0" - } , + label: "v2.0.0", + key: "v2.0.0", + }, { - "label": "v2.1.0", - "key": "v2.1.0" - }, - { - "label": "v2.2.0", - "key": "v2.2.0" + label: "v2.1.0", + key: "v2.1.0", }, - { - "label": "v2.3.0", - "key": "v2.3.0" + { + label: "v2.2.0", + key: "v2.2.0", }, { - "label": "v3.0.0", - "key": "v3.0.0" + label: "v2.3.0", + key: "v2.3.0", }, { - "label": "v3.1.0", - "key": "v3.1.0" - } + label: "v3.0.0", + key: "v3.0.0", + }, + { + label: "v3.1.0", + key: "v3.1.0", + }, ], topbar: { - banner: true + banner: true, }, - sidebar: { + sidebar: { auto: false, nav: [ - { + { title: "Using IBC-Go", children: [ { title: "Overview", directory: false, - path: "/ibc/overview.html" - }, + path: "/ibc/overview.html", + }, { title: "Integration", directory: false, - path: "/ibc/integration.html" + path: "/ibc/integration.html", }, { title: "Applications", - directory: false, - path: "/ibc/apps.html" + directory: true, + path: "/ibc/apps", }, { title: "Middleware", directory: true, - path: "/ibc/middleware" + path: "/ibc/middleware", }, { title: "Upgrades", directory: true, - path: "/ibc/upgrades" + path: "/ibc/upgrades", }, { title: "Governance Proposals", directory: false, - path: "/ibc/proposals.html" + path: "/ibc/proposals.html", }, { title: "Relayer", directory: false, - path: "/ibc/relayer.html" + path: "/ibc/relayer.html", }, { title: "Protobuf Documentation", directory: false, - path: "/ibc/proto-docs.html" + path: "/ibc/proto-docs.html", }, { title: "Roadmap", directory: false, - path: "/roadmap/roadmap.html" + path: "/roadmap/roadmap.html", }, - ] + ], }, { title: "IBC Application Modules", @@ -147,34 +176,34 @@ module.exports = { { title: "Overview", directory: false, - path: "/apps/interchain-accounts/overview.html" - }, + path: "/apps/interchain-accounts/overview.html", + }, { title: "Authentication Modules", directory: false, - path: "/apps/interchain-accounts/auth-modules.html" + path: "/apps/interchain-accounts/auth-modules.html", }, { title: "Active Channels", directory: false, - path: "/apps/interchain-accounts/active-channels.html" + path: "/apps/interchain-accounts/active-channels.html", }, { title: "Integration", directory: false, - path: "/apps/interchain-accounts/integration.html" + path: "/apps/interchain-accounts/integration.html", }, { title: "Parameters", directory: false, - path: "/apps/interchain-accounts/parameters.html" + path: "/apps/interchain-accounts/parameters.html", }, { title: "Transactions", directory: false, - path: "/apps/interchain-accounts/transactions.html" + path: "/apps/interchain-accounts/transactions.html", }, - ] + ], }, { title: "Transfer", @@ -184,41 +213,41 @@ module.exports = { { title: "Overview", directory: false, - path: "/apps/transfer/overview.html" - }, + path: "/apps/transfer/overview.html", + }, { title: "State", directory: false, - path: "/apps/transfer/state.html" + path: "/apps/transfer/state.html", }, { title: "State Transitions", directory: false, - path: "/apps/transfer/state-transitions.html" + path: "/apps/transfer/state-transitions.html", }, { title: "Messages", directory: false, - path: "/apps/transfer/messages.html" + path: "/apps/transfer/messages.html", }, { title: "Events", directory: false, - path: "/apps/transfer/events.html" + path: "/apps/transfer/events.html", }, { title: "Metrics", directory: false, - path: "/apps/transfer/metrics.html" + path: "/apps/transfer/metrics.html", }, { title: "Params", directory: false, - path: "/apps/transfer/params.html" + path: "/apps/transfer/params.html", }, - ] + ], }, - ] + ], }, { title: "IBC Middleware Modules", @@ -231,77 +260,78 @@ module.exports = { { title: "Overview", directory: false, - path: "/middleware/ics29-fee/overview.html" - }, + path: "/middleware/ics29-fee/overview.html", + }, { title: "Integration", directory: false, - path: "/middleware/ics29-fee/integration.html" + path: "/middleware/ics29-fee/integration.html", }, { title: "End Users", directory: false, - path: "/middleware/ics29-fee/end-users.html" + path: "/middleware/ics29-fee/end-users.html", }, { title: "Fee Messages", directory: false, - path: "/middleware/ics29-fee/msgs.html" + path: "/middleware/ics29-fee/msgs.html", }, { title: "Fee Distribution", directory: false, - path: "/middleware/ics29-fee/fee-distribution.html" + path: "/middleware/ics29-fee/fee-distribution.html", }, { title: "Events", directory: false, - path: "/middleware/ics29-fee/events.html" + path: "/middleware/ics29-fee/events.html", }, - ] + ], }, - ] + ], }, { title: "Migrations", children: [ { - title: "Support transfer of coins whose base denom contains slashes", + title: + "Support transfer of coins whose base denom contains slashes", directory: false, - path: "/migrations/support-denoms-with-slashes.html" + path: "/migrations/support-denoms-with-slashes.html", }, { title: "SDK v0.43 to IBC-Go v1", directory: false, - path: "/migrations/sdk-to-v1.html" + path: "/migrations/sdk-to-v1.html", }, { title: "IBC-Go v1 to v2", directory: false, - path: "/migrations/v1-to-v2.html" + path: "/migrations/v1-to-v2.html", }, { title: "IBC-Go v2 to v3", directory: false, - path: "/migrations/v2-to-v3.html" + path: "/migrations/v2-to-v3.html", }, { title: "IBC-Go v3 to v4", directory: false, - path: "/migrations/v3-to-v4.html" + path: "/migrations/v3-to-v4.html", }, - ] + ], }, { title: "Resources", children: [ { title: "IBC Specification", - path: "https://github.com/cosmos/ibc" + path: "https://github.com/cosmos/ibc", }, - ] - } - ] + ], + }, + ], }, gutter: { title: "Help & Support", @@ -310,46 +340,46 @@ module.exports = { title: "Discord", text: "Chat with IBC developers on Discord.", url: "https://discordapp.com/channels/669268347736686612", - bg: "linear-gradient(225.11deg, #2E3148 0%, #161931 95.68%)" + bg: "linear-gradient(225.11deg, #2E3148 0%, #161931 95.68%)", }, github: { title: "Found an Issue?", - text: "Help us improve this page by suggesting edits on GitHub." - } + text: "Help us improve this page by suggesting edits on GitHub.", + }, }, footer: { question: { - text: "Chat with IBC developers in Discord." + text: "Chat with IBC developers in Discord.", }, textLink: { text: "ibcprotocol.org", - url: "https://ibcprotocol.org" + url: "https://ibcprotocol.org", }, services: [ { service: "medium", - url: "https://blog.cosmos.network/" + url: "https://blog.cosmos.network/", }, { service: "twitter", - url: "https://twitter.com/cosmos" + url: "https://twitter.com/cosmos", }, { service: "linkedin", - url: "https://www.linkedin.com/company/interchain-gmbh" + url: "https://www.linkedin.com/company/interchain-gmbh", }, { service: "reddit", - url: "https://reddit.com/r/cosmosnetwork" + url: "https://reddit.com/r/cosmosnetwork", }, { service: "telegram", - url: "https://t.me/cosmosproject" + url: "https://t.me/cosmosproject", }, { service: "youtube", - url: "https://www.youtube.com/c/CosmosProject" - } + url: "https://www.youtube.com/c/CosmosProject", + }, ], smallprint: "The development of IBC-Go is led primarily by [Interchain GmbH](https://interchain.berlin/). Funding for this development comes primarily from the Interchain Foundation, a Swiss non-profit.", @@ -359,64 +389,63 @@ module.exports = { children: [ { title: "Cosmos SDK", - url: "https://docs.cosmos.network" + url: "https://docs.cosmos.network", }, { title: "Cosmos Hub", - url: "https://hub.cosmos.network" + url: "https://hub.cosmos.network", }, { title: "Tendermint Core", - url: "https://docs.tendermint.com" - } - ] + url: "https://docs.tendermint.com", + }, + ], }, { title: "Community", children: [ { title: "Cosmos blog", - url: "https://blog.cosmos.network" + url: "https://blog.cosmos.network", }, { title: "Forum", - url: "https://forum.cosmos.network" + url: "https://forum.cosmos.network", }, { title: "Chat", - url: "https://discord.gg/W8trcGV" - } - ] + url: "https://discord.gg/W8trcGV", + }, + ], }, { title: "Contributing", children: [ { title: "Contributing to the docs", - url: - "https://github.com/cosmos/ibc-go/blob/main/docs/DOCS_README.md" + url: "https://github.com/cosmos/ibc-go/blob/main/docs/DOCS_README.md", }, { title: "Source code on GitHub", - url: "https://github.com/cosmos/ibc-go/" - } - ] - } - ] - } + url: "https://github.com/cosmos/ibc-go/", + }, + ], + }, + ], + }, }, plugins: [ [ "@vuepress/google-analytics", { - ga: "UA-51029217-2" - } + ga: "UA-51029217-2", + }, ], [ "sitemap", { - hostname: "https://ibc.cosmos.network" - } - ] - ] + hostname: "https://ibc.cosmos.network", + }, + ], + ], }; diff --git a/docs/ibc/apps/apps.md b/docs/ibc/apps/apps.md new file mode 100644 index 00000000000..a24032168aa --- /dev/null +++ b/docs/ibc/apps/apps.md @@ -0,0 +1,51 @@ + + +# IBC Applications + +Learn how to build custom IBC application modules that enable packets to be sent to and received from other IBC-enabled chains. {synopsis} + +This document serves as a guide for developers who want to write their own Inter-blockchain Communication Protocol (IBC) applications for custom use cases. + +Due to the modular design of the IBC protocol, IBC application developers do not need to concern themselves with the low-level details of clients, connections, and proof verification. Nevertheless, an overview of these low-level concepts can be found in [the Overview section](../overview.md). +The document goes into detail on the abstraction layer most relevant for application developers (channels and ports), and describes how to define your own custom packets, `IBCModule` callbacks and more to make an application module IBC ready. + +**To have your module interact over IBC you must:** + +- implement the `IBCModule` interface, i.e.: + - channel (opening) handshake callbacks + - channel closing handshake callbacks + - packet callbacks +- bind to a port(s) +- add keeper methods +- define your own packet data and acknowledgement structs as well as how to encode/decode them +- add a route to the IBC router + +The following sections provide a more detailed explanation of how to write an IBC application +module correctly corresponding to the listed steps. + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +## Working example + +For a real working example of an IBC application, you can look through the `ibc-transfer` module +which implements everything discussed in this section. + +Here are the useful parts of the module to look at: + +[Binding to transfer +port](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/genesis.go) + +[Sending transfer +packets](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/relay.go) + +[Implementing IBC +callbacks](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/ibc_module.go) + +## Next {hide} + +Learn about [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/intro.md) {hide} diff --git a/docs/ibc/apps/bindports.md b/docs/ibc/apps/bindports.md new file mode 100644 index 00000000000..c0cfa703191 --- /dev/null +++ b/docs/ibc/apps/bindports.md @@ -0,0 +1,114 @@ + + +# Bind ports + +Learn what changes to make to bind modules to their ports on initialization. {synopsis} + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +Currently, ports must be bound on app initialization. In order to bind modules to their respective ports on initialization, the following needs to be implemented: + +> Note that `portID` does not refer to a certain numerical ID, like `localhost:8080` with a `portID` 8080. Rather it refers to the application module the port binds. For IBC Modules built with the Cosmos SDK, it defaults to the module's name and for Cosmwasm contracts it defaults to the contract address. + +1. Add port ID to the `GenesisState` proto definition: + + ```protobuf + message GenesisState { + string port_id = 1; + // other fields + } + ``` + +1. Add port ID as a key to the module store: + + ```go + // x//types/keys.go + const ( + // ModuleName defines the IBC Module name + ModuleName = "moduleName" + + // Version defines the current version the IBC + // module supports + Version = "moduleVersion-1" + + // PortID is the default port id that module binds to + PortID = "portID" + + // ... + ) + ``` + +1. Add port ID to `x//types/genesis.go`: + + ```go + // in x//types/genesis.go + + // DefaultGenesisState returns a GenesisState with "transfer" as the default PortID. + func DefaultGenesisState() *GenesisState { + return &GenesisState{ + PortId: PortID, + // additional k-v fields + } + } + + // Validate performs basic genesis state validation returning an error upon any + // failure. + func (gs GenesisState) Validate() error { + if err := host.PortIdentifierValidator(gs.PortId); err != nil { + return err + } + //addtional validations + + return gs.Params.Validate() + } + ``` + +1. Bind to port(s) in the module keeper's `InitGenesis`: + + ```go + // InitGenesis initializes the ibc-module state and binds to PortID. + func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { + k.SetPort(ctx, state.PortId) + + // ... + + // Only try to bind to port if it is not already bound, since we may already own + // port capability from capability InitGenesis + if !k.IsBound(ctx, state.PortId) { + // transfer module binds to the transfer port on InitChain + // and claims the returned capability + err := k.BindPort(ctx, state.PortId) + if err != nil { + panic(fmt.Sprintf("could not claim port capability: %v", err)) + } + } + + // ... + } + ``` + + With: + + ```go + // IsBound checks if the module is already bound to the desired port + func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { + _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) + return ok + } + + // BindPort defines a wrapper function for the port Keeper's function in + // order to expose it to module's InitGenesis function + func (k Keeper) BindPort(ctx sdk.Context, portID string) error { + cap := k.portKeeper.BindPort(ctx, portID) + return k.ClaimCapability(ctx, cap, host.PortPath(portID)) + } + ``` + + The module binds to the desired port(s) and returns the capabilities. + + In the above we find reference to keeper methods that wrap other keeper functionality, in the next section the keeper methods that need to be implemented will be defined. diff --git a/docs/ibc/apps/ibcmodule.md b/docs/ibc/apps/ibcmodule.md new file mode 100644 index 00000000000..d5864435700 --- /dev/null +++ b/docs/ibc/apps/ibcmodule.md @@ -0,0 +1,342 @@ + + +# Implement `IBCModule` interface and callbacks + +Learn how to implement the `IBCModule` interface and all of the callbacks it requires. {synopsis} + +The Cosmos SDK expects all IBC modules to implement the [`IBCModule` +interface](https://github.com/cosmos/ibc-go/tree/main/modules/core/05-port/types/module.go). This interface contains all of the callbacks IBC expects modules to implement. They include callbacks related to channel handshake, closing and packet callbacks (`OnRecvPacket`, `OnAcknowledgementPacket` and `OnTimeoutPacket`). + +```go +// IBCModule implements the ICS26 interface for given the keeper. +// The implementation of the IBCModule interface could for example be in a file called ibc_module.go, +// but ultimately file structure is up to the developer +type IBCModule struct { + keeper keeper.Keeper +} +``` + +Additionally, in the `module.go` file, add the following line: + +```go +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + // Add this line + _ porttypes.IBCModule = IBCModule{} +) +``` + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +## Channel handshake callbacks + +This section will describe the callbacks that are called during channel handshake execution. Among other things, it will claim channel capabilities passed on from core IBC. For a refresher on capabilities, check [the Overview section](../overview.md#capabilities). + +Here are the channel handshake callbacks that modules are expected to implement: + +> Note that some of the code below is _pseudo code_, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `checkArguments` and `negotiateAppVersion` functions. + +```go +// Called by IBC Handler on MsgOpenInit +func (im IBCModule) OnChanOpenInit(ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version string, +) (string, error) { + // ... do custom initialization logic + + // Use above arguments to determine if we want to abort handshake + // Examples: + // - Abort if order == UNORDERED, + // - Abort if version is unsupported + if err := checkArguments(args); err != nil { + return "", err + } + + // OpenInit must claim the channelCapability that IBC passes into the callback + if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", err + } + + return version, nil +} + +// Called by IBC Handler on MsgOpenTry +func (im IBCModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + // ... do custom initialization logic + + // Use above arguments to determine if we want to abort handshake + if err := checkArguments(args); err != nil { + return "", err + } + + // OpenTry must claim the channelCapability that IBC passes into the callback + if err := im.keeper.scopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return err + } + + // Construct application version + // IBC applications must return the appropriate application version + // This can be a simple string or it can be a complex version constructed + // from the counterpartyVersion and other arguments. + // The version returned will be the channel version used for both channel ends. + appVersion := negotiateAppVersion(counterpartyVersion, args) + + return appVersion, nil +} + +// Called by IBC Handler on MsgOpenAck +func (im IBCModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + if counterpartyVersion != types.Version { + return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) + } + + // do custom logic + + return nil +} + +// Called by IBC Handler on MsgOpenConfirm +func (im IBCModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // do custom logic + + return nil +} +``` + +The channel closing handshake will also invoke module callbacks that can return errors to abort the closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls `ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`. + +```go +// Called by IBC Handler on MsgCloseInit +func (im IBCModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + // ... do custom finalization logic + + // Use above arguments to determine if we want to abort handshake + err := checkArguments(args) + return err +} + +// Called by IBC Handler on MsgCloseConfirm +func (im IBCModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // ... do custom finalization logic + + // Use above arguments to determine if we want to abort handshake + err := checkArguments(args) + return err +} +``` + +### Channel handshake version negotiation + +Application modules are expected to verify versioning used during the channel handshake procedure. + +- `OnChanOpenInit` will verify that the relayer-chosen parameters + are valid and perform any custom `INIT` logic. + It may return an error if the chosen parameters are invalid + in which case the handshake is aborted. + If the provided version string is non-empty, `OnChanOpenInit` should return + the version string if valid or an error if the provided version is invalid. + **If the version string is empty, `OnChanOpenInit` is expected to + return a default version string representing the version(s) + it supports.** + If there is no default version string for the application, + it should return an error if the provided version is an empty string. +- `OnChanOpenTry` will verify the relayer-chosen parameters along with the + counterparty-chosen version string and perform custom `TRY` logic. + If the relayer-chosen parameters + are invalid, the callback must return an error to abort the handshake. + If the counterparty-chosen version is not compatible with this module's + supported versions, the callback must return an error to abort the handshake. + If the versions are compatible, the try callback must select the final version + string and return it to core IBC. + `OnChanOpenTry` may also perform custom initialization logic. +- `OnChanOpenAck` will error if the counterparty selected version string + is invalid and abort the handshake. It may also perform custom ACK logic. + +Versions must be strings but can implement any versioning structure. If your application plans to +have linear releases then semantic versioning is recommended. If your application plans to release +various features in between major releases then it is advised to use the same versioning scheme +as IBC. This versioning scheme specifies a version identifier and compatible feature set with +that identifier. Valid version selection includes selecting a compatible version identifier with +a subset of features supported by your application for that version. The struct used for this +scheme can be found in [03-connection/types](https://github.com/cosmos/ibc-go/blob/main/modules/core/03-connection/types/version.go#L16). + +Since the version type is a string, applications have the ability to do simple version verification +via string matching or they can use the already impelemented versioning system and pass the proto +encoded version into each handhshake call as necessary. + +ICS20 currently implements basic string matching with a single supported version. + +## Packet callbacks + +Just as IBC expects modules to implement callbacks for channel handshakes, it also expects modules to implement callbacks for handling the packet flow through a channel, as defined in the `IBCModule` interface. + +Once a module A and module B are connected to each other, relayers can start relaying packets and acknowledgements back and forth on the channel. + +![IBC packet flow diagram](https://ibcprotocol.org/_nuxt/img/packet_flow.1d89ee0.png) + +Briefly, a successful packet flow works as follows: + +1. module A sends a packet through the IBC module +2. the packet is received by module B +3. if module B writes an acknowledgement of the packet then module A will process the + acknowledgement +4. if the packet is not successfully received before the timeout, then module A processes the + packet's timeout. + +### Sending packets + +Modules **do not send packets through callbacks**, since the modules initiate the action of sending packets to the IBC module, as opposed to other parts of the packet flow where messages sent to the IBC +module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`. + +> Note that some of the code below is _pseudo code_, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `EncodePacketData(customPacketData)` function. + +```go +// retrieve the dynamic capability for this channel +channelCap := scopedKeeper.GetCapability(ctx, channelCapName) +// Sending custom application packet data +data := EncodePacketData(customPacketData) +packet.Data = data +// Send packet to IBC, authenticating with channelCap +IBCChannelKeeper.SendPacket(ctx, channelCap, packet) +``` + +::: warning +In order to prevent modules from sending packets on channels they do not own, IBC expects +modules to pass in the correct channel capability for the packet's source channel. +::: + +### Receiving packets + +To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets +invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC +keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state +changes given the packet data without worrying about whether the packet is valid or not. + +Modules may return to the IBC handler an acknowledgement which implements the `Acknowledgement` interface. +The IBC handler will then commit this acknowledgement of the packet so that a relayer may relay the +acknowledgement back to the sender module. + +The state changes that occurred during this callback will only be written if: + +- the acknowledgement was successful as indicated by the `Success()` function of the acknowledgement +- if the acknowledgement returned is nil indicating that an asynchronous process is occurring + +NOTE: Applications which process asynchronous acknowledgements must handle reverting state changes +when appropriate. Any state changes that occurred during the `OnRecvPacket` callback will be written +for asynchronous acknowledgements. + +> Note that some of the code below is _pseudo code_, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodePacketData(packet.Data)` function. + +```go +func (im IBCModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) ibcexported.Acknowledgement { + // Decode the packet data + packetData := DecodePacketData(packet.Data) + + // do application state changes based on packet data and return the acknowledgement + // NOTE: The acknowledgement will indicate to the IBC handler if the application + // state changes should be written via the `Success()` function. Application state + // changes are only written if the acknowledgement is successful or the acknowledgement + // returned is nil indicating that an asynchronous acknowledgement will occur. + ack := processPacket(ctx, packet, packetData) + + return ack +} +``` + +Reminder, the `Acknowledgement` interface: + +```go +// Acknowledgement defines the interface used to return +// acknowledgements in the OnRecvPacket callback. +type Acknowledgement interface { + Success() bool + Acknowledgement() []byte +} +``` + +### Acknowledging packets + +After a module writes an acknowledgement, a relayer can relay back the acknowledgement to the sender module. The sender module can +then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the +acknowledgement is entirely up to the modules on the channel (just like the packet data); however, it +may often contain information on whether the packet was successfully processed along +with some additional data that could be useful for remediation if the packet processing failed. + +Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and +acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback +is responsible for decoding the acknowledgement and processing it. + +> Note that some of the code below is _pseudo code_, indicating what actions need to happen but leaving it up to the developer to implement a custom implementation. E.g. the `DecodeAcknowledgement(acknowledgments)` and `processAck(ack)` functions. + +```go +func (im IBCModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, +) (*sdk.Result, error) { + // Decode acknowledgement + ack := DecodeAcknowledgement(acknowledgement) + + // process ack + res, err := processAck(ack) + return res, err +} +``` + +### Timeout packets + +If the timeout for a packet is reached before the packet is successfully received or the +counterparty channel end is closed before the packet is successfully received, then the receiving +chain can no longer process it. Thus, the sending chain must process the timeout using +`OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is +indeed valid, so our module only needs to implement the state machine logic for what to do once a +timeout is reached and the packet can no longer be received. + +```go +func (im IBCModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) (*sdk.Result, error) { + // do custom timeout logic +} +``` diff --git a/docs/ibc/apps/keeper.md b/docs/ibc/apps/keeper.md new file mode 100644 index 00000000000..6cbba0fbb8f --- /dev/null +++ b/docs/ibc/apps/keeper.md @@ -0,0 +1,88 @@ + + +# Keeper + +Learn how to implement the IBC Module keeper. {synopsis} + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +In the previous sections, on channel handshake callbacks and port binding in `InitGenesis`, a reference was made to keeper methods that need to be implemented when creating a custom IBC module. Below is an overview of how to define an IBC module's keeper. + +> Note that some code has been left out for clarity, to get a full code overview, please refer to [the transfer module's keeper in the ibc-go repo](https://github.com/cosmos/ibc-go/blob/main/modules/apps/transfer/keeper/keeper.go). + +```go +// Keeper defines the IBC app module keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc codec.BinaryCodec + paramSpace paramtypes.Subspace + + channelKeeper types.ChannelKeeper + portKeeper types.PortKeeper + scopedKeeper capabilitykeeper.ScopedKeeper + + // ... additional according to custom logic +} + +// NewKeeper creates a new IBC app module Keeper instance +func NewKeeper( + // args +) Keeper { + // ... + + return Keeper{ + cdc: cdc, + storeKey: key, + paramSpace: paramSpace, + + channelKeeper: channelKeeper, + portKeeper: portKeeper, + scopedKeeper: scopedKeeper, + + // ... additional according to custom logic + } +} + +// IsBound checks if the IBC app module is already bound to the desired port +func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { + _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) + return ok +} + +// BindPort defines a wrapper function for the port Keeper's function in +// order to expose it to module's InitGenesis function +func (k Keeper) BindPort(ctx sdk.Context, portID string) error { + cap := k.portKeeper.BindPort(ctx, portID) + return k.ClaimCapability(ctx, cap, host.PortPath(portID)) +} + +// GetPort returns the portID for the IBC app module. Used in ExportGenesis +func (k Keeper) GetPort(ctx sdk.Context) string { + store := ctx.KVStore(k.storeKey) + return string(store.Get(types.PortKey)) +} + +// SetPort sets the portID for the IBC app module. Used in InitGenesis +func (k Keeper) SetPort(ctx sdk.Context, portID string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.PortKey, []byte(portID)) +} + +// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function +func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { + return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) +} + +// ClaimCapability allows the IBC app module to claim a capability that core IBC +// passes to it +func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { + return k.scopedKeeper.ClaimCapability(ctx, cap, name) +} + +// ... additional according to custom logic +``` diff --git a/docs/ibc/apps/packets_acks.md b/docs/ibc/apps/packets_acks.md new file mode 100644 index 00000000000..1871eca8915 --- /dev/null +++ b/docs/ibc/apps/packets_acks.md @@ -0,0 +1,99 @@ + + +# Define packets and acks + +Learn how to define custom packet and acknowledgement structs and how to encode and decode them. {synopsis} + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +## Custom packets + +Modules connected by a channel must agree on what application data they are sending over the +channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up +to each application module to determine how to implement this agreement. However, for most +applications this will happen as a version negotiation during the channel handshake. While more +complex version negotiation is possible to implement inside the channel opening handshake, a very +simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/ibc-go/tree/main/modules/apps/transfer/module.go). + +Thus, a module must define its custom packet data structure, along with a well-defined way to +encode and decode it to and from `[]byte`. + +```go +// Custom packet data defined in application module +type CustomPacketData struct { + // Custom fields ... +} + +EncodePacketData(packetData CustomPacketData) []byte { + // encode packetData to bytes +} + +DecodePacketData(encoded []byte) (CustomPacketData) { + // decode from bytes to packet data +} +``` + +> Note that the `CustomPacketData` struct is defined in the proto definition and then compiled by the protobuf compiler. + +Then a module must encode its packet data before sending it through IBC. + +```go +// Sending custom application packet data +data := EncodePacketData(customPacketData) +packet.Data = data +IBCChannelKeeper.SendPacket(ctx, packet) +``` + +A module receiving a packet must decode the `PacketData` into a structure it expects so that it can +act on it. + +```go +// Receiving custom application packet data (in OnRecvPacket) +packetData := DecodePacketData(packet.Data) +// handle received custom packet data +``` + +## Acknowledgements + +Modules may commit an acknowledgement upon receiving and processing a packet in the case of synchronous packet processing. +In the case where a packet is processed at some later point after the packet has been received (asynchronous execution), the acknowledgement +will be written once the packet has been processed by the application which may be well after the packet receipt. + +NOTE: Most blockchain modules will want to use the synchronous execution model in which the module processes and writes the acknowledgement +for a packet as soon as it has been received from the IBC module. + +This acknowledgement can then be relayed back to the original sender chain, which can take action +depending on the contents of the acknowledgement. + +Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and +receive acknowledegments with the IBC modules as byte strings. + +Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an +acknowledgement struct along with encoding and decoding it, is very similar to the packet data +example above. [ICS 04](https://github.com/cosmos/ibc/blob/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope) +specifies a recommended format for acknowledgements. This acknowledgement type can be imported from +[channel types](https://github.com/cosmos/ibc-go/tree/main/modules/core/04-channel/types). + +While modules may choose arbitrary acknowledgement structs, a default acknowledgement types is provided by IBC [here](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/channel/v1/channel.proto): + +```protobuf +// Acknowledgement is the recommended acknowledgement format to be used by +// app-specific protocols. +// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental +// conflicts with other protobuf message formats used for acknowledgements. +// The first byte of any message with this format will be the non-ASCII values +// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: +// https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope +message Acknowledgement { + // response contains either a result or an error and must be non-empty + oneof response { + bytes result = 21; + string error = 22; + } +} +``` diff --git a/docs/ibc/apps/routing.md b/docs/ibc/apps/routing.md new file mode 100644 index 00000000000..1095462dcba --- /dev/null +++ b/docs/ibc/apps/routing.md @@ -0,0 +1,36 @@ + + +# Routing + +## Pre-requisites Readings + +- [IBC Overview](../overview.md)) {prereq} +- [IBC default integration](../integration.md) {prereq} + +Learn how to hook a route to the IBC router for the custom IBC module. {synopsis} + +As mentioned above, modules must implement the `IBCModule` interface (which contains both channel +handshake callbacks and packet handling callbacks). The concrete implementation of this interface +must be registered with the module name as a route on the IBC `Router`. + +```go +// app.go +func NewApp(...args) *App { +// ... + +// Create static IBC router, add module routes, then set and seal it +ibcRouter := port.NewRouter() + +ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) +// Note: moduleCallbacks must implement IBCModule interface +ibcRouter.AddRoute(moduleName, moduleCallbacks) + +// Setting Router will finalize all routes by sealing router +// No more routes can be added +app.IBCKeeper.SetRouter(ibcRouter) + +// ... +} +``` diff --git a/docs/ibc/integration.md b/docs/ibc/integration.md index 09c1d2d2de9..d2d9f057ea3 100644 --- a/docs/ibc/integration.md +++ b/docs/ibc/integration.md @@ -24,7 +24,7 @@ Integrating the IBC module to your SDK-based application is straighforward. The ### Module `BasicManager` and `ModuleAccount` permissions -The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, +The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, and `x/ibc-transfer`. After that, we need to grant `Minter` and `Burner` permissions to the `ibc-transfer` `ModuleAccount` to mint and burn relayed tokens. @@ -72,7 +72,7 @@ type App struct { ### Configure the `Keepers` -During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and +During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and `x/ibc-transfer` modules), we need to grant specific capabilities through the capability module `ScopedKeepers` so that we can authenticate the object-capability permissions for each of the IBC channels. @@ -221,4 +221,4 @@ different chains. If you want to have a broader view of the changes take a look ## Next {hide} -Learn about how to create [custom IBC modules](./apps.md) for your application {hide} +Learn about how to create [custom IBC modules](./apps/apps.md) for your application {hide} diff --git a/docs/ibc/middleware/develop.md b/docs/ibc/middleware/develop.md index 9adc5a8cfa7..157115b55e5 100644 --- a/docs/ibc/middleware/develop.md +++ b/docs/ibc/middleware/develop.md @@ -16,7 +16,7 @@ Middleware allows developers to define the extensions as separate modules that c - [IBC Overview](../overview.md) {prereq} - [IBC Integration](../integration.md) {prereq} -- [IBC Application Developer Guide](../apps.md) {prereq} +- [IBC Application Developer Guide](../apps/apps.md) {prereq} ## Definitions @@ -26,7 +26,7 @@ Middleware allows developers to define the extensions as separate modules that c `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. +`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 @@ -64,7 +64,10 @@ In the case where the IBC middleware expects to speak to a compatible IBC middle Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following: ```json -{"":"","app_version":""} +{ + "": "", + "app_version": "" +} ``` The `` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `fee_version`). @@ -90,12 +93,12 @@ func (im IBCModule) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) (string, error) { - // try to unmarshal JSON-encoded version string and pass + // try to unmarshal JSON-encoded version string and pass // the app-specific version to app callback. // otherwise, pass version directly to app callback. metadata, err := Unmarshal(version) if err != nil { - // Since it is valid for fee version to not be specified, + // Since it is valid for fee version to not be specified, // the above middleware version may be for another middleware. // Pass the entire version string onto the underlying application. return im.app.OnChanOpenInit( @@ -151,7 +154,7 @@ func OnChanOpenTry( ) (string, error) { doCustomLogic() - // try to unmarshal JSON-encoded version string and pass + // try to unmarshal JSON-encoded version string and pass // the app-specific version to app callback. // otherwise, pass version directly to app callback. cpMetadata, err := Unmarshal(counterpartyVersion) @@ -183,7 +186,7 @@ func OnChanOpenTry( if err != nil { return "", err } - + // negotiate final middleware version middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) version := constructVersion(middlewareVersion, appVersion) @@ -204,7 +207,7 @@ func OnChanOpenAck( counterpartyChannelID string, counterpartyVersion string, ) error { - // try to unmarshal JSON-encoded version string and pass + // try to unmarshal JSON-encoded version string and pass // the app-specific version to app callback. // otherwise, pass version directly to app callback. cpMetadata, err = UnmarshalJSON(counterpartyVersion) @@ -216,7 +219,7 @@ func OnChanOpenAck( return error } doCustomLogic() - + // call the underlying application's OnChanOpenTry callback return app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion) } @@ -373,7 +376,7 @@ See [here](https://github.com/cosmos/ibc-go/blob/48a6ae512b4ea42c29fdf6c6f5363f5 #### `GetAppVersion` ```go -// middleware must return the underlying application version +// middleware must return the underlying application version func GetAppVersion( ctx sdk.Context, portID, From aaccbd193f19f97f8068278141044bf324e6425c Mon Sep 17 00:00:00 2001 From: tmsdkeys <98807841+tmsdkeys@users.noreply.github.com> Date: Tue, 19 Jul 2022 16:10:28 +0200 Subject: [PATCH 228/275] update fee mw docs, add formating, fix typos, increase readability (#1665) * update fee mw docs, add formating, fix typos, increase readability * fix broken link * Apply suggestions from code review (De)capitalize headings and references to headings for consistency Co-authored-by: Carlos Rodriguez * resolving merge conflict * split the CLI commands and small typo correction Co-authored-by: Carlos Rodriguez --- docs/.vuepress/config.js | 10 +- docs/assets/fee-mw/feeflow.png | Bin 0 -> 394717 bytes docs/assets/fee-mw/msgpaypacket.png | Bin 0 -> 150696 bytes docs/assets/fee-mw/paypacketfeeasync.png | Bin 0 -> 142753 bytes docs/assets/fee-mw/registerrelayeraddr.png | Bin 0 -> 157337 bytes docs/middleware/ics29-fee/end-users.md | 5 +- docs/middleware/ics29-fee/events.md | 16 ++- docs/middleware/ics29-fee/fee-distribution.md | 70 ++++++---- docs/middleware/ics29-fee/msgs.md | 128 ++++++++++-------- docs/middleware/ics29-fee/overview.md | 22 ++- 10 files changed, 148 insertions(+), 103 deletions(-) create mode 100644 docs/assets/fee-mw/feeflow.png create mode 100644 docs/assets/fee-mw/msgpaypacket.png create mode 100644 docs/assets/fee-mw/paypacketfeeasync.png create mode 100644 docs/assets/fee-mw/registerrelayeraddr.png diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index a5841915b3b..f459a997da6 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -267,11 +267,6 @@ module.exports = { directory: false, path: "/middleware/ics29-fee/integration.html", }, - { - title: "End Users", - directory: false, - path: "/middleware/ics29-fee/end-users.html", - }, { title: "Fee Messages", directory: false, @@ -287,6 +282,11 @@ module.exports = { directory: false, path: "/middleware/ics29-fee/events.html", }, + { + title: "End Users", + directory: false, + path: "/middleware/ics29-fee/end-users.html", + }, ], }, ], diff --git a/docs/assets/fee-mw/feeflow.png b/docs/assets/fee-mw/feeflow.png new file mode 100644 index 0000000000000000000000000000000000000000..ba02071f4d8e8132ac527c279cf32da9d9dbe24d GIT binary patch literal 394717 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

    av2fjL-LGJ4S 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 z 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 literal 0 HcmV?d00001 From 1994802da7289e3fae1a177d109997b618c56bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 22 Mar 2022 15:24:40 +0100 Subject: [PATCH 049/275] Add alpha, beta, and rc release definitions (#1151) ## Description The proposed definitions for each phase of our release cycle. Please feel free to adjust my wording closes: #881 --- Before we can merge this PR, please make sure that all the following items have been checked off. If any of the checklist items are not applicable, please leave them but write a little note why. - [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md). - [ ] Wrote unit and integration [tests](https://github.com/cosmos/ibc-go/blob/master/CONTRIBUTING.md#testing) - [ ] Updated relevant documentation (`docs/`) or specification (`x//spec/`) - [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code). - [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md` - [ ] Re-reviewed `Files changed` in the Github PR explorer - [ ] Review `Codecov Report` in the comment section below once CI passes --- RELEASES.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 27f0874c650..839e8e06612 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -21,6 +21,38 @@ To summarize: **All our ibc-go releases allow chains to communicate successfully We ensure all major releases are supported by relayers ([hermes](https://github.com/informalsystems/ibc-rs), [rly](https://github.com/strangelove-ventures/relayer) and [ts-relayer](https://github.com/confio/ts-relayer) at the moment) which can relay between the new major release and older releases. We have no plans of upgrading to an IBC protocol specification v2.0, as this would be very disruptive to the ecosystem. +## Release cycle + +IBC-Go follows a traditional release cycle involving an alpha, beta, and rc (release candidate) releases before finalizing a new version. As ibc-go works in a non-traditional area, we apply our own interpretation to each release type. We reserve the right to make both go API breaking changes and state machine breaking changes throughout the entire release cycle. The stable release guarentees do not go into affect until a final release is performed. + +It is never advisable to use a non-final release in production. + +### Alpha + +Alpha releases are intended to make available new features as soon as they are functional. No correctness guarentees are made and alpha releases **may** contain serious security vulnerabilities, bugs, and lack of user tooling, so long as they don't affect the core functionality. + +Initial users of alpha releases are expected to be advanced, patient, and capable of handling unusual errors. Very basic integration testing will be performed by the ibc-go development team before alpha releases. + +An internal audit is typically performed before the alpha release allowing the development team to guage the maturity and stability of changes included in the next release. + +### Beta + +Beta releases are intended to signal design stability. While the go API is still subject to change, the core design of the new features should not be. Developers integrating the new features should expect to handle breaking changes when upgrading to RC's. + +Beta releases should not be made with known bugs or security vulnerabilities. Beta releases should focus on ironing out remaining bugs and filling out the UX functionality required by a final release. Beta releases should have a clearly defined scope of the features that will be included in the release. Only highly requested feature additions should be acted upon in this phase. + +When the development team has determined a release is ready to enter the RC phase, a final security audit should be performed. The security audit should be limited to looking for bugs and security vulnerabilities. Code improvements may be noted, but they should not be acted upon unless highly desirable. + +### RC + +RC's are release candidates. Final releases should contain little to no changes in comparison to the latest RC. Changes included in between RC releases should be limited to: +- Improved testing +- UX additions +- Bug fixes +- Highly requested changes by the community + +A release should not be finalized until the development team and the external community have done sufficient integration tests on the targeted release. + ## Stable Release Policy The beginning of a new major release series is marked by the release of a new major version. A major release series is comprised of all minor and patch releases made under the same major version number. The series continues to receive bug fixes (released as minor or patch releases) until it reaches end of life. The date when a major release series reaches end of life is determined by one of the two following methods: From f4a5dcb7fe5ad24fbec01f0e0fb72b79150792a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Mar 2022 14:42:22 +0000 Subject: [PATCH 050/275] build(deps): bump google.golang.org/protobuf from 1.27.1 to 1.28.0 (#1164) Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.27.1 to 1.28.0.

  • Bb6?ehyMyA0m4=k2?> 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�H1 zfK_hCRIXP%vU5g9nimKI1?HJW^>JCkqD=>%SWh6wFtB8!GF4cx37;)%-%7QY_CD*C z|M8;H9k+xBViT1})EJHlX~JZwPd}$|Qh*B-YQg4jX_RvRSM5p}ddZtYjBPSWPZIM@ zb6atZY$nd;a2wap_kjP#d^Gaw`st|}lZ>Y}kLNsJKsdTw3v2Sp&t;XKA zZ7z7k>I6r0Te{Y|e2I#sX)E74YY#@yO8BdA&W+@St;Noni!c8TNBhm&c$h`JO$1+i zr>pbAwf|sCxcwAS=+bw#y6aoNKsD+qP3;@(Cb)HU?Yht3|81gBDzo-43q_tweg33c z^GQ`LOt*)d@1y;cs>}^fOHxv-(lm?TJmQ;Ukam4+YmRSE*L_R&?_XiOpFA>y zikv)4M()KxRoC2|E8bXx;~ptMlDNhZ1eBEOSQ5kKTgyEV;gQweKhO{BXP5HoJN_NS zKBdsI6^RK-W5s7d_%8g|#wKHkYs zz-P(YT?cvnMcc(aSCYqCi~8m=VR3;-mqLC}2W&On{^x6ry=R-iYDg;lB^%r5--R)T z3QzfSC2!#h=ztJ34huzeY~>X^5|VIsNg6z9)MrtIN}Y-&rn;SN5hTw{lVee5xd#vf z+ee+FLzukut){LTI+vqbrfZ0l+;o3=t=ea2K`3M`$`qPo`TB8b5fy1hi7FBSCdBLp zIfnk?sLJH^Rb~4LJL|s0^?k`RgTDljLW2?(&JYZA(9R{LCVZ1~C60fn2is7>T?GzU z!azqYWUVL@6FxMc&e#;F%QpuR&i=04p0Nxbb(#S1 z*y`EpdfV^;d;*bl*H*IfuDY`CR1)68zt>2=hf!pd9js943}%A^uK$8QgYx(0tovbF z*SFdv&-uYE1ekBogNa>y^)8yQBP3ZHZrw(|-(0PO5{}t?m9Ye9eMnNIJw~vs!ZYlD z9FV)%O1}I^v!K^jp9Ldx$Y}_?ti8)-t~ar+)OyZ znsg%>ntJ`2ckHlGeTI~kg0K`B)&ycChG}VzsSp?f_d;3X%j)=MX zOH(8kBsTsb{%VplrFmFFj%;`95dZQC@fdn;XZ|>Q{%rb4@fGg_iGZ+3y;QX`kEZ5O z1(%xE+T(0mcX>gky!0NFUhuEU0fx;5x}jU0DA_>)q<=;ZjODk@AXFqTi7KNZUA1+W z1|r2bVMT=2W(x&cKL~E~k3&*l{40RBNuF3mDWJk#6{OK+npdo6c;VFd=p*b#tk@%> zs?gPXml4h@6;UhjWo*oco~=ShqrKq|p9Xy@HcV&!W2bViXr6#YTci~UR|1|Zm@lM) zVgK|1H!=wJUsB}r`y~21Gmq6q^zIP8TarfmI+4Hnhyq;WUCZ`e#RKTO!Vcp+k3~nZ zu^|o^jFP4T+|b_&7J6VgAzh+t5Zz{dbuJi{PZB%}VTPRk&1_w|5tzoUC@oZ2BW1dH z3Ai7A{mjZ@ANu|TpPTt+)H zC$dZOgC`CXjhc+V(;n>*eIkg)uhNRbV|Hp>D&xXImt>(b|K{;|gQY+X3^Sg-+bpKH`xU)NI(@u0MTa6%b@@hn&W3xFW72uwKM$P=Vo zMyF`0-RL67x!zkGB-S_ee;pzW&fJl&M~|ICGG4s*-(-pCO_5b>lyHrF)#@IJ7Oha6&N=p;2S=mxB|aV^?={UKG@oyI--jr@xhX)-+%d+mx6QZ zSbly7xV+=e$$+X#t4Wf7iPd~zkF|rcXxdrS37@u-n9t9TD`@%R(qvu<9#B&%JDrJ8 zBbDtb6!*}Z7G*duGZHRehD=D%LqYt-j_v|V_QHN*L+xA0fsxxbTht!eZ`c{;*KfoKRZwm>c$} z#74cu^z7Bfc;}YsYQ!1wv~c|Iu+bfR_HRY{4=y(+S?_Rf`(3Wo-UTY7y>Cq}3oAi1 zABO(~E$W}tf-WjY%0++T>qvpdmS%`7U$aDb>KP{B$bhAv#QlorBv0H-4G#M(iIEEH zc{KkML_A&S$feiBx0}t1Gzz%Mv19emr-ScFe#3rz5TSio-WE8#2E{wIvGjwh*OS%T z!Q*$AMsjbJsl1!`#!O;FIH&YQOYXOWTFqd^g|&UwDm^Fn_-lo0DmG;smbrYbI`aK6 zR;}Q(vgaZrsyvWWlOp~{Xi z`Q|sMP&xE6ArF{2G5!h!*2bJMR%DEF4>Q0gbUfrX+({aj9i-vtcu5{|Oe}qqOd7jz zN3?rOl)bO)k`~NP==%^jwa|pCMA`wpncDJu^+ENX8-0hIU0be{F~dS*lRju zOxKlVH>YJc@BghHcyUe?3~yNAleGmk6Y=w-K+ge8DN|5!jC>+}5+^lPAD=*`E%G|< zoU?~JK;c%O2W^6TlCqZ#ABk}+6BRT1EJ`q;MlRHDfv<`^wxO>9fDb)8Unoqg9Lwy?WtuOucSGlU038 z2IYSf)!%+>J1b~Ix>K&(IBfU7Hr&5f_6F^LUo-H%vP+*k8=6(U|04CN3ZdtyTMZ)L zGtacqR8L_`t;;`zY2+>CCYk;{NyN-Ze)~cI&0!W1Dr_GywshmcnV7Nl@ixrSNGOp2 z4}htiBL}F8o-Afdui5=O$ma1ejm^3PofK_fp>^EIt-PgKEc7T9i<%ru8Kd_-R-F2D z{zN8J8p^R*HgqWMsPwoV?#$PFcs8c`yOyrrf62Pwkz|VKFa@lpL6CI?^#0DU%GIC} z>c;9q(55WVAG?#sfAr*#aR(go?DG^#ZkTyR2^*alFWWZjKvS01zSnNE_txKtG(7Il zTGen6(Eq)ne)s1D!)(4T^I|}QpP50qky~Rkk4xuhlJ~GyPsY{!u8)^PThW{!!|xTT zo}UuZfCc~WPN`6a&VaS0jZDkN1DXQ>w`@9h^`1c7H$}>}6NhbWL$s%%sU{~M^V!zv zm1&3OT_*>)`zjn`7U;^JaUK|b=e z6{!IBX1L->gX+E`fz*L@YU4q-E~djI?dnC>GvUPw=2?xG>Tj8jxAgw(NGr2rjLS)$ zE_`{`8{3C4TLTV;&DO6lH4~TLZfj<$Tie4g0$AN(VqG3z0HDC38xH|+)wY87!`7N# zZt2 zA)GEX;p0$APm3J^#Vdb8KvL3+tO__`pO{4Fu;Hrv^7ot`Is+CFc-kOtEYLpti^>n( z1T8x%{?||exdb&gBRkVb(>r(j_u)qsC>q$|Oth6kD%?lX&neD?_Bj8~$MHWAzS66e z{bTo4-za(|b5T4AcmF(g7h;kxC&qFkuA#rDWZ#1^fteMTSUbUcw)XAQ>vR3|=xTqV zKR<%pbFpy`2roEsj4DAi10RuN<}0z^Dl$ZT>?!%{4Qi(GxFW~AE14Z+xqKWqg^N*| z`NdO6k;tz-?u=${=V?zphT1-j(<0YwFJ50&kv>QdU?bmRNLAxtTP5_xR!!UZ!x(_S zj*TGav~gQX7pHa;$gvE3<{1rF>61IN-=z|LuWVRAbQYrltTrZkriZr;zaUrmT8mSkvhKG>x_K*U<`!C;w_9GF=toG1Ljt#-``T< zO#~qG*sozs zExtSgzs$VSj2-%_x5kbU(62_FI$;0Y7{KIW=h($6^80KvYazh${idoFBEuuXyY=y>5m zEe6wZnjc<>CVwgvabQU;7V;0O0Kq6!fiU}6xycJzG$ysLXJnS+LjCmfo{l(DYnrex zC>7&pAd4aA*Wa`)K36eEI(mck_3xaXC%}_e{ZF1-K9QqtS?%mhfgQFv3eEzURO>%{b)m5u3|CSh)V;SA z5a_SN7kcF!1fMtBIB=Rse+tn5XWO-B?d(Uh zA5pa4<19!U@@}bJCk>3@O*xAxP!kHXVf+vs z&VJxi%hx!Gs>J&Eia)jxD!fclH3agLdsIJdtFXEE>5U6i$s${3KzPZbF>7mE(JS$| z13nOSu%}_ZN1R9F?R^-=o-vQj)9;37e49z1w1pi#68avPtLkev^9eD`c z5br53bmqeF-f1(UJKFV;GXhOYG_ZSG#ZebYP5x9Lx52Hd?X#wot@@g zwC>N-kuU!S=NeDd(X7{(RyamO&thR|ry^<$vsigp-r(20e4-ap=0}72o zCGehht95>Lhx!pf!Y>5RG$+&EOd}SISCoUlsRAF|lvFL9RD2{}3ei-o2|1i>aNnm{ zn<^g@dc?$eIwV^zYxO2Ss5a0SVF|nA)o{x*xPGsh0z3$Gw{JKmicLLq4Y*L-Msz!4 z``n*i_qh;z`7u0p`7BM@NW=<|fMKjr1|Kf(Pa7eL;*qlLG&@J zFkB_G==?ioDHKL*$6tIvNh@`pU;CP;Nba41j*r zjGt&j+m|e!a2t1)%HzJ6pm_fOjmQ%k#la~TtYL`^SsBV}N_F@cj|_?Ld|5gNFB|@u zA1{Q@oAy&d3;gB+=*Fv9EVRC z+`r`4NYDcb-J5*6eo8z-cJZ+N6jp(ZqH=@6T7Wb6=_tBu)*>#dzD^?BowSnwa4cML z2EF>VAv&za9kGid{hTWG>ZxS)bELNRXf@)ElpZ*YSdR%{QddzcKjZ`q9B5T zxL03K=9>4MsO+b|Hh^(}n0pf=VAf{r#eFp^spI(rs$1|;MUeOA(6@H7BG@Z-U zAo$m_F~Q==k9~tSee>?ip({3sw_|d&6_Zb)UU~H7tl0CJR|8tR3JsZJgDU}kc?c&W zmn-jwZsZf&wKa;?y}t3=hh+4CmBe)^g?#0@W!r zGU)A%LK8|bIjqX8Z`j6S-b)UL9CzgmAiQo>gv_^7b;_wgM%O~@*nHxTaeAJ8O>cRh zjY#bq{w=V|^HNGL<4nHkC?NM;1=o;1O)klDAp}$C2`L?139?*76L3J_XKxG%NPiaX zDj^w7CaL^!ANpSWeQm>v9{$t%GF_e36@LCap#I?-fbKn$1W8&K0lUVH#_q9no;w2q zPaJ6~{t@p6($I#_XE6}}F7)OWmH+$Rtm^!(ZK=(y<*G9j0YkUCcoWJ3-5_^3?Cj8@ zg;T48su0tDXbq}rBq`MWJEm8r>iU+!q3SoCs6W@pEvpc|@0eNzzt$yyiVMXg27%f1 zvMx9y99I&w%Rc_-D?6L*EAjYqe2Iu9Ry9aooM?o3xU>D5pFDWpNAZ1=iR@cFwyHem zl0^6Q*J^yonKf#HdkVWJosatTiPk;r5ygAnd4qyztQbHNUie+yffdHcK$@{CjdM5R6K1I$~S91W8+-?_$v)Yr4S$KgU z|1Fv20o5FWM%HK8rNhLT9&4+-z|`V9wpXSkHd+J`)KRiO>Dyx8*&ZAo!BXytO)r`L zjGJt~8N@#D#Fq&yrx3O*^iN)uPoPd@l9qN_85mtP{$h!XgF8?Xfr%w+}9~NUIsh~DD2KJ z3rTxh#en%CqGcgQ0qIxfO#8Onysw9stS^x1I9n_raCh`7HT0w=ZqvnKQRO^A0RKv} z&Q5U0#K-1MYjY#fe)yP7q$eAFMoGIQ;n?opRHz;1ZnLabl12}q@S2!|I{85cPMv8j z=xc704QX=lI+%H8vraCFP(7J%|IK8Q`Z;-3Pz|+1m?$d*U`j!FFYrH%Fa@TTa3oh`+@?Xhi;xl$A)I&#-a1BONGwQUf^Xf*o}fz z$fjHJT@+X?%nzWl45TWE+8?wwgO@z*H&5!@WoX#{USvJ1Iz^%t%S*W0(l*@z8Ri%H z`X&;hW#zc9Zx;XfQ5MZQf9v>1|H^FGiRDU>)3RXI=Z;AqUCjCFO&>N98m!0D?vl(m zOd3sw5Yf-`2LoXZ9jk@ouV`$f6=9Uqp7$KurzOFg`%^_l%4om1V#tO&pS~r*~z*A0Nj`Rl4#YPa2w&0si*%Ex4 zrLp2e*PhPlPZl!UK!@%P5NFcFu;fNiAuz^^yG8m>$kL|%NhQQc&C{1!mXc9uouCV; zD2KB5INb-x0%Tw9yFm!Bz?=ub$EO_b_q%DDieKg|lyi7RZaDKB3;fQ!Pbd)Mb#Z7j z5F`~X05-Hnqr4d-k-tLfz0|zcqPU1{x_~p3;{Eb~23FIt@x9V%Y4&S`A>V9{)Njdh z^2Y|6*7oW*XyXfJIa7j-egPjHKGK$pWSJi&d$)GHr~RD6v~cc_-a~WYI*tCgqff25 zAzi{Pl6a)UxNqxQ!d99LW}E!ozngGqJ6UISwUO!I0YnVRoBtUy>?_1r9=^W|QeX5L z;u(AHm*-Iq`S^oVT{jT(rrBY&I_TBlZiwX={r-matk89OwKFFO(grsGkuo?qEAZ^~!;ZVUeY1yS4%m}=wft;p5h zGz;V~MY2@>0@aFsO!w>fNz)=rj>XxjQNg3!TG_DM7~X)B>ou(*Y%u~ZltL^MisX41zK-hMYuIhOG|8YC{b zFcJ37slO~Ah8^QdYKZ7ROV1a-2cxr&NVA?a^Frx0Kul1wc~h1jdndSxw5$4&uj|DE zFP*rfa@a_`utr!N2#aq8NqN||DV5O1$l)8h9}M(4+;)A*#5)&#F6Nu32q1f{=ge%^ z_^af#Cp;*(P{7+L7EHmb1uo2%%m_a$>k;75V~aAXM7W;Y(r})Mgr}`VI`MSWXcZx7 znL^>UQ%+v&Q@_aW%egt?t9(ccIM>BMO`U0W)M;UO?Gz%Kp!JD4Bc?_wJ(+o8?1U6SFy>R)AFtLC=PH)M6*{lO1&UFR5FE$K(cce#0W<}!+eE$fQ$bXSI z$5ZIbAN^LpPJh;=nsLTK+Zbk+@x{~iDYD}Ox8|lXrg9H1>&5|kN7SmVE>MHQO3x+uO*|(y(U%(Yy#@a$YmHP_JboU z7@{8f14?-1ISs=w_vpdpCfmf?x^}$e5M)tDZ@OK-)KgpGw!94$$vwYC_<_kg^vL1e z!Z1d}yS1ZusTk7-^0Tg%%~Lw!>NaWgkYFdLl;P0}0+Kj?#&}WAgNpfx5&LW|dOZ{2 zewzj(W3MEk#M+@nJNh$I^0&<_vE-2Ysfop5i5Cz%&bV#J-|@0a z`Dg_7sBe_l>12UFgW%e9D2VlC3F{#PnYj(pOP+ljXy-${Jb6dL^@_fqXlCo<>>ZO5 zB!dLOlT|NaE^r(#Ttzw%{v6P7k|3+sDj>h2GppD8{n{Yt%WwIZ=Ju&K^5(s@P#{Uk zLbKgLHfn>#aVNa+PX+c1w^uk0!~NzYkmecJROu=(*_Ir|4@5XTQu6Z9(Q|*-D7%f_ zGEsRq`|`CjYqHK~gES)ayrP3``WS0mCS58bIo{sY2p;1=RMm$yLBx+!6z__r06t?RdFeR?%*SiHy-z+n? ze>RR@o%G+KKgAfC-Hs{i@^05Ha1MuRe>+hs;P2R^j?u>w#}p2ea=~eI%wN%|Usgp; zDBruKCLlyM@r%3%t~Mqh@{i}^0d$P#`pe86_c9>j!2Q18XgLq=Y|Z*~HGD`X z_=)e&mAhfn6Fh4BZ^|1arz*xnWV1d^_>;IkyXL2ETjTV(%N(jYb8r-Wal~76ywEx( zffP<&It&qmUnl|QXuUUW){e(vV?j|_JM zWB5Ud{QF<;#(YM~ue6dY@?gLT8dqt47hmD#wcfJ@5w&(N0mAIXa}dhHvK+|@-g#gm8h<2)Hwmfm@(^x-`-T9mot*1I`^ z!v?*yBKEo<@27;lyx(Jhm4IO@@|x(CNYoxi%{X!|3)Sclvs=Zeto22vKiW#ql|w4l z6%mnbe1{DLx9^bKD+S5X)d5k(H@)UyR5!1I8n{&p<~tl_ec*RZb%i7$7$I|c%ytwh zhuB{tOtI^KbT)eO3`KSV&b=vN#~ws(_hJcQE|hqsch=kdH4zVB(Im-Ypj=#^9?2|a zbb1ctmb^$r!{56hC8~@i(95g-P<|T?d#6 zo-b|Mv7%IVVc7V|U-r5DsgAn-%jN1N(F`;^@F1 z{wNfoh4wy2{AMENy(?cUQ944Vta664Lj7T3wQFC0roPdJ1sPbuVLAo^_ zE61d3=wU#_xkn9efV*VUhc=FLt$64lu!=(PbFk$DD!O(9 zH(m8`dXGha0!9SzPa&sg1??PQTp@OQozR>dmgb~`1?WnNklQZ$m6%DC$GXQXGx0BI z)o11P+^YfooG|Gnb2EC%UIxz4O%(@Yh+5Wc6{0~rD*>6IX8~8{8)WYn)lQPDE+2IU zSNaxxTV*Y_kOK56SW>gGV_Y6w%-bQjbRAa5Ztvzc|X zu88fdi3#e>Q}JG>XT~qzdp^auT1S!F(A$tax(Qf+@9z*I3Afy~rehXT zg8Aw1%hwmW+k;s4-Ymo`04L9ZGb2cQ(TYgK4#sVI*rNdLXW;{-O^n}G-8CC`KaJat zRCHbbRK7mI+7pCagfk9Rjk-?HoNbL_IEpLN?P(BB^euh$;?J=U%V0hirzj% zc-zdqh{8{rt>}GK(#Wa@8u}g&Id{_cTxVZC78AhBGu*!oY1SY98a=Y=I3wE&oYW-= zX{=Wlh^BxARM}mhlGZHD$RyC_7`1T}a@?|2$o(Okl6TSKm2cLnP@bD|(*W?{9R2!>y;Z38~;cN<2O*Z(D-idC~ zz6WPkJ%BF>T>0ntXM49W$DPhdFagWl0#oaH_D?3-#O}kH^i3@s0cVUM5rTqw6%hKPI-xCn;S&t%sV9RSKWMhMe{ zd9jJ%NC;k#l%#1TFrB=Lk9(R;OCG5IrEF~f`Fc-Og7=sRrdb|?zRojO=YQHF?mlz+ z!-uz62b4?;xb1dO_c*h;Q!}Or2;x?%=wMcsC%D15tNshdA`9f3bEsxT^ zJGSO;{*g>+5%_45vFZl)(nZU&?$H=@dz0Ez)dn|e+D!h)vuTOhj}Ac z7Q3w?@D>*${sHod!QXpB;hp2W)e{)8>tB`r;H-Qun(jnj?&qSg7N^d7tKA<%!$h{4 za&D^(`ko^4XVdYK{0*}rgQ4ZJZgb%6_us77RldET*RU^t>1w}EZ2BM+IGFS1)dMf+ zH)Y(N@$|QEs{LLc8YO#!2FbQN`Nox5V*R|t_Np7|)WX!9nBYa<}6k<{Xk)EH_ zJEq7ALFSb=mgqcT}`!NXn*BwoW6F;d+IEI^RwcA z{Y|gf#PI~7DH$xMST5>wQq-PVc?bV+)TO3Z6IZY=yqfSNa6@rP-SI{Vz;7IP+wN(` zPCc6JJ+J+tC<}-0XfD+77%t-fD4}UwZkwQa;^qdDeDZKl1UH2Ey3 zpQ&|;-I)pfW^{JQN$6*xty;*0z0q>(jFp?{{^QQDmr&(wmSy$>ayc_y<74^rjF{!s z7rp)Yd%boOC+O(2md(aQz`vM;N5I*>?1RT%ZW6?wCChQC7EYx-TUeM$kHZ~-C+)A>jZhXLANtL8obm7ED2sLVDDevj zXlU|I=9`ioNGN0_bEqsoVCTKD6S*RLIB17W)i+FHQfOZwea~Gl80mP4C5WP;pCF-r z|24G+Q=V+VE3o&d-;XgbeW8#ZfiH{9B6ou>>2Xo?+O+Cm3T}XTDIu@CnmsdhUbz}T zc+*P)9$YPJew@gRUu1?xNmimAJ5m>n#uc= zH=}KC5Z;m&HwLb1$PlO-8fHil)Q@qDF`=r5c}vGFcnUwo2fuuMC)$x4*b|ttu4)a- zl^MP()Z9AORu#zl7GRAZ{V&QjCH~?~v0@Z-bJRa0cqeVWn`ZYi_=P_&5u$f9 zcX@-BljehPm2fRlM%X)0BwT^xj{p6huam6N52uQgAoM8Qb199sZ!hDbpF)RvG>VS9 zE0xcX@Ll*SX|{-ZyFbffL5xO7D}}%l@uM16%JBRyxgbmZ&dU@^)eO$`{+A_%u_ z;4z%V@_X;!MI>`W5(lA5CFeH_0pWo`?8d<9|7}*1#yUe{m;_Jza}uJTb@AhQz&z1C zzw35&l}-{b^QVVUrQfQ5nL4dLr_%mT<=~m#tyF-^87haf2nZO*&*v&8$p1#lcCGT-ARCF*`;O6`^8Te>KJr4fz?_?;jP#AjMaSuunncc4 z9Yx|eX#Eb!+nm`|{7;n^3lc?gJGp(T>Zdw!PsvOJRqv%}UVYm6Kg<}pY)IdX;2&p? zGf>XZ{Q=&h_sq{M)2%5IHdm_7sS|`BL z_Wau0n1AqL)3cmk&tXif8GX$cW#ZXo=4{$lz8NK-WV7c?Je73mWKl6?-<6L-;IS;z z3kz*mU-e_OA?vLweN41>ZfLFMukeJ=G}t*v6?C#XLI0+}vUw^s>3j-(+VP&H?%X}_ z6}dkZfMmT_I^A~Lu1#InU5(|daTJ#V&V3+vX1)b3dEV073!VV&z?8`ghTBwm^sf{s zO%?Dt68&mkE8mA75gcMCe`g+nrDu?mSTYU5?w*g|XJK=W(`}w@ovcS4VcNFim{cX6 zzsd{~j)|)6HIi*H4toQU5Gs>;IGKh7h8YfC65izcEaP0Rrjq`4$yG+i;=VX_t^Hko zblWRS6*$Pu#Fc?#)xq`WrSiue^Fx+qz1%zdfL%X|{?lSL{D|qnP4;@DAxtJ7{1UW3 zYct}%eZVk(vk860KGNKwU(UI3&O4OS4SqBC#&}9IGEz{s4{YNbG10oe~{8v)IF}nxyZZ`w?Lo&6TNcld5rBW zmi5=OyQH~J)EIoCwT$`bM<2-0W_}yLGbeU1}2Bw z0P&N4P%s1FsaZmEzP3}r`eto6^H`-6q5fO)S>FD&-D=~?Qc_1m?up4oUT^7yyH=WA zlH5n$oAOXA?5wgW>#H@rovl=YcKvIjU+PTNJV2cvOH1)y?#5V0Q~gYEVb*3b?(Fq zDj&T=3220c5$PNruU_!72RbvkTz%$SNSsO9Bd;(59CbAK2T z)+Ar7t37cZn#}pdyawE?xVYN=&Gi(r{>lxBUXprnv(RrC^GI^r)A7=A6`xEc9$q7Q zT!WDg901TA zh~%rIlZko?_1mO0or%519<-{tZbl>+53J?Olswk*cE7r(vSX%MYx`Vkc=6T4vlc`V*RX%|XC)b91^qBxynJ5nA~|~9M-N`Lee8Y!74_>GKryRrw09I}bVy@)n?ri1#C71csOCb^W?UiBepKaVN=EidhcuyNB1s-Lm z{($6W$z@E-ve!XxYlf*i-2mBljSm)b!dhZGS?)(zW*FDlg+Oz=Vt?1|x#O5fNXUW9 z8QX@^53$K6J>-t7o@FOdsgjS&{(tsAC^%=|oxhvS@cO}KFelF&d!s(Tj%s9|d!EOK z;zP4J-P)Ym+3TMC(Ouu`_R@W1_Y=IX-mi)^FyoG0zY0`grE((eh@YgjxJ^P}i3YzH zvP1beb-gtWrj^AeTGs4pdOm!g(}T2`s>lV0izrSWs6wd`3ZwZZLx# zS2s-rzQHIeoA@=nN?+tviR|@8>IWJkz)r##&jglzD#3zO+yg1n{{px5GfAV#fDjMD zR?AN3%|nT!G(i2Wmyf5Op8nky1TN@{jbA2laa@6fzsEper4a0_K20h1HIcvaM9nQ@Z3=hc?p44a9_!Duw7o_Zkc`JjT;xZ zduNUQwfKA{KluTy;Y=T2JM-#x-~LfZJ*oyl|D@Y}c<%o<9&5ISb_Mb#_4y$(uwqCD zR}Iz}Z;Ua_q#HY)rs<;(a_vQYtPc14ZERpA&H>CU_R@q4w)A3wszWFKIxh7rjOz7uOe6ewvJ!d z-DC_;vUs`Kr%DWXK+amgayPtVnh;qesR;+if`c z`EZIF1!T(L=0L`NnMvqh$JPfJ1!ocHl|V?YS?{2!^!~1(TxByR%Lyx&wIi$vMB!yj z0+1f?EE0b~90RcqTWDM3)|S%hgQDm^$bOZ~K?nD>Z0B;qG5d|CiJBiTL3l#dS0OSL zPM81(t;h9rU7S-Ftj~snq)q2Z)6_$I=Bpy(pI*P#I@_!A88@1 z)hmA;Ui<1#h-yNIG23OeU|Q8ciNfFik#uaKO%jKsN9u>O+7bdCOhf?am{pZ1W0U9M)S@>HKzOB-6Rb4z5m zvpE4e%g+^`w$0g!B71?O^`F}Wm~c>5Y@v@cX>8SbiE2Z&tMm4Bt`weM(W|&DOu4NS zH}<9d;Q83v?qaDcfH8TrShULdesP+d(P%S7aDU^1O)SL(nPW=+Rc!5xs^PAm-X42X zl(5nI5SL#L#%<3_AQ?6vX4YC#|2-gfvE)SJ6u~2<{@{|^L8oDpAHzAfg`9{kX|RH} z*~ewypH>XD|FOQ<&k1&U-q}CXf42Z}KC{8|Rpi+NQH{o9K32q65xV`D+x$uPGt}5S z6RM`ywwg4z@$>RZVYiwR%+#w(!>qf0Q0d-%@TztEZt8aEzvXh768149 zTg!Rs-Hey-K4;NytsRRJVD1jPUoz5a_9u}+(jE2F`F}!kB{X?0xqWKjWc^NdKQ#Fq zH6{ncSFn0qwUzIS(PcQOu!UPD?XQSbn~+(^SCQtgP+sS;a=ldL?pk*5s?bThO`HPf z1*H!Od2ybj;*a*1b*Ijb`-{_yTi51x&qEBJIt703*csfZ{niGK7Oi5ghPc(ubnaFo zU%?MKx(>3wJdmW3ZICNs%p5U4 zC4CklelScJeqDE|dy6*9zJh#=XnP+Ev_fEEMH^$zv>HV2v%UWt{=}V=@ws_p$@*Y!fr63EISgEI%}i?<@cH&607dzHJ&4PCgGqe&k1gGm6kdAq5Lyt zZ|U>US%(pQbD!1itji(Qh*EJg95sdR|D;6&7gWh95r*_v_~~fY0fi&gq;!BolXPl7TAL9^uynR%- zL;%-m-&Pf0T$`l39GISm&9>*4r=YU08g>)!=X832dFs!^&jX9jD?tWsT~0;n$5v*3 zw|7HiXY(|hr)iqzS;gsBDv!FBvu)DSY!6%N zK34KTWZS!_X;T?Y-;f#JV6UIC(~1JhR!E zrS)G{cC~&n_(%N6timoT>I5~)yYxq-$frc-Gi7A@K18c9-%*|~%f78V!&WBDh~n5c zNdzN!O?Z=tr*a2Ns+{k}KD~~Ex`pVAda2#FT>_$r5N_m^J5SvIcLk8t*FaUI(C0QK z@-K;t3#<@+fh+kPLLwOL)#%iIO|JtsJ>2Z`2#%ft1`pjBAMF57p8~&6Uuq%9={cfx zA%iT9$HKG_e|;`Ou*ZpiYhC;SwbxzCF#pCD&*O~Wab9h>ugsLtqXdv26xY8}4p-dw zymF9N+aIzF4X^XL<8qMiN<11qdH_56a^3SqwU(cwA{PJfk;dTamg_Y$C~a_%{1fFi8H$&r;Ie=rcgRBcUM` zr|7%ckX^xBJ-Ffz+uXn6J}UH(`QrFXZxGb&y6qzLQS-SFlH51@eZZF_#QQGS%cq~w zt>3wE{Q^vW5?<%QmWFc%DM5A3pV)ndo^Lpm51?jR!PcM_iy8*8%_fjceQc+qW-c+*%fGNGekBlX3QXP1d(Q;$kVbCH-eb zwzk-~c&Ri($d3B_ndR5)WwRN?c0+Sa5bP=0P@wmv&N2gqbkcp&6RjS@T^js=tGU{kot)idNo#~E zn}VG5l|myI%?W4DlV!SW^Kd|z4id7Eb#EU=`)B|bBPA3k64w56LeO2tChMhY7bO2j zkv^vn8mKkQ!DNWLAUaEs4K#}2xHCvJlGM|HDRn6MgbGWY-f%gi3La(i0C37N*)^-j zK?@@!wcR7oC&}9gVlj#7_Jf0xT3Lf&M6f0C$s9fz<^vbP9WjmojhD8;4HgP6f@okQ zP-W}>6T>F%)9i@14a-Fa>VX|IfgD7*%tON#*FH)cHV#l4scJA9{l(xjNn1$E+K2iB z28VVdyfSEyhRaQoq*Oc@QItd&N3_*T;DJBlobbhGLR}W5>VJR_og^MGUWZA7KR~v( zfK+J5V}#Aid>RAUv;oPmXzQb%p~%5}zp%~G-YYpPBy8EwKK2WE@8eJ6e$s1R{R!LO zY%<%5SZIsiQE!=8nEk4M{N%dn!Om0##c%)L{3d+P@4CML@LS*hi+JoEzf}6_WywjJ zF^0dkEW~fuIV2C)Tp6Hn+rN;gxQ&XgB31(X{FI-;E7Z^UM3N#uP;prgyDU5rl(+?I z+gYm3{`lk!dN9W1#B55~bfFKsBw>tq7q-px)~2WHvHF&qQdsDr#qNh;27-V7kSD%N5(!_n#({=6Svvt9*SDXSCN0*lJGbDeM0{BW&~i z#+hCouh*&B#iv@POmA{D@(92aP8%PV^o?Z_95^G|a9%I=0hI^y-9C=LzAEE>QaL*g z^@EMcR1?i6apTP$dX!C&WhG$)w1a_65xxi?kje^~0GDfZ`{S@_GT)z5 z-|O9femoHk5O8~!ns6oT6OWCPF1p?bVGbhu^6(Y<2L(i{+sJ5BfJbQVALZ&Y!kt9G zt#R5f&{?-AxT_K(hJ%;!J}1Bz#6xvccM4IOZRdSLp%u|Tgj+)G(1Rb49(WOJhG0}sMkHe zHvnAs(??J;k{+x$N;G6EehP_xHgvlt6TT~_2lZ&HXNL>r-90?W%(!X83G~}R1&ci} zrhVRRFAyW}KDLCuE?IB1L^9a8QRuI_LF!AZTd z=Zm1*VnJ=+;K*h#>>bIdGHf6MbYc4$K6MnOJCK@DNUuHbZg?TNdO2-Q@@22@7~i_AWAoMC(8hJDnzRNHrG*9or(40fi8?DQviw!o3K zAM3Ax@Ygka=Yl)W(@HUXsQsql;r>8v>l`aK5T(!L`Qu4ao}GK^#>M6jjI)%pa>+}- z4PO|g|3|cqq)f)nKvt(oy!WH|fdtLyg`FUrW%})l?Vu%eY>e|F=ZpT_ zuL?w8H6e6V=e|sKp8Tv&iqB5Yx?t^eW~Vyq;a}O+!}pmoNSv_f3+RqNdD&ur4hOCC zjo&~;YtT0+u>PJ_E+C6EdU=Jel(T(#b+0@11&_$+-XA$ldUZgiIBA55P`+>tcV78k zezLv0T-1pr&eQpD6mZ&=6e--wdZZ8{pf)D??4adnQz&l_5PF-%VAL_Ok%^Y4 zg5tS*8%28&9ga?XA}$H#U{EjzXc7%4RF$}%L3jEIRL3)Lt<^Tq8wFP(-i!G5IxIm{ zCX^pwh}(AR4Xti7^*|m}^tJfoPy4$y*;bM)?>zHJ#7{e7VnH)%GT__GekD{M^Hv zXE8PzB)(KDL^92CNrp$2t;ycjhmAnm8MafkZ>2Io3@%a42J!o-Yz|Q8ueWuZSVsm0 zX~v^bkhm(*ivs0HZ-wwO9&e9%65L7Rk5>}Taw_n*e&9{G-}Lpb{{lSv$iq-Fwz0Ai z)aK?#L=enuU%t2YI{m%uB_D~e_>$j;`%ORmqd#5Fm2%rLtD6C)vGQ_MI)kL~FTGes34?S2;PuG{~8|vBpn%kp6vQvvml+m7x2i!6!v+{%z>SS#EU8Meapm+-m z+g9S8z_SyuIC|aj|4On+@Bp zmpXwLX-$(3YWI0g?HcmtG<)lAI4%e9K8Um|9Gq{H;s9c`cvc_n#=5z>40E4TO*WJ| zWe*HT{?={qq?(mB{Xx+M*CvJcL-W1knED#3WO!-mcfk5DVjl)@S1V0dcx7gtOaz4Z zk=>XqbwXLF<8fTr)!dG^$sRGwxQc=71o1NK2=Gi|KGXCQcoI^Pa>@K-KC>-~j|SNO zaD{^&ULob%w-<#+>J-%{?DwD|nY7pbmDH))uSR33Nb5s(ubp8McqD`8BPIX8W^tJ% z^b*G)GJQO@G2E=KE7AN?(d)@^a61b2MFi2OC7teC=h7#~RR9t6XddKn?@1^)I)8@0B$_|f^ zU6%U;9Q?xdE$w2%2dxa@&HBBuW`WsaB^asyX!JP@_HErRDbd0ux{Y(Va$vx`KWE+o zNAJlG5VEmKIJ&NwvKPDNm`Q0}+_|GCAMT{f*OvHDBj45=7hU(v7qod?ZE^w0k9nAx zgrE0U?!#2#Yx@OUK^ZeRt_sed3dm!bJW7uRwteu2)HV0_)sJX7{dev9vaS9F;oL;P z`hUXPKXO}r%pl}vWxINRldxj;0{)?-FZN+R1?2VK>M{;|24gjCiIi1rveF&wapsY`{^*lUb^nnIu`#W|} zdeHVNIJ*JY74NSKYNsQ>6V=0o-)B#4H2&(V2k6qGX zb;m*5AVw zT@H(7p#QRW%W}i?@<76$RkWnQtKt?d6zvx7(9YxJ>-JJ|(zULfLvg6nSwlL7oDKUr z`ap*>?;Ll|iGz-v6eSX3pEN2AV;`ebryxCM%! z1&sfMed^87jU`RkxIXUe>CDh%ph!X52GXrEZtv#kK>usMoX@_H+F9_IzWWDozi9+(|He1}sVxXxc&JU@WiI$A zt2<}r(4&Fqqc3;}Z}{3TzVEYtNBS#&Io+>XYiMM&#OP9oU; z93-*&SF&T?CvSSWt)P%{uI@r-60cYPkXXMhi+_ro@C=hfD$!05qu1mXmv8Rbd znDhBL-US7#D11176XhkT6F!5v!k^<@s=U1$*Edc<--oYH{ycMv6FhaPP{yC~$E_4~ zjCL`!3oV@|^(=MbThv3X)_5aDex&e~T!Mi0(21rSOKm5q{IK!Hb!oCvZB4OJlw!2z`09a>Yegjb8g3K*IL_Wd_cmdxG5m*$OtiNtX0*$a z?ZY;WY4T%Hcx)TEAQ>_~c)Yj}JaaPa8s)`FOR-oOR*-HyN-2`{E$}_;e zNX=Cs?$Gh7QSpgZKR;I_;4?>}c1awzc2oMYUUC9Q8;LwJQ(}(tZ^IvjMOU>k%eJ)A zN2%Au@*}(2-DzU}@*p5qLY87FyLM6Un|v3BvlC2@>i{{p(tUIAWGDx6oU$^$kOPj1 zNr>jTj>;9#BpD$agUC8}q+lnOJ#3!jB*Gv&DX!PKWvK))$^zGLNJrcinFbz0UuQyh zGLHsE$*FfAo+k;lw9#?$m0LV|==g>sPVamW9db}+FFyF>=8(TG4_tACKTTej5t5K? zR1!F^XFhkkHsSjK4b=X}NZw2Tn{wWpFGc+YN&}yijIx%6+L`(^&*=HJdKqhfxFTq&yV5RyXqdtVO@l4M}3v{9%Z^}|xgE_Tb?#mnxD4&^EN zie1Qwg_N1e*B|@Ie|g{AK#%l^uXylLSJz=Y~;GKoUFm75lsH> zzwl*v)hk|x`%Po}=YRO${qw+KYo9g0D9`PP(R{7h{xJ!+YWCZU*>)@A_QZpg8g@F< z42>@F5QaV9VZqzcHhu>8(by#0q}uguYrl(}q;pALxeXOD1_*vB z;{0LoxW{GOac1M{uQly^bw?$~7?P8ni>>^Y(sg+MRwt-e@_lCgtouo_EgrDQx<{s~`8V5Yl7%Ls{%6Y*y zm-Dc|)S^V27I{@|m`Unv;M(wrI^CA}7SR6Kp4Blr$iHs5dU2`Ol{AT}U0#$>aej^8 zMJg>eX8-4i`e-BH|KQTi#_wW|huY8NJfGt<2+jSpZu zlh?hi!)8g=iNv7ts=*k~{Jh^A3n6L-#(e@Ubfx_%rctPzl5In6@?z|@-o}kIQj}~3 z{l@t2;IF9bxW7kU#)a`@v#r?Y_dJYS_8SCBtIoL%^S)^%gH&i%I~RCvj#6ai==V@% zi>?stCVxk;Vizzj%r>s+lE_|H8EDiaVfN#h$dUdhS8|1C!`rVZ7+CzrgT%V3SwpiM zMS>z%>KdY7?Rw@PnDfUcM>xAeZhoKJpx#c5g<#jWEU_a?71q(CjIE5XUEAB6pjiT8 zv}9k29g z_FGLC3h6RCd})IsA4nW+6~a)IMkZRR$gZe3oOwee@Pzk=K{&a%enN3K+8~)9cmiH3S2X)?B5>B!`wFl}GMY?O%mNaS86miw6 z!P@Yc*T>KAH@QvN_Y<j@uL>ZOHT>3>~ zU+f&y$;CBS-8ueR@+Mv+wPbS%zJey!8P|PXUK8sT{gg?C7`zj#4Ay&JM3|_86tJZD zSc>~My7Cp9b#k@pklXPro$ccj37IwV-VIij^6cm$qp+ia`;>(7-Y1@XPF4Yr^r}~k zAn=#tb3XIakP|IRd`UW&CGFm}G1lqvYhV3Je9v=guzr)h+>sDD3esIWJE;&P!I#eGF~dc zkg7xj%uH3(3MGRVtjr8png9t3Rw{x?l}I4@Z-6l=pvnQ~T)%gB-o01e3L zr>!0dGxlwxiH-OEy1Z@al*!K0qCI~O$PURjTMzz!r;2H@=l}NPm81HU>#-p0I zGA0pc2-_fkSD0^55LMc6NGD~?6ThA)M)QESC2ee@j&ehf$QJLBPqgMHg{IK2qhw4$ zdP&zn`$$xa;~*tmJGtWT`UX$(&UrK1#5`#WuExS$#yv8}eHCKD(J(9izVqaL_njCA zhKBgeM1x+yi&~n00=r+L87uxO{94q|@PRP8kn{A3WT&P26401_(RCg+{kXp4)Oq?b zlk_D)y309SA?Snt=Ul@=AIqsB0bH_80$rig;h__wa=gbHv^qgXwu0?o*jUXzV(cYl zg@QP#MYArXm~=44W}4@?u5xdMPlE!C$0SqCSlIEXqQZWbQ10)VIp4 zE1|cV{N-XYRZn`9`WBLZzhB}8b^GhK^_k;czmG<}7oV8Cyu01kxi8hkWWrVRvy4H* znRyDQyrQ>s&-Bq)bkkMZIzFFtGftTX4_Jm}5kG`ep!&l(mG&Z1Le365?)l%&?RK(r zmatw+>89=8=4_`L&J4%yZ$9}ES>P~qEtDnvvWU+7@;Yz3b4Sl?sg9(&WOLo;N!rLR zHyAo;Z3Aab*#H6jfRGw@rHm`fcEb&SY}yJ9!7nZC(-xUvL)J#}++}>;sAW~>WX7#E zh?pUt@QaF8`kR_U=Tvi^gj3YQwkDaM|IKnWXssQs`m8sh`^mQ_Ph=#33oRa7=o}Y> zt8=GU=H|+WcservftZy1RoD@aM^vlrh%kcVpWVXWY|Z~fB06k&+B_w`U@p$DzXLGIv8Uldid@GaF zeJvs5G>QYA2N*je{wSEBc%l#J@`%ZD?7~jP_zLkb`#Ws)H357r*K#e_@(ECiGi=wi zInq_Vp7>R*r+e*HMCB_O9k2UfmBk0Dzrs5f#EcgYlmeD?s`;CvnL3G^aiM_LIAG7@ z6BaDSHS_*$39A;R$N5o$Y!T-L2_AezSeY|5is&>>ix@#Zn|hsd!ALS-5*i;vJ;t57 zSBj*NxNRX*k|~r2kePR4$>~V^G|@ z`7Ldgqz;M|;9kdK0wkCaO8Ss&%7{zaKe1x#a80by8j_Ou@?c?X`eqp1G$H1oKk~n6 zmnyG=daLqCpry(}@^JFEm{^96D3L)6ycUjU0$X_GT^rS7-&mUJgfwx&X>+?08$_Zn zsS{GD9<_b%w|$qqS>-qZ{LO#n%jCm<>Fe$ix}Ompx(9LD^;3;DPF{Y_J3n1M_}~7g zcgf$cc~c(yjPgzI`|$Z0B2Kc6NA{lY04;tnOW3__ytnrJ1vg6XQ{|*d^mqKXAwetA zZ?(HsNTE-nxe%ltd$9e+dvy=kw=RnV2O4ebF31RO;t9M%Y~9a~WbMG`c<(R6iv?6O z>9#cV-aKk@y0&-%h5Nc;90x01r{X$ux8spGMGU!m8u@RR;O`O!@QpS0!EAV)Iz*2unvj#hj2dJFX6 z>~~MxMWoCPvMw)}`k2_*JOP~9rkPb+quwFMJBTUp8;|vla2&Qw>Vn+h75I`o%J@3R z6w7qo;z#6-xI?VyC*Uxyuu;|GN{qESUoig66=lui2M|X+ex7{UvAKZPud}p+tf5lGQ1!hM-0npWILV3VdmPhfapCZuXwsaj0V{3|G<& z;97toJeaMvfVF~I@TT9ux5vvo$1H!;_e6}fKBcw`I_R3oq90*9tF2PSZTKUR$Lj9| z?uBI`e2a*%?_eE}u5aF!e?@GmHq||XO{v{DrV%dUM;{LzUm9lNsmH|($$MpKevUZYpijW_5 zUU@P$fj)ewwO_4mc+CZCPg?lK{m~$R=K`Ix^!JmHiDdkbYq<_2WFL8RBQ|msLtZ%I zu&w%HA)F(=QK#?tzxn)!$K#)0d@|a2>}%Eyjs%b6jwPRXu!_8?#N22IvW0AF7Z}8u zw4u^GR^fLKb1X5fhZ7F5hCuLRjhy1Kh*883EnuS~D)_kDz87H*zT1fBAIP;_%e7p~ zwY+7eCrUX%y1Is@-Cq zzQZdEdZA8CN|YnGsgLM4gpU_J7W%0bUirQt#2O8ptQ`{;e{^NVI>(e}JJ35Z4vizQ zjKzOTT8llHjWo@&g4}(l-mCdOQ34RDpw+boGTn+S#lKPv( zL^aimZG`ZENFTG9@LGj0*6d{T-{_{gQmD{W!%0*K7nap>pC-ht+jQR?e@+6#g7w~b z(XcCDwP7D}XZ6#2LDES5(XUnirTB&|^wFdzD=yj6vq{CA%3{C%^_cYOE<(RE(5M7^WnoqNTwmDfNy7V z`X&Wh=MmOR>*;if#X<>I zx-YVn`yxaHTeZp%n|$S16Aouh42X{$%zl(Q?GG{E8J0W=zk0@^<80|*Kopq z)25TmK_ZH1Qo7CXJ5E~IM!H8}VLRO%8|fTX(qpa>n)@_$<0A_kwKvR-#3FBbj&^I7p6NnRXO}8zKbXwDFE?_8Cu0 zrR_MWeVhb-*?hB5$6xZdkpWSUx0cEc;bx+E$jK%{mu$}sO<}Lto{C2Nbcp#*{UPos zrd@^R%vN}nXzDb$iWt#xjg7nkiZ{+AVUfh%-H#9(;A0^l;UAk^hb;kqCgFo~&SaCG z3>0Z@Y*xmFNi^;Zb^BOF9rT#+&Zq3$@#lEF@yjpY_Tfz%Xu08MZ|jcMJJOUp^M4Rm zjaXbFR)}%6dN76swX6>p{*L&O`JxR$i6U67#vbIx(j`2V)@UL<7xngG6*Yq^$d`2;NYC3jI)3FG^|-v^^7fA7OFT*Z@TXf@zM3=K^7Ikl7p~BBhu$7z{^8|sV_~e2yqF|c`q5TYT!iklHkoc?P zS7~Ow@Ptn+C=LV?f>A4cZh^lk;Vn|dP?RQXDM@7yu97Ymc2~yt#j{8x8QB}=@w7VQ zSYRQ~geIC=Sg!;#_@I~Yp~3OCrJ+a_NfXJ5m4t1Zwd}PQ=3PZs>sMnrqETi831mg7 zKFc^yPLh_i9gy#|DO$EM6a2uf^-rrLb>fp_T_hCM32fA8&)+XS>*x!cBuMycA-T&- zL=z@+%`R<>Q`{UrC6g;Q%dA#=S8W`P_SVLTb;|2k4Hgg+-_JxHWK*j6>S~-Eu1({I zuShg1=^0uyd(6YFNz2!M{a<=h6Tm3PiQwb!x4!GM<)3GH&-=bB^bEW`lXfgZZ2RM@ z3O|ByEYw4eT-QCRbKX9x`&tFw*NPrsi>+AzvA)TW{g{#L_n0p61TBcgV)KEMh)qAK zt7%`(TbB0d>@s%Ln-c`=HToO&MdCfKDYvc%d(wc#7VS1$#|E<}XY$iwnkCL8a) z=6(yD$`^^mis1cvqxKH@GkWBu|T7(tJ8ym%0fg9)m3WSjwRt zn~1F5YBQ3;>BEb9TBC_+W!tq^n}CfTuo-cOP9QD$0=cIXHC!9|i&u42|4)k1J86t# zzUG)nB`S0V@>$`GD#nAsAHoo1F}G4e6!2%;Qt{3f4nvh)IaMQHtKlvf{o!0h`0>6Z%G^ZQaj^zEryDuN# zYhu+F{V}gfa!{&%6}k_7+NC6?>v+};Lf}XE4S^pOitQR-&#bTz1Et7|3XPFS8E@#F zqcZHeCxMTfro2WVk^ENjKa3Xx?{XN|Bw-JjxfyXK>x^#rBIxx_JS9H4_J+U*-vEA> zh@-i1V%5Z|f4%#Aa%aTi1Tc8i6gXtf70O6}5UbTSz3d=G%n~+uO|c^4X@1qi=uZ80 zH4+}?=wqk#O*4kc^lR`WVj%ET>UuI_!xMIl%s}Nx06%$hTauo6H-&JVex>fgi#_>O z*Q=dOTsP>3NeTFp9KV%wB5V{D;)eq*ZBoyOeiF)!86ngr^A9gz&gM`!2zd(oF! zYnpt|ID$jCRcGVM3Ck>k8peaU%nO-XdiDDq_DX(OhS3J}8SPf%Hd8O$TMZofGrPl> zo75!c{iWbe4R0(?Bu{mM$77D* z(qiI~3#%SICjKI#YxR~`q}NVYenB7HD!*yL8+z??mI@~VaHrL;#rqIA7S zMruB86n{n=Lee;<=yn?fxl@v-(UB1HdCg@l9-9hX7x<#o%h|VRvFXb6psSr0OIhDo zzRhwn$ZcDjYFgR^m3=Up>5PxWB-#oMB7H2NBYMFX@CLqItvW`dN!Y`WT=?d1-Vl(4AQhog0<-xoj)i~Ev&iBnC0qJ8+<3IF& zXBJ4&1_dq>HhB2?Es(~$e{mx8tiO%lXI*;dZG;zI4+|>CrESY)j|0`)NdD3$NEz=J z8}@Fyt7EyaMoBiGZu#SJ^h~+3yrZFzjt4uGsY(T${?5@ zE1vxbEeMVJane>`Q!tJud5+wKl=lsnINc!vzJ5jM9|o;#iMVUplL%w%Yum4jnrl`}|01 zxMe1taq-Ht#CB$8xNy4eNbt-LHf_~D-q{b+M^NUnnr|d)nIHPpX?mZO?j?VV%&x|QAL_m zWqg|m92I!%&e$7c&&n(!b&b}tKgR9u?=G)-%E{JjGyK|+CrzFUeD_REeVV| zs|0TE>uCw&r{Ug{!Fe)*7DihJiWk*lp-?gbAYv1Zb-@93>hBD!nLfT>7cL?QAHSpq zq(WFv zdF%@6mb2%QmNKlG-2?DJIjNW*jgJU_@P>_MLids!XH!N zMa{Kzy#B(_cw#99$1Zc01h%mW!SH&aqqU~Q_Xcw&>;^8$oGERcgsh9>Zj!w za{0(de^$QneIF`|Xn03w$O2*>@l%+)KI%@^h+nba3^%Y%7cjc>@Jw zc(dh(26H=}wm_@RAZI(`8(6d{%6pBZnR}igmlZ4;4sr1A=+u$jN z!h)-4)elWs>c%wVviu$J5ofp_j-l3&fBw$Motsx9`_BGQr^QahSfY4zw}Fvi%fm!% zHJ&RA$TINU+z@Os`{5y`G?pZa94lJzCdVl*h>(`h2*g-wUQm`amaoRMqYb}@)sY^c z(*N_=qix5TeRh{r*ah`OJBM4L8CosC=z|zYebOa?9Po0qI5mJniSc}fTZDOSzj*n6Y?DX zrv8orj|nk?&uu9W zAiYd==rin`)_YM3a;ZmBWKxU135ngIOUANHG>BAtkaAsd8gz6)&U=V)L)-~x4WVIM zrj;(OYd!4O(600FzGABjg}>pA$&TQD-#n)E6Z&19n6O&{ZRzW&Z>J@FXvNtU;{x9D zT9=Uk)J;z+-9|Fpvf;=(D1MUSm`o%J;gmCC#LA36uBA-mx^Ko2^FRh~{MWJMj|ZB<=h0xj~`E^HUJ(3vnvt(S(!EBeA{}T}O-{^!un2e3hJ& zZ9aE9s>McLxBIX$Muv~qTvD&Lg6SDkID*@Db5^@1fUo6RuH{XRmSrM=wNID?C<-z;P}d-PnZ~ z>~{J)`e#lN(U(@hkGyzRXe*J;4vGNy{KKKm~&)Fcxy;7(>m!)g?ECm(4Q504XC7g_9zqqc=)1_Cm2Y@M6Geh1+WAUCGU@GcMfvdulla z{Ixr8C~Lil@x37Z*Pyp>qPPx9zV2&Xg|KcD*R!unI=b}SX~>oZ_N z!{?H7g6ZI9_}WjQ4h~>BOhMce^^TL!&O!hbbaV+eNs#p#F3hQK6Ny5UKI4*f6&rvmegfUs3@i9_s1w z=oZL)@95Kr_m+J`eb$+s5djWZro>h+l4Y+Lx@=q@pYSGWczBWgDx7St~C?EK9 zxNFshIbdI=Q)ND{dxTztrw#fTsKg3`$WkfH&0U|!8NcE)vdUpp`5d5P8&q-~K9c>? zGT^EuLq zXs>`*uOhZ-(_o?$im7F@#^%`ZQY!R^|_{sCP1ljP_JItk)Qu={?UA<~>>{Q(J z)4OR2+BTb>=0ROd>3r1SrZ373eT1&J?mRr%(4OsI=>pT?7cG`mVNB?_1_PX!1@{w# zw>=|=px?36J?ku=d$utE{AV%e-viKcAvg@RsqimVWB=t>qq(GH353GU_(X-jS*Ztp zMr1aDwA!UHVr6Xmm{D#DPC~95>Hq%fa>Bt`dqNow(bcxhqPBkt^fa)DU1(yHlKgXa z8w=K=k|IN+fBeEu%wD2uj85))GfrDbm)`27P&(`Be0S>y^C+A`H7%WpRqMYvI0ktV ztK_nJEHTggEkhU}hL~wNOSVY46)VtXyBWWFvc!YJviohGG{yF))(e846v!$fO{+bN zSy`v`HJM5xV8WQoz*?!?t#>cmH-=7>nq104{ZK3!JGx4EPfSjWMsUoQzrJ?&pjKnSz~lY-(6*@_ERy-0(_*k*d%f91U<9< zW++}c@cC9+ zWZOcK1QAtBDDM0Z7RNT zpk05LA)zx3oZ>ZTyT^b2n zay>~BSRjX3ebU(c51vpste+_5T!D+wrp3(-Jm1M5mQH?h7$kk1g%qGF31hg+Y*sqS zw$S_Ma2=R%vPTzDStAm9BGR2Id{#s_s~6xF8bb-#;IG4?eV5+FM>7%#-kWSub_)5)jsB8X`nr1E^~RBuDCroDC`VA8H@+{eq80I^562B7WS7I{`{M3 z1CLy-B=`or|3x>2H>fq7ZmP@6a;RBVuT^lqzwdEzYjRXyk6CmvvLEM8+D?_W^)H2O ze8^JX`|S6mX#HXqCAh1AOsH=wE|*z9VsBxkA-gp@z*7`py+!_pk6NX7?eb$epLWhf zqb=0D*=VZa$%B}>6F^bNcvWBZSHYk+((fg;iu`NXo+qhbEUr+;Wr4T$+3{~aWA2yM zS6k@k+wxe|?7!mfnu&cHykqj2XxAH1bhlzr`p0hunx^Pg2|3(Xc&O6#mLRDUJlv~; zb=DDr`q!6CdrUCrqk#1IjHX_63d0c_5AF;|JLy@y!TD&7nJsNt< z1Y@jdogO}Z5VENd(p;D)jRUWRH)uy(-wUix4-K_jTZiTS!_h7W>Y+&p-t{_lr=OJlLmYyQ3kM5<6vg-e}BZqqAsrWO2gi zcCiTT#5Ct<;`HdK<8O;7;Di^pf{?x_`jJ}3$@^I)tGDf1a?K$6bv}-T$e60bz(Y!) zpEEq#W3bUcTUnP>tWlpeEu<`ai zj*w5b7<;pfcb*TRwN4fEaX1lcuNupbHhOwDuc8nbw(QXfkrPGn8`?FrE8I#jydHIB zmV9oK!8OY7iqoZh_J(JHqZ(jpsx-vA`!xB#ylT^ri zAet3j8-46^tDjAZtDS{(TuPMxX^!@zDMg>lkqTZLce%eC1agXuCZ(-_^`FsQH=Lk= z3+w!e!&&8xC_d&Kq26#^;kc*v`Yp+O?yWS@h{dosf%arwCe$>Zulg&v)kWyp`?qs? z=m(M?L|$+6dh?IN)apm)HUWqP)m#TYqc=V3Zhce-A(7twN_41-loX;kg^47rAIXn-1AaWt;ke`3XjO841g?jz@Z!EzdId z&vNT6C0w<7Ptw@<(Z@7__D(*S_Z)V=X_BOyxNL@`75;w4xnIkgc|BUqseKYTrzjRA zl~YL50@iSGLEGrZCtCQ^Df@Y}!^_ZqH=8%^`9lNKecLQkdL z!M&s79B+q_T&C^@j0VMD_WQWMH%unDP@VGd6JED+bLp1^QU|^#Vi@B_b=z6c2&@(1 z0>G*ikD{u?;8V-xp?Psc6tbc^;=$I}&Iqv;MmGVgzesp*Tkn?A;Zpzm4%UJ8fW<{; z#YLyImK+Qnw?+FCYmbbsJopscp5w%z~*+eIdA3Ko<#et2Y@ zKu%YaqqLE%y6)=HIh6aR&N*ywr5vz9`RSyGVh~J-nSuYbD&S(+ong}&DGwpZvBaXa zjjLAJI5lABuC~V2SWF_CW~7Z82PCbR4Yr0RpfiX&RPRJ_Z5Aky3xF;t6hP0!`O$KC z!?6(wa*GkAwaSB63{XN+@()v=f)5OO93F}W!nSj!{!!}M)v`q)1+ zr(~&6M{Wk%(c2p0X!su1OoLtkj*9c2SKbzAnJ_AYeMqYTj=Am+N5S)*=HB%kxP}$i z6&#-M_0!RlsJC-ex|-!&O8FM1Y}g}-r;fRN^l~l{e)kxr5oYry6bfsum9fOwA1DGJ z`L*xn&wX&c27aVTy)V1HOa`wx*LnH)Z|l`m2u=Z}Ul-$}`L=~o2HWN|4gZX?-G~f$ zPAPOW;1br&{Mw$rzDi;Zt;=m^7VV%)_c7THA41r%sTg4N|6RHVvwtv%U3YYVncEZf zm>-(+T+Q2)b-moYVSydN9DgL>gl3(}@AGTO_UwA_{-eGf0U+7S9_1G+(H--O{Z4vX z<3|hvIPFW-6J2fo%jcv4Np*d$8{Xs-eBqk<$scw?wTuz<)=V%CI^%nyC$ zv0o*y6h0bzGV>GEE8B`Re*CFdPP^l8j_Id>QDr3D_PIiWM<0O})2~<6Emrm`y@#;G zl|BwcCMXVndWXsKOgu3Aou~aHCBI(t6fCvMZ`Jd?MQrvI+(!taTXcN)P5L(>3-@PiN5`z`$d5*LT zp;8z|lPvJPlSK^k%IGJg1}UU7*!lo4qZmEO!s#ATm$}|WH&6Yut;Yr|o`+Jx;=io% zA+k73RkAbMtbAKN#Ju^5F}A+qH0^m;&LHGAO`UffkIm-02~nHPeeO1gw)KOBu+F=H zUY6CUqx5>}AC5~4WxZqFn>9 z1gqBH@!*bBw3O=~X#O%f(tmvhc%6b~oG4y%yDfbibs^r-quB9>SSvgO%$x%Ksg9~f zDf6*-=m<0%3zS@qtxqLgZ&cRca$O~KZw)nCVo|}dm)~Ad_Mq)YHOk+V{%SomHP9Ht zE_o*a_s@HlkuMM;6ShX)0l{_gaEiUtq)yMq^RUXN@qhPP7-PmFG*)yOxTKap*R%$j zy{MNgf@jOVMqIm2rE>7sZ*cV)dymyFI*w?P6Yz+A?prumNr ze*82S_4inlTxr@2GsdXmTx7Ye=jKSbGL25JEk)Ukn_R@DG(#~dofgIT%cthE$ZM>y zb&`1wX{(o~m^SV{?W*fHqI>Zlo$o(V-~2pv?<3{5I)b(y_dL>j(t)Tfgq*&umRykr z!k&JvW7>6bVkAXKGs#~z0g1ZhQ?^}qxJQM>)80AzJqk$TejBO)N5lZ_-vsK=UvsJ- z^~r?hPq$8|0sebRt_Ukduq zh8rXp(wIqC2(E*IDLfm4N3$_d5~*YX4_SS6mhL~imW`PVf=;_NRXhAbsgUS;=D#+- zAXbi)&szHF6x+j|;OkpmbKF*Z9Vqjhdt5mK;wDynIuqAxVyDu}ueam*dkKnkkXi~F zx|`kT35iDuq#GQ6Dd^$q7AjiJVS`|)pH^!*;Q{_$`BNzFOK|aL7@w6&pWUTm#uDCK zqfPnp$K%Bt{(c{9i=3z)Q~U<7(5rXPy5|r>0O5_0_(S+PQt%naq~ECU3*A?|gCAzN zon4l)u@Ntxld8d-tHTAAk`d72t0Nes3<{V7BlbFL@X-q6(p26K7*33ig0Dk`E~{?j zG-XA)!;#U%1Nd7G-6MYzhvA>ZncWiByYV0v?t&ywViId~DDs_!IiAZ4PSfEU<+Z`^ zR`eql&37y*I|OUd7{i{Q9vU``%EuxJ^WG9Of`YbR^@#u-p(r_}6{3tQ+A#;m^?i+= z>oIq>o1T_pl!rcz`nc^7i{OL`#;x7eE*flA(ILcF35BRB#z`if@ z2i2zJzYcKv2888ro|OLiMVX|c32t}4_@ua(YdQPIi^c+W_dAPL)`?=QnKmeW4SeQb zW#dBl8Ou66U}zUqB5w@#`X8(R!8e1(bqAW+-l>y!K*t`n;Ks`XrnTGa+2Ihhh2eK` z+q1UC7V{`KNQ2WbY(C6PXyMB3OB>9<-;eK(Y8}(dApYs$etppVLB+9mkTrDW-Be>e&??Y)PQR*YXVP@%(z222qN zH&xqWu0!N9pL$tHGuQUx8$lH3xDe%~Y7X6q=#%<3B~jmT z)s_t!HM2W$+e@;R-C`jAf{lb|San2p_XAtGWJDkpI4qWa2ZKa&iV9D8ir>fv)P@J# zZs9WV-C%(=?NFpX)m*-XYP4%CBUhHT*I77k0Hw5=ghalt*fo5~Io2Xg&Ug#ShMd{l z%IXqys^rqzrA&w!t|{JLA*l@vnOSt_D>tscY!a_sQ$W)sAIN*{*FKKTQv4yFQ~8 z=+cQp|7hWuPb|oglIVwof@L2}%P6atSmsA{PWD6dr~_pC7l%8tlrfOMEu1ucbS%e; zVDIPw6MG8_J0i@Q2bSUEf<=7Koa6(W zM-v(#bc)^v-go2(H5Sd|B8f-7vk0qjnAr$kRb4Hn!m?P&IiJYohD!^29Msh$-4_@KHw7Q(w9ABVQVQg3Z2Ipe zlcOnjIAzdoIH~AtXEgA-YO2c8ncCVSs53GD+^Ch0>9)hD-oIrmCADAQBk`QI*y9%sW4L+Q8173fzU5&i}6n`}JL2la!o>SSnSJZ~<4wTW}GSybao zn~Fo|^F)~%#%$dYzG2%aOn?9JHr!Rm9f^#1iOmny*IjuW_(k z1m0(Lt+^Ozj}Be~63n<<$_1+(U0^Ca`7<@scg%cqFc){wIpxZ>c1y{z-MY#k_jcje z`L)j>-F(?Fnsz3KeC4p7u5(q`eSghi=AbNlGCeE zP_C627FdGD9g8!OhuSHPWa&NdZ7fl`SUcCVcg_hxJd?hn$~4T@a<4Rz?8p0r%mW47 zhp+7jw-zIJMEn<~H&*69L!r5SFo+n+wzxkY;|-v(Yo+z-u#^mpeiFbH3^FqJq*->r zewvGY(tWBw{g`knuT}PAxZtpPZMz0kH7^l<)Heaf+fFFSSQOiX(l0SIRO)F>^w47{ z>8Q^&N8##fpF?};4L%wC^#qj0fqoyJ&mHzJv7NoBqrwt)4r4_O*5lmZoI8JFr%Sw= zopk(?Me2sA6ff(*4)(do1w^}gLZ$?a5cSBrV0-$NJo_QHgb(5uoD)dY2UL;~Gb;c` zoSweWM4AluigaosIOu3>pL}lYx=`bBMq1>n$8Qlf`TdUEKx=`u`A*e%kpat<{qJr& zVIS`J`_%r?x|F#7RGT8GBaK)l0Ts~ze|L@8gR8c*o8%t*HywF;$udkLs{PXI{=)w2 z2Ik-U^~?L&!2V#|(CqgIdvtUYRzR`m;w%95j3kkyiw5u- zQ2Td}rm$Y2fnD#^8B>+$S3qwNyT@@YJE8D~7MJ}!(?#fH@k-{Bz(I zuZ~JE92t*{e*DeiRY=^LkSfI$l1EWi97no=bKD7ao0e=L=)v@FuX@@*o1)&5Qv6K@ z!3M3H8YPj|1als-q2@01zGTx+a(L4rhq3S18dXD*KT%aPR?8biaL^VSJ`~_5PUy~H z87TxU&IQ^;B=rOR@rT18Rhvh(?z&2MaJVy!>+T#`;4I(Wbzu#}tGoGV+gCZ`X+8vx znExk5wkvh}*+rF7OM^fFFFwQ+D*^r(AJ|60X)~m#_Gn1_#g`K8l4E3d5SmwIg21u4 z)aLylD9YL|NZ~$+`V9GFHdcCqPzG{+=7Op6T z6IvxUUM7zebC+9=jMA_*S`&z6RkS6T&_n&5lB@FF47jSFjI(>DiG#=9`9ngyDftVX za9ja6{q2&KeZq-QCmGvmB6@O<)*{cpx_Qiy`(I6;Up!$Wy5UG*$S504-F&9MGcLL2 zy0vI-ToOXLnhoi-+SMEqKgP^aVqF(WoAwjDs;OUe+_PNam_-~1*2%(>M{d{Nm#+!G zw6Lr36$9b?@Kv%4#BpZ#zMwZru^em`q$c?{?Try(M^BLDISq8j1f8kaPMp)s^=ht= zGThSZ%qE!lE#+gC&u-S8mZjdHQD-5dV3VPC{;0TZgCLqnIK1y)7;2(-s*o2gB3lSt zkf!?T@_p0LJ1Qgq0dB3G;05(nt9-B|n(iO|^ z@M6#^P|lP+DMB}5J82g`ggv8T9E=OXq$#xnO6^t;Nmi*?HT!45hHZus?G7<`BuKe6 z^x9O0Gre(fCev?mU<>8*hcB)ZYX30*CgvMMjVzv zN`MMCDo`NEoEWiWHJG;j-T2S&Q3KR{EQKfa!LqV^2yT*x;&LHkw`fv)Z@W&E-$VWQ zVCPJ#{iV;cyuVYDpLV_U(meh9o(4MEj!2%So3n_iV8MTmVWEgr zqjSBUff1SdfTg**I}EYI7^8WO3X_fBq=;(=9VSy$^e<;Uh&<6Mol_uP`jd&OdFEAD zv`GGZFT4;oKuQ(_dGxF(~gHsAmpCd@oiTYMEM;%N|E@z#a9TrIa;1> z^P#MxoyzCLuqMFL$>o1vG^B}QQyS{Nr$ih)@BTdv`_40yzr_C62z_eC>50Hc$~q0H zBiBH*C#y_or`+Fi>4DTJZ_=OWburX9#s4tcVE&iZsJb(;F<=3hf-F2S`are-aC-yR zGFL~BSC9>!K7t0}X>gNbLxvp`MBlEd?sxYJP(U?Y-ya_*i z6G|ajwJZ?g0@C6*)&Cfb%E57ms+9yHWMEqF#4;+Df##~s^u0~c8sY}eSiaat+Q|Xb0=$S>{}-5K&k`_@dlCK*& zh{3MZg9ZF4$;51>tVxZopNeC3q-J?mxgs3XvRksbeSus=M|G?KznIp?u3f{bSfYkO8ORqprBl7SBnT51Iu`IBD)~W zF6o;S?8^_qH;dKdJCfFlE*%BKjW#!7h;1Z;T<~%IV$oGdE3q5gPM#Ee?tWh-^!aP{ z?CSKWe0ZkjzCIuS$8D15^Kt#Gas%+YAos({*dwt zH^l?+@e`?a*`g6gKYmH%zcsZ6aUko0cx*XsP0?C9K{C*lnzImS0<@W?fpB`89ZcU9 zBuQjUvWi0Z18vFHA-cJ@t&<-Jq)Na~Yv8iR!VfOB$`8L4z3BH0i$%`)?gfn>=xyHh zsYYv32E#Y1WYjk(Y$ycw?<~_Nyz<-Oh)I4 zUT`>YO|lJce$N z^{}bb;6grz{Xwac(+DrURzW9O;CC8#LgQrW7)^C&)81s2PEihw*ngK z=1a%)Gasm4o8Y=HxR(!n_Mx&N*OWrSWHWz@PKkNGgx2ko4K;L8uRf%Q(a!J_Y2^5? z{yUrVeM}x-NQgz!16}XzkvT>FBqBXc@SvE;BrlZ}2FPmQeK!v9H^BO{1GAE!i>lYd zGHLW`3tl9d5FC{sSNti=f&9KE9ueFViML8<;Qw#c!}DrJw4wxyN+kaM3zVb^PG>C7 zEtUta@9J1vCoE6#$Yc8+|458o@2JenwxGScO}qFaMib4F{}h5L?o>r&Ioy7Ss@2rT zQ-kA^Yy<7HX=?1UXB!~u^xe5l9aR9oW6;asB(`NG+9qN@r30-)5={Cg{a0&wxO$%3 z3&gVNB2HoawVK)JoZXUjR_<Ju4EpxQ@z9 zVhT~vfzUbfeobH%{_F1{PVwA`qyNu+m&137!2EH6@K+{+NB-q(I3iEhm2va>u>*rO zW5a-!5GUP%{}bykU-yBvp(7y?V~_+EjH(tV2@+K3Q0HT}{^A+HeaR=b5g3QfpR_|~ zZm3NClR&n@yl?qAc4t4DI-LnmR)fqc4%oEtR<_7ySIpq3Ldqy(#xkY+)C0%0;4%ox zK}0DaHMkX`@IYDmX$a&Wg%9iwtVQ?Au$+|TvVck5p!zmCszf$mTrzJ;My)``7taLQ zUUF4n36k{)B(wFP`9Zumaz~B*b4G=nh8(R+Lo7B%>#-H>%A|+Hk^)^AFg`W-r-iETXqxgpjK0T?8Ye#rfu33memmxw1$> zWzBMxfi%6#Bvn|v0=t2uQA>L6>qMKqp;1`eFat_8&DMFUJlpI&@tS?e)_^ zYfSx3WtiVJ8_MTC3?WNjhYg4Mc zY6~4o#e#MG#V$)&O}a3rxIv$FFFS(DmsRB!Jx^4YUF^eTFM-C1np%^1# zl)6mnA-Nlu^K`}HHY|nd@Nglc$_;%x9f6*;BG7SJX9R2}bF4|$;|@YEaSE`5f;=e3 z3mwY_v8To3p-<^yXM2pgQ4&JD>d!sREcxFYLZ_wxl(1-)4VW>dbJ6z>nfq#Vlb~&z zR=`Ky4vxT-agm5RbIITp?G&la+3N-_i7hEsQG39z4U&QDz!Xsa5g7d!m!U=Kv+RoW zP7lJ?Z^D! z7b6cTpBrnH$e&v&|ejk`M+lTO-U zb60rBuw#4@#Zu&!@O7RLO~UIEU8lU9Ycs(0hV>bhSOvrV_crEjso;*B$`-;NBao;^W%Cm! zm+YK%WJILw+$)31Kx{Pjj3OwY^Ap8@vFi6u4UC>q^pJF>)nwBU41g%s{cjHlObrgk zK`>|=WBcTcNR!axiv8qxP#dyejgZHwV9cmjueY>m+GlS{w5oRFechx;*k!HN7~&e? zuLS?Hhc?HvC2+_8-e$eyr~BUshCn|e)5g653WYk7k8>VrgY?(hmy1X5 zzCl+mnwXBtU(Egm)3hhFQB))EW_iZXdw{Hiq(s1pV74<1Ii_Y6dQ7Txi;7Ep0G`@e zzXA-a2slP5>2SGua_I=-XT(gDG-0$y{x7BCdJe_D!58;)07iS5gfuVKJMRoiK>EGK zMp)s#j_1Z9|E|+!)!=e7eVU~0_kQJqLC8b;#A1+UQhn)!n4Ls}h>qC5J~DJ-?Ff;- z(|#F`Un;1~(2s?D3(^ZoXesj+3sj&_xB?D@K~^W8P5}r(s`cGXl7*O6nY#1-K0N+} zT-bU*-AF1K6#L(Put;tN?ALfZc=y0ZF-lH9)u~f1>qfdXA1uNIj_BI{tF9$u3_I?T zeZRG+wLT|d@ye+Pf&MloGwd8pt0BMG&W(uShqE~{tLBA>9MkkiYg zaqkAxU`sP~@zQ%dk}Bf-o^|=C%9UMYqFA>a3O;MD{BMtYbbBsmKI=P!&w73IqcBSK z{Zn=R6F1ZD**o9zPKEy z())btSM9S6_wm#7F}0_1?$kwz+k{F%H^;}NN1Ogik)ECBTXaFhVjBZ?=&!rLO=%xx zLWhc2^0b-++;cr;bJT3^#4PWD;b}MIo}wJP*i^g408*4d6w?1=!E@hI#P^&)fs8&q`s;%Op@VL#})*> z4z=)2^+hg-8{*usRFAadn(q{^6Il^Oh?DB%x1;Uu^j+E|@fAC!9=ucaIDAkgS;;jr zW$nyy4SzqEoS1_x8Pa!nl!x%g@%`ub7Ui3nI}|)kaHnb#w6jE(?mlK_G6&_f@EReKAK4qQSWk0?W6osq@Ht0Fu#!7pDC@;SBSUr-RcWvW4xDiJ(9mZ^RLIh zG<9psfvpq_r*sMtrCYT6raYaJ3SH*-S{_Sz_@`dw_WSiaoQ={$fLXo2r#bZgG_PYt0c zTm=Hxi)MhIw$RG+vu8@Zm1cw@2X9E*#OgBRY32A9Io4R3p({%T_cqh!FOfZ(FA-(S zPyu(RE6m(y0BW>ir606PBcdXI&JqKPnsD|88viZPsRmm!rROjY9QJmh4K#Cx!R}gN zJHkrZ3Txj!sTHQva2)whT+`)4oU(QdTBD_qO9PP%^EGG0jo0&hxm65#@Nyeb?v^M( zR;D5StT?MGjc1R4BAweg`KZM5GLv*8C3~kXzX|F>WMw!K%(W5K13#FYn+O2d?G_l zbww8NjgFL~dO4GkRdKj;AYKC`qH0$EUd11GsTB*WKE!4qe;xocsLk^v`^2M*U=RN7%<1sL3AFx8-r} zW3+u+KPS$UP{)A>C|=UUUC-(T&fxps-Lq_=wq$YzM0Y<+9u-_0 z8IO2(lI=!N6c%sxm*n5IpCR3P53zetU#%7ci9}m`WwWXAyM$v26_?FfZuOuk zDz0ju|N35fi;pX4SxJhp1dRG6u}K82jty}0nJc0+?E_gMoDCLTb3)+?y_YB`s|JQ# z!5B)XB>^ZO#ERUf1nxYoHRoSRfRYa}l|Y)QsA2+jkt5wPa0x8k#q7) zhd5%1liZ=NLgT+-M1w#pMol()>& zWoQfuNc7u(p>l5E1GA3xq4kRb$}u5nNf-9OU*&1q`sj;;%eC#6Rxo`Y)9cXviVZ&X zsPxd2d7EgQEFlw=1|CtbdbwfAZ5CO4@fi_ z&74rZ>c52sx1v>3;cdu#J%s-zN=2fB)WwjfFHFGRNR^bMVb8+p%Y=4+6mW}s9#L`*ryUekvZ0gxD&C14==4aw z&>?nNN=)xSx=WZcBqEELj%w0wmVimrsdi-+=tnygZnfc!T|}7K0HtY`M6hTKG(KU) z_=}VRP7l&`!DD%5SQ#03MhwN>>npA!OQR->AD z&KyrvQ zo0OzxMGGiBpWVbSbGP=+{2v?cA6Cyv3VxYBBc=WsUHgf-i3*;t>rkz^ufLf_1>gVW ziWU6sejiHsy^-I<13sdCF0Q_VB%nxvX?N>jE~4kRRd9GBaR8f5(Vj=X zO|P3We(@JsN%n7==YbsuC6JVYR*sQ;n^9&4`UYQ0J$3lb>-xS#ZysHrM*ccE0R_9~ z`E{axk4q!=u-)C4;HNl`?{e}L4qO5Em2a68pNa!d*ZKt>cLnS^nZ(U5(h%sVakF@L zv&S59M8{E4h)C<9a<491jyg3%0l%&{$b2G=c-u<5vS?n?=q_UnNu7@HwGThmQ z{q24^R$z~ejkbyF#%>!MaSm=<=x<9BCz&D;ulZnKUD2=aL};F!A9W#dQ4CI}R^RQr zsaogFvkQ{jT0Ir&VwITaX#7fta?oM*`)T zb>Y+Hs-w%3U7~SpR@foHk#9D_qas8p@0gEDWhy(^ybeX}$-ay$__AuL`%qtI&qmc3 z(=iHeLK2D=2uPKNX6;E^S8*n{jDl1?Lwe=O15gd9g!c&weG}N_TpY)E)UrcKbQ&Ft zYK6IF8xIDQtY(fbkK+i$Yo0W0;KC8$)iihbW^nCJH>r4oP#)OlOFDydi9B$OVl+zs z{9xZw)m)|@aLdFZKB#iba{6OztDJYPDoc9V4-YUHx6RGp`uY-jl6sNDtjlQrxX&&pj!Mq$8}>aLOe%-e+_nJb^GzXPUn+2mDibYCq} z25u?Ue3w|9bY{#-+D7#Ic^a5aV@5TbUjLA+w5l=I50fR5g?N<$%aV^bqNHbj{RYcs z83xkEFrk+``rkqiMmrH1=iT#?ab+sM&jW=IddMOyMdhu7a8evvzDkqHTvHPAA!n`3 z9BbD@Fwx?aLx85K9VWnV_A4YwKiVKU4YUOv@{KXZZgLm{CXOT1FZ)$m(3HqC2R530xF**NB^^xwlem7{mT<+QA49-dLmEEsyW2s(XyQG@O zHoIh^NBED>va^ct=XU8kFRIg-!3}$Gpunw>*$e17*QX^L0`@Xzq5tMI%k~)78k@>7 z)=nbf0mbXYE}`Zbx?4{5U{miJ_WIrKqpO|#=0?SL#oU!=2N(hyu3d}EgqXm>2DfgU zJwk#7O;*Zknj*#L#8b~IrFo%$EH)GWR{uUAB{n1?y7%v&pp280g^2Gb0ujRQvA>bW zoh%yas&s}sg<{Vo!tWr6SP+11hfEkrq;#1QqME7QWy3V z7xdG|DEX#39n{-!F#JaD&L^+wFB??s{o$?0{ikyk=D48Ze}q4IcytCaOX?$fOny-|rh$7{6{ z#c|b%vkP6LZ@<}YXNI*I20KoS=C;fu-*_)q=n3-?KBg4R!eHv=1L0Fr9~WHM*;QK@ z)H08r(*sF78}yuzOE0UPz&x*sf9k@~`)ykz$t}k+B4z%%o#^n=t?>-E?52!u&W-;$j`4 zJy5RE9GwCnIFNVQPqwj^MtVCe4)`4s^%58-MlGdGhQn^FdchhPdCz=XKA-WfF~^Q$ z^T>ITGX4u~)ggn`kJE-2+jTq0#yPj0I0x~2n=X3xV^OlNV)M_k7i~1cLaRSwbd!J? z?7W?J1<0mwd3GAA+#JbXuDxcm=UT3CME76yp0hPB_{?HmJVx_&y+o{pdr#c$I!hV` zKk&N!UKC@Z+d5DoGnoSK32yM>&2rp{*C#2b1wQJ(*JB-^Vf7~3S8DSNY4Z*}D39l5 zqODND()5L21J70(e{$IsLCheiawDN{nX5)!Xbc*;`bOtNnguGXCi*g?jau7J<#+`S zvkz)a*qP;-4@733-VyZtN8|5EZ)b8c%Hef1hmMaA12I(0-V)ob8+%q`-@Xu%*iC`m z`r8iHZ7AQzkvI_v<>*HMg`q2sYEW}8&lPz;;YFKF8c#A&KP@~~bN1z-z)OYayCGVLaou)#R?oa8+Qja>-U7B5$RWPE=ynJbe9NHSw9%?r z4mc*c8YVK{HtuCC7|s{{rT47=q>@fqOA{4}mbH(FxzDsfozdDe5ryMnG#AQ6DYsP3 zH0FRT27XtHpfI)@=%muP#`wXM7W$Dizay`%z`N}rFAU9*{~n?ro&^0DOI>8g-2V_pPS#=BgR*XQv|yJQTE;VOuR9%QBnK7 z1Q$mGo;Se#zo$Lu^?N?dj2R#2HqSmPKqp0KoD@ZCYRD--g7Jl&-2CnB+J9cvn~uVC z+On3bXCBwL$ekCf0{S5{lYWRM@o@KbN?;|7#e!J)15l-nNgR$D)%Nj$+QbL^^gLbeUle9<3 z*2J&AVZ=r*n_5L8YitzV%}cKUBQHhxKi;8nVi*Q`EXD?Snemt-7yQ^61HrGN!s~Np z5B#LnSL#SiyO$o3=w0~Tm%KH^+MJgA*fJV3$q6Gg6Y2)g{w;C@>a&nCNKxA~$jb*_ zR`1EjD3vn)6$y;{E#e5v2HeTV65XPq8bG+avSbHwH;LEj!s#m|MrTx7ny+CA%yqsb zN~4%9uiQfvO!Dk)#CUI(~BrK4{lG9=ZYC(cZlUlBDY;QolZ}Q!q=|2Y(>LNG*X@WJLY5l(!I={mror; z|8c55(1{}A)|<;NVQDDuL&+NZ#yX6DG!Ai9C*2`_5VVwgXI1&^qxYt8?DWK8Apa`3 zF1B4f38g!nJ<+Qz^jjg4=vVm#QjMC?nm{12&h@FEyS1=Kk&;dA9~_zVWewU6n{trw z#zP>|)&;HVUDzFwv^e`%T4=Ql(mcl-Oqxa_{I?Tz@-95?18(GI$bI)%#cf!Lj7M5p zyj`5_;#KeWXzX$hwD2_LJ~xvM-6aaTOxvR~Yc#QmNk9W;&5Px%e)i#6@@%rA7m;pz ztjUm(M(ncK^BSng_HrG#NSJ|#*$_j;-8pZT>utZ}ds4jK!+M0o+dRJQbH?ECH$j@{Cqv>wnw6_=UdkfEGJnE)}HW?q9mdFTRB4taLJlYhxy@ zyV?2@F_`!h#s0?8&8kB`cO7=))KY1elxY&vL8Y65gu^6hu(@d8=CPQU6-6F-0wEM6 z;VnD~iOwFDx=|A+Ba@?Qr@<$zY}!Q;Fd|zoR?*&RRP%{pGHf33qq3S3k49o7Kb*$u zBNHzOC_Gld8mU99yJZ^JjN$G}Qwl#D#-<2zLRY6D=o9u;GADo_CREb#8!VJag^{wt z*J*kWg5XiAhBjiNl3eS4{^aW+xHX(JzRkTF==%`9Z>?Hhrxwylyimnj1Jw5bu0;p# zE;roExR^$o@`A9=&|A2>oya8m4iJ@aV3#RI;BaGtA7{BJk)-|I>|F{d8ksOpq0Ym} zR>z01=o>6XrN%OU3&Xev2)W5PiUmD-0GF9W+IFT$v`S=qg#`X0q_+EYW z-KkQ+i2<29;KqUjzB2DBYb;Uria%fhxNN2VQpi>z_GLS>S_c{NL{pA92=^cT$c%Tf zvVhB5c|8p*4W1~Ow?+ZGaO8Y@K=gW#*_?qAv?%;{>|3O3Y|l%T9y~M;@fe}paojXs zJfi0P1k%oVzc`Tbd9h3SxUlLs_=)$jJvLx< z4-ZtMU+A$D{bb_tFi<%XFJw}P>q*PhOomrjq=~pAbP>Ouc)?Io8!V{*%>ITck8-SI z@^-GWLf}W@G&>gsKk)CqtzPln6wEO+yL$e{qvCdeZ}Kg4gU+S$q5xKTmExK!MIAr6 z=X~L>i5)mIDE)@O(Rl298#qh>4Ij1n`=c$d(pbbm;Xd0svAAjiw%4H#1Dud9%N$)7 z^sOHY>nlI#0*2$l&x2@Z&*3d)>#NV+v5`~enH`ma;PAZRu$rkqsr^SpmSdC$M&HtVQFEvLWVeJ;b8pW3zOK^J+oRqwD{#XXX;G`U-5%$h zCcjgWSLRt$*o~|<^|(PZ)#CeUEG)(?@7ke6t*2a#E;7XCd2;8{T#Rup?I1I^|HkrJ z6TO2Xv(m}-$`pn76_)s2rTo{m#$z9SoQq%w5RBBt%k6lXUHRD~>jJG$U7wh@c;jEJ zm8dvZEg?86+xTtY9XzZ1>n|~lk-N>LCx5}l!Aw}+d%2-^LQhDv+3V{}23Ezzrjt{4 zvVm(yQkkX&VAFZSX1j;BoB<~4vA|F=cF*@GHDUVaXT5OzSGNJU;X~bo_1^Wx*U!U7 z*;NqEP3*=6?QcODFSPi-;WxFT<48A1?SHD{?BEJI#k3N88< zeTXd1+ZtTQRO$2%?SDp=_y3%UeSL^?Dvp)#x|QTtG;yiHCW@_#o|@|_32uv~ zVq{Rv-K6~*?!?ES`5jTvu|kj$m`+I#oZ1U1Fl+gfyoG!7msj z;!E@7IeME7Kok&lD#QDkMk6Z@8o5VAKMoQvAlrl&SGE>Y6dFt3c)7jaP!%qP(u6cH z4~8lkiV=pKuZL3hsE7e77jriZ6X)2bP&LvXo)D)C@0)wn;#UmtCQMiR1y51N4K@9?7r~AN{9hz_xD6Ixf1*Omm;-qujLLF zzyV6gJRs>8h0xPHR^x4Ku-_4MHuc zByY5jKU}JD;8capNyIh6?Ta_g`|i9Cm@$Fz z?IM@4rr2w@earpbd%sYC-uLXqN4@JUaNDLyQ^;Vea8(oTZwQvlJ4`)|5@FJJI z`{3q1x?S}0C<}zBhKVVuTNg)Kgcs-5LFH1f*J~;*EWM_i9Lzwt zeJ|A^;;N6enp(P9h&@o`^-bf!O&09=JN68qU2N2DqcxX?5uJTJ;VI?q&ujPYO&$Xm zd}Ne~xP@6`GJ~t;xsIB64h9?o_YTPgIMEj5F%m}e)#$~iVHj?wuRACC3E}Ci`B&bg zz7HE+Sjx(F*e?ny0Xjx@_F2WxF2;6LPsKcARjwz>w>%5rgnVS zQW3{|Ycy(%JB!N_xigv%y8Vr4E2UMVxb{$8?tUh2#K*(XtB+njw=A+X#`7SYKRMI7 zX1n-)Gy{{5)^9~aByv+_c$}`J0lu!Z@pN<|CKO4|x4|WF-AxgC==={3#LbjGtM2M> zi74-kfuIwYs3AIifZp)384(c(efcK-A0vMqH|6LtCKaWvPLoSwxs3_?EGjE%7gY~o zDe7fs5%DkzQOtQ|@@?iW!%>?XM^0;e7>kmG)zQ%IOa(eECGDkR0~j$K>l!hktGBHF zvoW~4DyH^p!OMov;2MV}w=7vFoUZn2XjdHJ-Jg<23KzoH-nM{X!NGPQ+c4zY?ZXc& zUCY7luempL7y#Tbv&-8ZpekNn^jK@Gibwbmv*hK%a|`9Wfe!r72#cY4-ES?0-|iO- z`bnQ}jTx+vPe=(1w^|1-!UtQH_q?w`6>Nl(|5{Dce``neKV>A=Dymvrj0DzC)=K9V z%NEGpbI{lV4id-b#%4M$T0t(v0pZhzG^O46axgFgkbaR3IV zb@v0`teGKLqg_mW`{Mq)S%6CP1W_sH7r4kdS^XmShJ2~S^Kt9!-cc{06=;PO&@n!$ zPqwkguqongbtUeIE#LZS@uzu1uXSbvq8`>IjdI%evYq+svQ86o2Z&uL^Opn$NVj3d zhA}|e=KPFr3M;-997%lnlCslb*Rz&3!q4U}mZx;b z3OCw90As>q(QWl??xRTei%RypPBL(IM(_T`r{Q(8`(1AY%e%J*owy_+9CAnRsUHtN z%(e6yFmR*yIPLp!CjU-&;Kcu;mhBs{A|$0oLiPR=1Qb69lnx89tX;(Uak~51g%%}? zVe@XKUZ~yM85qf-$vYEve%0pKJK)se)W@f1k6ZpB3H=LzY*Ls*ANr1JUl z!`|+#h_R16ACSPo(o=dqgy`bCOtpHxZ^NbM)VDGgKmf*#BKi@SGP%AnC%nMLV0`4~ z)QkS6Nub}PB`Ike#6y+&~tDZ#Xi9>3S!A&)+P0y!y;8 zTPKYi;0I)dH9JCE)e6T-bhdH8@)WFnBUhWbHhL}a3l(u-T8|8RG6eJ+)eo#F8?@z@ zqpwy&sgeHCL6I+k4Y7Gub2QQ0VN5HaL*0TTx5qs|`c(n3N(H@j<*uJY;LTn?JdIuZ zxDr9^Uq1Oa{txEKcs6aG)!G3_s=fY{rKx~pG_4RR>rvRzJRSvifI0!D*8OAjnGdKc24x4W> z^#4wTcZ0im^xO@m5;E?feH<`TDBB`>30Tl0<3{)2``|M@=?K;??!+54sDc!{>eB{S ztx#|Km8bLabOe>HuLY1>Geh+l?AoJH zZZ{fE0~?rS91||=_K1Hc(VYUH`Q4aiud7LUBaDMr-bRc>9!6#;7ICnIlexvPYdkWb zhtR8#5b8Zm6p)9Gu}vmJ@k{|#hsOp*knt5FmM{x=;}d^2%DDvVY=Ex4OPx>?5@k^1 zT;PrVBLm_uls(xRt#7M$$RwY!M2`jkw~ig#WGYR5X30flvETp^U^>-vSP56Y|6e#< zzhWfb^fJ!~u54-Uz(M|w3E`kbIF6JNs5 zKL=%#wOS)`P_L0yllS7V6&>$WEpI;iRT%)KZqU}0)lJ?;tDLBG|K+H{gLXG>{u^tDSBgkx{{XifxO z;u-hHeXAuHEQZx**P6xC^@t(GJBDpefUUuWwlO8Z;-k5u-oq zZI*^?WOSf%=eo@^gB)?y@6Y@Ke_kb=%q-;bxR*@O+=k0Vw66YzTtO(jN!bkRgywx2pt3VzsM{m^6idu zr55uRxr(p=F*K*(EWuK=23ropR~wSZuN`BrfhIruDDNZ$WRmk6nP?KxTyTF|Gdr-U zqM{PshLMlvJnY*U`3_Rhw92LryabeTr&jyRS2htJC$iZgNy){Pz9TB^HX-?ly&ye6 zlpD6L~mhxA@21@zhR zO(uvk_8z*!1_H~!z36gy1Q zh=|!X!@;Tt&2H6nUH~3I4$ltT(HWGV>F7RZO8J(RONvigD5@e8K&Q1JEpPb zcQEd(@1Ua0N54d~j&@97b}74NUZJ)`5mkW$3uw9c4f{rHVF%-Lyo?HAA@=ub^16)- zRVX2y=XH(?Rc%wlHx6VqSp-3?d7NsHD@{VlBWT2xPF;yCc@m}9yC=AV>KkD*uf$D+yA-LWK1nJK4Xv`G?U=(xh~q$o3UFN@Bl^W$_8OC|pGxvNUX4Qi zvQUAULi~0`bUkW02xee6C^B)NyhY_GDl?iXT46j<($u8S>g%>}AlUyEM z-Okev2aKbceAaF=mW3C?@2fZ0U3MRY?u7>pK8uWrZoZ@KL$Q3@BD~KEFP2mLPQtzo zQW^^=xxeE60XUY-y?45$boNzwE0vw*vFu91rm5w}B-ZB6+E3z*xK~wu;4OCKxW9Wq zC!>bJuEkZHQMwdLjF~!Hq_6Nkw}W95X2Lw^FoYLaSz9O&ZfB}etQV?%TwFzY1UO3Jh zj_0k4=Xm7<{Xq``r9_6{57!#d;SmTQDf55-Xi%V9L?013l{}4$JoHnDir&8_y$q7C zn<8Zgy5X(snv$R7OD-b>*_$LT6wh_fnUY@#wzk&Q5sQj(R)6XInxS>{i0j3!k+iA|h&MtI+R~rgYK@fw4eb`2rrF2M z^*n2j-5Hm8UsLru6v{Ks@fw5J4u|zJL3ZHZ%2kXDtY4+ul=CH!zf4>@=?2(T|)Nw|{kSF6iaVt!4+cbHxG za=~sUnS7-*H@gys(=dHvaTzJOr&Ub)W<;hlBNWa6r%ih;^QM7FA?4fy`lX=FMVYj* z!9h|(+F_x{=3dU)L?wIih>rbL3XvqNb<@G32D)1KevT2p+m1b!0~uQbOhxyCIu9j( z?4t9bd|NoAudpO>9!C-B7Cpk|BqkGG}=}OO4KSRH& zMc%vxlNnlg*L1~ZANLC#2B^bHM26ky0=kaThM{?gm>(;89<3N+kidkHeJ2~4KyiCY zELC_qL*~dqe1mI1a>Ve|+BaccuL>PeK3z#*Ptv-%P{0+|H=IeT0Ov2gff_li)4^Em zLP+v;#@RAet?E0A2Ve*?jYfzGp5IWGBQj13X71858ZLqR z+eu9<(X$8P&qx$t{0;Bxe&XIV&V_@en~JJ}=u$^PnJO#nVf%dzbmyvxsfIGb?CLq~ zHsR^hN_pi{D*{pGi+m&>*IX<{^2IG*_fb?ctj}wLd}vcj?{sm+;^{e!b@fzHQ{66qf492)LG%iPBgSe z2{V%RwI0vcXWsF>tocBGn&UXR1^owSG-l>tYJJ!nizjX2`WoXadmL)#v90$+v`^+{ zzis|h;pQ9v*@A4B*rqY9XqbFG-vS7tLx;kcmcx-?X9Wab*TBQcRvd9pKZH`zDBtDB#=*L$o;wAPaU^J zsj>+UZ5n(YgG_)&(m+rC(o$bA;#R*owLjGm8?z6ZS^mUmYIslhJ}V_7!tK7b_eeGk z2Is)WtYw7iAis7Jb(FU52nUw__^}dA7{bOvzuRI=LTk*OyQ;rFf+EJIyHRR*fqpMq zF@@U;qwONZTs>~nf~R$hh;QTIt(aPwys~bpao~8;rhQzkG5FY3;W-91>$PN(WkA&$ zPv3==S2(=pHpB>71J>d}h^J6sN@;cdwVn{V=3Fsa^TTBHa4c^}wdgcb(uvOzC#6IP z0k2qlTveadE0N)r^XlyJcFb6PCpUy>rxZ?dC|zHjWD%`v1q16@r6w`n0w+EAN-Q9K zGV(Cnf=@1!z_GZ!b=E5(VEDVFIGntn%92;nZ7g`LI3jDPTh+xq<73`syvv=hdYaJy zmF$pM5A87O5TdXh)r&oW$5!IBFE2^e%vokwLu64<9n9*Evs-#SP$F#1Q7-H zV{@4&C51z;@Y0{7oPaz~-|cbGDpum@FG`T&bS9T>99N}K`ToPA@H4K$sQzft^l}i- zrN0_+KSU|SH0jlzt18rSFh3W_Xb#;d&n19bH1r_6us&@9J$TK1;0^XSiFsq}@NWiZ z@ioy<3eny`&9DatG;FK{z4@{3wlqOei&fJ zgD$`K#~+#US?#%0bUWw6ewcm`Xywg)Xac@PO@<7*ktxn!MLT3D=Bq7c8B_(wii$>^ z{17K)+V&l*J1X~?(u`4#lycikf-GIbRO|NjFdOCVTyIp0OU!Qbg$WHoT9V(KtR^(LQy_ zTcg-WYuL3Gcj!uqgv~siAyCsAu-1xm9~`P>j|1H$ zs^uDKqS^5Pf<`cHcUm(%g|cBkL0JySH?XNf)u~NAlc~ ziRSSWt?|v9V5!TH>UXpdMZurIR*&qK$_Lk2`+HBfV=BZu#uJC{Q8#(+6KpOT>(8g$ z4c49k(l3k0YDiFD?hv^8(;}qf+4OY}@@}-pjmi{bl)LRb4_A&!ulL4D89OF;iJ5+P zVjHQG5VxVMLuIR^gOI>}VssPGB&he(HmNRvWbG5-QrgxMZq&@N4URFe{64(0RTrxHU27M9W&2)ZzC0?1qK~Vlm8?W2*4Pt-U-*hf(glOEYeNEIqot#E z)TwPSQ3t)g;AMl?%8t4M4l9NU`})<0q<%ko{bcl}cQPW&FudGpiAlqDvaWo!o1UI- zWdZ)2gR7)28cGY==AclVVVMdo!+v_NofX+R00T2wp5FG5n)MZCidL#tt*>^1vty$O zyOMI!$aIF2s#lHY0ov-vTw63=zt&iHeuZ`r4^4Y8rLGRe5Est&Soy+LN?l%M0(Xx2 zkEk9p5lQNySb6|H$`qS+$;ms0V8LfxTiS%X5?)9|k^C{nAk>+$)NzhB*3kFh{y zrKZI9-v3>W845cG59!P9i(y}N)rEO%Fz*45=!N_26b-`$zhUrf>A#^iLC*o*lL@1~ zzc_K!Y`oNe!02Y0ls{03vCx)yw zI1aj`cVuP>82eI)dDiwx^~UsaX!gi4ppHfYr{WWls$h!u?~bJx?b#5%;VRhj^Yxa=t#X^ndRjQvTbK(75De-te@A>%O8R@*av**f>EP#rFv-a(qK+gS?aHHaLQEPdGO}bL0HVYw48pj{Lrx)b%G^3Z zlST2BE{-0|*xEinaEt8owp<&c#yW(C0AwigI_Pb0I#J=JIG4t*(W}4tUG51{pg1$Z z&aB`o62qE}0%?u_#m}$m!_%P08I%!}_nFvnJo*nX$UF75UhkE$q$Y2;WUv71gu)Bv zc5XX}ZOh_}*UUY{obX^NL%V^_78i7LAWCoN!!m^ET2h8F?7c`=Yx?75AIr#Jcut=D z^2(sK_xy2cbm9{Udywt1T+>>>2?s)6dv({4`2e@=lJ@8Z+a2?Hq!=+5gsBJ=29hPO zHshj$_|}s44lcw4WHJ!fuNM32hL2H7p$(?Tpz2C4x92RtiI}0Itb=6Hv4agx4H&D4 zvpeHb{<(&M7YN=h)0f?20fVKZjZ*xsS&St_1dZpM1eWKe#65wr%?&o%sl-A2p?4Gg_X*?R`J&Mxv14B#@03V*Z&s2|#oP`BL-S!w*IO zBDlCQwu@D%Cm6@L?fq96h1AZt5?NO#ics1p@glEqR%eZM$I427kaUa3iMZLHh6hY4 zQDm>WXruk+CdU5#5TT6-U%9*k9bAfMjBM}aHP?Mb3_(QYFL1-*9TCXiFgo7cDntShG@A4}@SF`Y z@xM#W9x9R$<#1--Z;UYtg9rPY_<>R7+UC1Q|3qlheCU6|@g!h;ReE0g(wnRxd!^4Pi4KcbSX5x*#Tkvv$z zC6-z^xgmO2vIo6PJ#I}`k`Sc=Sfc~B@2X}YbHr4YjVtSt&vnF>_pwy4MjO-Ev!bSf zC%W|8%JziXT!*A4{AF~s-Qu^&O*$64pof97no5G^e8Z(m5*|2tlB7Acqv~Dl`$6 ziH38#z~N2U2mPZUt=ZIv7SZ$>&wn?A&Lt$CuCCsR>1d0z`&^)D>q6`rUsT)%Ie;pc zsiml-%*@7NpEQrqChfh_k44(^+4 zO5tTycd!$=k4abojyi>{t_OWBmLD+=k%{uHH*r{2o=QTer%1cSEM71{srEGfPq=p* zv+T{0f~mMu-Wo8xX$H8!&~?HMn@o0HEaRU&eZ$Yt(r_-_Z<(QS`O2c1EBm1ewB zHIDqaw1Fw?rEyOLlMNs8?^$;@Bc;TxKKDXMrMz3>L!n0wyD|_tP|K$x4KZyt%p~a% zbt#hA2FPrv-(5Le$O=XNq%cW;QI^ch}dF*HTHN?{wBBA^JUiQx*;y*9%0l0b_ zz`@;XXi-_O0g48QNJl~8qA`B`+gK&f0sd(-eWvP;`eqe6#a%8qFY@@W#w{ z$36;?iTk~H4XB6AfA(4w;RfeJiUc27jngcWFDPBfbhg*{bZ?_0j@`*>X0fF*uw?5p zt6A}oE-V+feKlkLaj++b(YligD@`J~ib#<^6;2QgOOvxF`f&$`V;OhoE=FCa{e;HYS_etFK5dh z&)Y$Kq|7u$70;FUKYdUwS9{wPx1w}Z8fq>cea*{S|Jq@o?IT2ro>LS0Hw5}GksOf8 zpb^J|LxRNLVzvPa)_sF9v<^o(Ik=EU^j1C(K9-TVQW}Vs*Nr~{KK@n{)Y>x-^44OP zPK{W|goL9vrLe%a!>oIp_4dC_**I0G6J0}efX5|AiBnc_sZ($S_jqTy zS4Nf$v8O*7yGJl!xemSMeJN2`QHcCmWm>ys>Z=J@anEoOQ~GMXM2oCED@5@93Nn6|&i|e4e@co?@61pcT zg*<*s?i=5oP@i)-F4$MkuH)^5?JFzagJa;-QI^y)Q1o&##SwP3N4T&=fZ*q%=si~_ z(W+#<7TUWWDcneKY0`($Z|~sQqSLx73lU8imTL#*(@UN~gdU^H(R)iVitc#reOqsN zO;072H`bbuho0?JFa82G&N`OrQUUuFt(*$%(O6!MiFe=aPr{r_EE3e7G+2#$rWrM; zZt0*YpIbYemNZB*cw&3~FX0|-7j8o8;Ur%28xQ#|=yxs$%z47Sb)m2RtD`B8_BY-Vfa==pI!E zhrbe#hj)qGgc&j2(m!tbZ*pffJTtcX_M<3{iYG^U#@4_!F@2^vG8(Sw+5=PpDS+uCj)r$Uht2q zxrN(a`=dm-7gPP>$M+?B#*(qV*P7}N&w0lA7XtqeQa&U1rh%eF9ed(L+E#bo?%}k` z?>4Jl81-kUpw^2}U(_lK)1E&dQ9N77rN?l1a?X9HneXqzzR66gs#iOeaBnDtgr&X| z=iYmhu4;%cw_55)yg*-tu?P}s0k{#$=OmwbN`{>cIhltKS%tjPy1KasRrqh>a0q(M znV<26i2GBqR;#y?LEQ&@PFVO17XED0rs#y?;m10A_IE-$v8cZoX06kkEdAMa2VtvB zc_Dxw9zjn%*cKl2p~H~m?sZLawR1k~AJ$BQs5JqmQt|Ej2*LhuWA8s|DFZe^HVdyEeJQgpd!;dIP7$^S>DZ+28AD3wn3mMNN0OHa zA@SO{$V;Ut(?C6y zhkmZZ)*_t$>>@*W>7hD=3P~CDOYm~pjFJjx+YqLr;nRm_q|3QO?){fM3fTbBmLw&g ztJ_Oho*cYS(iSc-{w|GTxQpz<{%vNH-$ETZeQa;;jCR%RwXtLF#9l`EQUg`9s)^v9 z>_R0(SGRBMw+vqtjavjM`e6_VH;(cKIAStxfQob53v)7V#n z^!I8}utEgkpElS+1==QB6Z!rByDq2p(YsCYc_jXit^55n^j%kW1X=?2E7zg$gMo-^ z-44yMI0YR*kUwVIcVFR+!kuNz{R_6^J_xbjLSqCQ0OznX%wLGS%-W*zo43UEzm*<3oyp?>rIT>);>NkkEF^PWMF@nzP z`r6+VZdI?L*y;2a^f*;o(kv$ecf;zr)(~xN*e6XP5aJL>r}1xoI5zrLYZQLFj}eM} zUt}xG@pzLVMaq-_BzAe*^NrwvV?|~V8ytdo1uHB0uEi!oVn#)HSc=!2Qr5_8L8tlF z@4k+;(E>U2#l%SmJ>laOPDiD$*<2X~wx25@nX>GC0a}VcIFWOeLGoVhjl)EMb;x%c z^;7wffe=Ke9^LjmRES4o_^G{-T~SSWTVXAB+n`6Ix?$N67%1IkRva6}Mz{a1sjG1* ziDKowkEDJ%DwE0M{fTV*MFI5APiYOof1_iUI{o_UCRr?wOV9pPW%;SU+jBkOlEEKW zxc=Dvj0U#uUXFJu89Pa@Un5@trLB~@{<&_BvzVOOvwAK}VjNGsVoZ9Jua4(9C)WMB zsc{B)w0&dowF_IbiDMEFUO}ql>6xiEflObdN=k9Fkukqy7&7vp`J0-IBF_PE^dMwozAD6i@ z2_KX{+y?3t4>&r)Js$r*^XTS$YRwBT+(vwN-c=<#s33jBdz!z4YL8QL0~YD-?TC3d zf1e3rJZ$_-ha_pMInFcSgw3QW3xE;!S84O@ZZsy2Rmey6sW}w7(0}v3ot`rh?X6;d z3J1z_E-iAQnURnFt_k34xt43WmbbX@LOT|f@w?yeNmu^elc@~jY5m7yw$^0w)7tdk zbCP5oU9aF{!BQhQUL= z`57k|gNPC>=U58HGjH-_BifUIj{wyo_+-T5^;^~^5hajTf+Ifp5fZXGc|$-9+{Pnk zvh!13HW8XaG{z?1HQ-9)m$z3fP>i`kc9h=%eBRBOCv_xEKXn?fopdgCDm!mOzxK*M zDUbhbf+QEz;k6d@Zw<0DaH;>ow!(^hp~kHLsV7n_G zZ(?D^sxDwmG4`Ns46P-K9AA(Q1nv{UO6rpTYT!qANN;&OvG{b9FZ&O^=*>C(``*7v zaxLeR0924D^;2G6?d!%mvav5Eg|*yl z6UyYcrw&QT`##R9`u#l?aDvLdKxOn8HsE}I3@+T@q$u|(IPtrkG2Hp*2;;lPq7iJ4 z#Utay{qPRnh)ulP+|NU2HafX{!rpN$7kn`0;Pa+6ad+}(ml8feRyj<}L@OnM9g%np zuq%+Y)3@U7wqmE>Xffx3rU*bzSzJ`hSYsS;FXGmaTMK^T)f-6UgBKt*7G_0bJell6 z|997w{h8aU`7p;<>?U=0y^hU-6S|z7+i*T-?c5&5QAa4?E8h z887OdH*W-gaYfT)KpsU{|Ft?fOTT8>#l(9f(c@TBVyx=MMZ`IU&QO-dJFWN#U)N%K zf;ZamCAaKKU$3+NgP`I`!p^Du=v@N%A0r9uf1mNLx1WELziq!2c7q=;?Ee}QMR?Yb zkWMqJ6kZ=cpLw*&vyX?r`}hmHymD)WY~eBQFoon)iSKxfc!-q=Pj!M1juWc|+cPO~ zq|`Af_(<@mCSjy&MFRwC+%7WRM5nd+buY(jJonCb;}Ni_KL}fS_im}MD8+GRf3~Qm z)Cb?N2H!69Rn{H&IzE-!+l4yxIgQogZ&kPB$+WHNi9G%K31h(v<`?eqScRW7f@W1J z>{Z~il4aPujtltl%qDf71-)T?S;#fpL+eObQL(Tmz5XSB2HtG5G))rVD-c`^GMiS^ zHv*hhwIX6R^HsHUu@xcpuLX?O+y1$Q!5kNMiVs*0F<%t75wTVxn0Ke|CGb%mcvkIATmozT(8SdOg?#qS$-K zA(Wh#M&fweB9J>_9F3X*okOqJH|XIWlzr6p=^Sg;2F2cwOq@!T+6k* zWo24q;~=F)r$uSfKKnrA?j;&hSN*lg8*1 zZE7Hr2{aB)bZV3RZNi~dgbUmk0$#vHB?NHc@il@)W6BW(n+fxR4=9@=xn@M5FE*%( zNIf-i_My1|$_2qn)Q#~0==)_Vf<$TZN>QcKzg{uw*W_(}&)>m7Nodw^!*5wmUVAbk z0zh!yl242uK_m=oy^FqPuWVEhX@+<1?SKh#ieCN8{hc z%XE}bqEEm10aJ?_L8f%Fan+}gnXgz~901L+Y&N3o9)r#5O zjeqr*e5(AxfBy^Rjg}wy2R|ww_~73aCCTB<4Y4>u{)NY7!kIq#5x^qE_q)IMyzfKu zv7dil-e~!+|K#tB9#30DvQ!^mw#B1zk2rx7fp}apZ+eI%t?=WNiEjLB=_7^X6tb%M z4SF<^m9a8I@`-hmbK%(hOVA+aDT9q3HMdcCWtIyaCa`HEp`Wzo3Mljw$zIlZKJmzY zW2d;sBomI-j0%#188PI^ftzh>i&oBWk%&j~@z2Taonv10Hrq%VvX3}moR7HHv~4)0 zdh%n-L~byf;wZov{1WodX8a#ZAk?RaCQNSo#+0CqJP2bfzU zn~eJK-}oJm;&a=^G6i@$0q<_@&^Npv`HcHulPzNxz>m#ux`oVzmifYH(BJ?xf>(^E z$+Y3lY2^1EA7#>it*6m*!%yA^w8gw8T6+&x!H3`!y1IOF{cPu?#wTbvx;h>Qef$L` zcV9l^^WHAM=JVbWzf-g{dN-2u8ta&JG-wDtmhU%{s$+B1@vh%TciGD$>HF~)$99`w zrD|#C?lk5oX@gq)=>)T{B?Ty;?=Mvb3QxO{YII^=z5o|IV4X`jseKvI#N)=SIle!X ziCqG@Ik7P!qV<i)3dqrWcqWp1m|ri)h0OZ6KBBzQ3xYSea`^QEH_j)R#2)ple&F$s_2 zo^J?@E^2?prE1Rq3H54I2uC6N@$iw#lP8uN@d$OmikQa;mp(5s@<>PQB3fvcVyn3u zCH{8U*^qq`#vNl4v;Y5>z5fsTHB0Wou}BA$zMpSiUn1~atc*axZ+AVL0D9hKP(~1f20yXvISL=k&sgrgk+mFMu?O{ zkP%8!VHK^ZtRU>n?%aE4=6yQv^PK*4f4a~4zW46j>zZ}d_sqQa`}{aRy8HC6bNZa~ zESX%xZo!9s{m}!tz1`)>liN|=;47q#&7+h>*q+q{yR4aJ131vB5^_vR#*kxzM+D>cu_RNoyib{iqPHd4}( z2hUVjds;ZxB3+Y6io8%i?%8Jw{uLp;#RDJ>9D4wzGyxrH6nrb`f2foKSyI4*?d1fmh)n$k)<1j5 zApcYc>!G0l=vBo5RU6GljvbJjU|E!E3l>TdKi36=j^Fi1J|-_CeaD~pGszFZ6QCK< zLh*gg9pnEqad1>*d_yaOhwRI!hO8gApZVD3X*jW$3Czr8H z^!C;yT_1DGDeY+0JNlb+-|_tEp&|dPHFcah)^Gxcrm7~P@e9OfY9H=h%Qr$Mme~>Kl!{35> zixQgsV9X1sK=O}GKV1eSu+`}f4!%fvSixyoVSzpK9=m}5?|w zGkW899sb6-`&U!xbzU`M^pVXb9UAjgD*4$8u7vGF6Ur{Xu-$`>O`#i3a?rBK zZlya%k?|tczR9Z(Z{+Da`xyl8@E|aI{-=Ot;I`W?tGVa&p$5=-5}Smeon@VdCe$w~ z6)(Tnm*tZgF`Yht6*+7cpRMVf!b%)e<}6gXAkh^1ePuHuG;8u_4hrf z4394TrQ;nO$EY<2qsH~7GpdVG3_F~5!Aoc7jN1!%DZjFD7ERl&=}1n^XkCF9&XMJ` zwG|I7AxJ-rpWD<*@JD@^HHL%H9KTlP61$jKaa4+fueH5>oZwjC8vd)sv&41$!Cy`o zIv^^!8(a%y+#iew`{f3QjTeuAN4p@}F9hmyA;6l6^gDuN`D#!jbn(l-TzsIgDC1r8mmu~?kPuFx`$9;Z@SF$E= zOu3?6qmHg@xUDKr0kU3K)yu}ZfMJtdfB+uBzz6)XHQPtpN-|WV(sg1-RHq98gXgu= z%UCB0FKAHL%h^8XwT39lr451(GkTtjstEdZGLcS5@N7^%2AWD`s`47BfUZm%t#o6- zCc}W>lT9$Oy~gfDBh}CRVWpj~{B^%ZKK?KL9(mDp?EL+uPyI^ht{d#WbDeSQWkMhe zdIt+qR<=17=X6~|x*>d=yZ^rb&;4KIlXvaEX!@Uh`+rwH^2Y1a_atjz)(V`^k7YA8<(Wn0oM7a>pX* z47^SqA76b>{dNP}O|$_Gv0yOti>53eZH)l0#BPb3?dH^g=lA6`1L)`bJtvOxm}JsV zVaL)=AXs_S3;92e7ItzIFEuG(p*SrZ zgYFly0Y(0ecKm}!$R=4Y11P$kcew#S=27Do`QYbj+npYCF~WxUxu|mL2<~I<9~{#N zoV3_-k+geBRpiA5S;*pl1}=AP{QOUSM*hxEy;=OpfBK)l3j*H-f*ZieyMdmCJZ=&i#qE1}YN%&+>lzF&y{aR{R*W25-XXNQf*t#s9lL*D* z>6^bD=?h7v;d~FQdZB#3*2VRzi}k`UzYlN-r&Zk|_w@6M7KO)G*X#L`fN9YedXWM6 zrztMKJ;d~ZvM!YhBmRZH;TJ>@E(iTlzzP|$@`BV{l@HisN3@SWGp|;JL$;N4i?(O9 zutdvjM9~p>#4ZI%NiPZ6A=RoB+5T5V9a00H-N&*blE_=ekr#)=~?Xs&s&U49nHu|{lopKgfHF=`(OEECxh4*xPiVO`J#ui-T`X`{vX<6FHXJfKNuDzoOZ9C@(#RnjLR-%&|ply^dY8w3LM_C=@h68x=nJt#=u zLDn+1L5|b^mx6l0f=Aq63OEUEF`8>vNf~T)R)3vlGxT}{^fg`6HC@veL}J61E2C9b z!BWnHbSZdzDHzLja{%_f)Ppeh1)RB^`^v0>${E-b$>2eE-_soC5zsX#%)5lcsZyaq zd2>>=YueAQR-Cer~PFl*N3 zjsrWsF$qO<3{VPwN=}ptRVon}R^Y4QL{2bFeQAw%66enA<8PG1j^derE$G%}D`K*_ zce+(@a!|JSg$+uB98FSKYdJe3Cp<35&2m!0XrRY1mS^lN`vjFp8_;Rt8X-CHDx?oi zMEhi~l`?&D%}NVZ7n!eIRAC*K6Ihs0!_hrjn#^6e8C*synE1x3(JUCj6Jdn2n+$_G z$XS0Og?u6l`T=$>kvc8uaH-El<;7DMBi90RlN$Yu!E_lcG+k^grA5iHmKix#6Hr|5 z_?6%jA(_sw{rE3-2ubG8!Pi*Hi*gtoHD;HYE>(bH&q4TZTIDVh{)XU7{`f1;JbkQ^X6Hh<23U zg7CwNZ9aK+28ToZ$tP&KV7F#Z-7h?8qa65hUR1lNzTQu|!S~O?CT-D|>4&DDK6ZBO zY;0qvaM0fE1$K}0bkJqT4iWgM0vuU)1XTtLr;-gD5Q`l`Uydqw(yPb6{dmXVUf^X$ zJPQ7|>Ssur5Gl}!qy*%{vIwWyDIwin{QsT#-f;yO2L8yPW9o+jk_@jZWggR)+GLGt ziFWoRUFerR6rxQF^+FC|(n)UwER7A||7%v0Foi8+Y(&bTDm1pKRa?-?GFzz#-SYEy z0pR10t2_e0|J4WrGyH*E1;J`gg*r3r^iKId(yMpTqYphgPPs67`^hekpH}%V_Frq= zJ#qK7p^;$h5c-41zU6vR)_+raq~LuXTm6bktfNJK0u=t*g{q|(xPlZ>o%yNxPpM1C zqX(@XvsxL8;wpvCA1an~ZiQ`G3FoyA!+d?Bu&zS7E3N(#GTy=O>|y}Vv{ z*U56eyF_PMz-0H_S5;Hmutk5c?@)M&>M*I#gRaF0Db-gOG8}&oy4?87@Dq%JQk=KQ zH0ggGO%{E%>b#ZCkr4TKqN$9h;w7IKp5{wR=jJ=6UFd0Zav67y2-`SmD$a_au$^jP zyUj~KD6NYK=`zwauvvsawOQ1_g9mypgumTQbVV#w_*}|3%bhUL#tUtEW6_`_O;5iC zE858u8a$E};Y1JMpFS!x2QA)2$K9oeuiczGp5K1^J*k5hw?pQiLjm0-=l=i}PX2+6 z?|h_C;F!8BSUNznfR$wgWugQLr|m{TTz}2ZIk>`T{?;tU|9R?}^TI-(;u9lUkQify zSlkHSJ+p3M=P*B+!Sg+2P17mJn(cZ7^fg`6HC@veM5-&Rtvu`bE(L1WE9z^?$*?-` z>-U_$U*A{vC7AgA9JrqIYw-lrZO%aOnOl^;e-@Lr?`XmCRG^b+!ef- zpa~Yt=UqDbebQyUFu@4ME*Fs>^rbohOBrAkw$lR9wARAkDR>k3bObVIX&;LPm>lS% za*QYXFQ_WSoMRGR366Ny07>bW7^t7zx@rBEp1;KS1btoxJi?hP{h~3iXLq`<^sj0w z?}aar@bgRRy<%A}>Q-q30HZ7bU!{#Tw-|f@_GGywbJT%UL#ogNytp-a@f+qHZG&p0 zIJ%YFEW@VOcUt=m{mn87)Gz_BZBVCEbykkttdJM%^WCJQCqgx4)Y>$;n2Opd_EnudjO@}lX_{MmnB{{E*vUErvy z*FsP2p(Af-wRqDRmJ3G8;td4wbp-Q^zQ4Qqp?~ia@`<1Od-9^`+duYE`HC<55?Tch zjg#8bjP)PEt`e)xbKc2Uo=5*`Q4dPjLi%CY(#_>qN8NF(v&0TO6yqw6w1sf7I-&`u z-TGWrZ)mB+W%8 zMc6YPwo=nJ5{*v0Ol7I&KHp@y;2@tR4sq-BJaLR~>2jyq{JDehcf|WD^%V!g6Anoq z-=D=I22C#!fojNQb*GJj|5D^GuAq>p-$p%T5pZ;)=Z&@`dr(8cO7#8a^2@tzl=!hH z1)U_tA5gFl4w#0YaXJknFNca$C!IeYH=^py_Y^-EYX({7YXfI;=5Y z@?om(HGhZ>aSh#XREITqy|#Qt zIg|i2<7X1YRNj5RLISX>#sc$(QpZ{YmSYF-JMZqK z!*qh%iQ;1_)qNYf8v5>LHRlR+u;+b`(f;4p>9k3EWC>GE_CrIJ9Ywt@6y(%Z#?RO zudR*)&si7|c|MYx=Ve_^y=^OgHw&Fny~#)UYvlir=eyD3IilflbqxSt(=}bwHGKi3 z)gb*yJs`@#+h+x0k#|*Jf3^zr_WZd@{jw8uU%CWy4%QLKlNiLSUUFe`;wB7ZbG*2I zrdy_TEU{ZyweA2xTlj|CY7hwUjT{zkyzB~->TI2L7Z3S#VFE8qwuBE5UKe&drH8lX z21&fxLD9A{G92+0wGm)seyR?;SsT@?Xd&q&ISK?L*J-USSxlDIvL4+>>y&hHjlgq0P12g=ziGw#o%k|%k_Hx#f7MVYHfBAs zo*W>^N)anf%(EH^8Q)^6pLa20qW{EOBnIxl5pX9g!w~T|MzKJJX_=f>^?;PO6(`n} zfGr2ZgrinE6(2wvO+@4(EBfFcV^@}9XQm(k_-duOIyPg0g32HNm;a!=X!_(Y|B8J7 zpZ&>%jCH?c&}4V8&%Lu}&~NuM+uH&gA)QZ0`?8Kl@Ch=WtFTr6%^&zn@}lY31^k`g z_TPzbS3y^?&%(BIZ}v_K4l?B1d3q;*kta`_JW?;3EIJHO&Aabj#dkFEB4?w&gC;a7!t#FP@826nknp70Zc!JWrDbts{NLl< z`E6jY44(kF_0vhlf^(~SWNLUQnnj?uW7xZ&(4Wem%Zd6t)|#$!c22Q5V($@f0HG) znUb`}sRrBve{WjJhtq6w?B2dnVbwnToqhDx@g2GN#5!wLtKaf<2H!1%&^*c5POc8P z`DVyZ$^-|e73X;?wMPj&((|ax=uUQ$^@OX1AZdXsDkrJ2+I;6Ko`~Ogpk-Az38BG@ zEATmx>OZG`;ql6#67yc}#4dJqVK>kozzJz1{i+P8&ba>kProVu*SrYqwQgr!_wcztYRXj zQ+0e}^y_Z(G<@v(bUf3dQ{$N|`dv$={L#c9+7?-k?>T!ebjtSFUNCH^7yibU9UwyW z#e%%H3;4m!(BtpEn@oUtq^b|Bv=ehL4R0o&ES5ya}QxA;Ds+1!`hjHGjN zwn@%waaokE8#t@P{kNorN*OqHHelx}TqyXR65%%Ck&oG;0)nUVde4@`Et9+V@{*S3 z*6yB#|I7U|IlT+e352eP0y@zeoDYFesne*VimiRGg@G``Fha|qQHqmHu#`4jQD6cKFnj+PL6_io z<(7F6IKaRNgXs)T&$4U6a+Q;|?9B53giBvwxz95ZQ|JX5ark*c>cp#k^A7{D39d=; zv2B@zmuLV!u3W(rjl5!&7t4TsSHUi@H;ry&#+hL2FybAHq^(2rt7k3-x${bM7iN|J z1#HS$>Y|#I_Yp9H4TqY@#Srwb)pw<7u@s@%m=cDTy2wD9O7~%l20k$nvhqWqN*MJ! z1Nbf9^ilcBFaJ_`(e(X)?kDAwpZc^{pNl($o^1X%&>jTRBue5W%mP;A6?x8DeYa=- z4%Cr8@i+gT{I!>`3;3IV|JTXy`kLS5gLapXO$!f207kMq)9lznrbiy|>0Ty}RB}OB zcKvpbjfKwK>5~ZRd=T?n#O)I_vCL&9$^{9F>{>E`6A@Os_F!d5v;t-9iLyarf&_$|Bail zWrKE_G?(;`@VAG(tx4o^$3<6qlXMRji&=wJLwKt#1 zp$^Y5vdYe=Tj1_2r-^kZ#7z3Yu}n;r7RCi8 zDxw}jC&SBdkhDOGlGOok&K)C<{MOpBl0~veI-h1U?XklJ4XF@aiQrk5DCQm}9IJeW zI_l&ZfHf0(p77QF@5t0F;Z&)#iLcS=1%*azix*rceJ|43q0LE5ren0x`hnYs$+IMH zIDq_LL6be;2IG(`V>D%Q-jfP75tt?TAMI{I$l6_YSzcA8jkSVLc%roPv@(!PGo#%a z#B0X&gAhtO%Pa;IqpLc=I?IL-j729`NnA~xzqILe;>`(Wt&?@=>ptFz=VF)jArU-z zq}s67Q0NozECT%onNW>qN-(GVk9_FH;5o4CN*RS5Ut%~^riD(S|F|y+s}xf$1L=@+ zuXEpXa5iXdLFD^vvSuf`yyQyZY$xG39&M^+K+3h1tBz~A)`Su5w{(8iJt-IcK$08v znItWbydQbvL-Jk!@*k2HO`rVbPs^YAvp<D&eE|Lqh|N}oVrG)PaH+gokAoB9X*Av96qb;i!t^Rcgd zmxcTXdpK>(iac)3KApds@|1!4Tx@ri+r+@Ore-{gNBuO;UhxmwnSdG4hEQVT_Vl%dJBzf%*iFc?2yaU?^ zTVWzXo9a{P3;0(BcHOLX2|ZA6k5G_4$z6ko<}{KigYz;ii{5z!S73-NHs ztBv}^#G+^GVzvAtpX>OEqz!Ii*kykH zJV|9;hu-t|A}Pun{q?k>3s}>_d_Q-w>%a{JLMz5*QG}~!% z%xY*76p~ww_bUR9mODRdYYR&FQa32cJ7|=??FD%$%%Zg}t8&XJ0CCqU9_Bb` z&>^fo^o4fWR_XFzgQ((k(s*~+%Hw2)ci&4LZiV42eV;-s5v!dOco)0r?~+70He}kK zP3}nu*kS&>Q7TF97y?xXt@GIAWHNBh7k$yIr$6)d<9DS8CDGQUxp4R|dmGn;e+?f% zax5Nlf=+H@8t`J_?D#ZHa%u4)rNRXQ;*=hvK0CilOuQKOU$iL>%W)I+w^=H#-52d; zfH}*;Z{e{ip_6n72M}+!YXJC~uIZYt>4Qw#j9*Xuj(>X)nDh7RvVyEV)72>H^LW1s zSl@>a%FgvNTuSv{s>SG+k7GN^rXl6;`2xmTr!CuICkYOH$-|C;0R|l1mrfb^EL33$ z?Rt5k!KFK6Z8(HUOc?aw2U#cc_AsHud8_|iCnl5~(q5mJp1!-L&I{+Cw)~tg9qsg^ z_SWCor%dRX=al+f78uHuU*LdY6u>iM(z;2Ejs*4RyGa?bbR_Xg-C@)Ujs*>(rF2k< z2I1gt?6ezut3HSuwBn#&J{tx39lYLXBXHIHmHY-uMbD%Xi3b~rZ}w;Lo=<+xNxPI; zOCZE*DK1{%08V+pa`qnv0tQ+_r+7O6Idv7|lJr{XiT-@F;rLA77v&ulnox(1liD}$ zJL!e%1o(sx@+LtI$-#E^fAF60;Gy!~3WON5^cOkwn@cmix7Z0uK_>H zF$PqS&oTqkpwoWgxD19M{72&NdJb4}cMBRg{>3*0L0hGPa}LyI9f~}urnJ4Nbiu0N zpr^x}DzBa*KpC^$$;kTASCiCLP!V`zHHS{@lJGzIAOHTBvitYDzwa-ekYJbPc|5D^ zMHQd=%L#}hT@xBjx+>ea*=`g&VG=satOkyc$?3oUsedRx_(MM>FPe@Wz{lU1B-)B? zhW^OKDS$v_Obqva9^WO4BcLVajqM%U>AWtNbd#!opLZe4Y#-_P5@>fVf;s*@i)=H0 zN!ZX)2FIDPzJTa!vEP+*ZOop8p4cSe&hHJgeu6KPZ6WRZZTSXqrAx}|F}-qbFm~T0 zztK9{+KMk@Zgcb5z%%XWu$@7E?*on9ky(og)(rs0p(C`Ya2#oV^2m<%z%}E0ZCjI% zoVb%0PMC;g{&D0fk0f11%X93ujh(j|SqF`M*Yuvsx%l)-^y5jyuq)BDiZSj@v07VP> z)J973f1<%>d3)mrzx-!E{Zw~n2_br_=+&OqPJpzpEk_Za(r?#X_BW3s1o z35LEPm3*c+c)}Pf5GWe+dNjHVbz*l|?|+e|=eb>?>v25&>kr26+NXC>->0_;^U`Og z4mU{?#IKU0>R4+9SJuXT-`|a0RBOL?u9UNBuhZ6L%0sJd+agPU7?18D8Ig(%gj`G| zzdSqN^W=Te@_OOA$VcLy7|Zuo~asB~J-NTco$FHTc?1?Jiw` ztZQmilWVCbQEZ#@aoczsHYl3YsxpeL&{Ai|%gVT_f#2{jf}Q>Gc&FKxl5T>XI_;|{ z`8*3u7yf{Vke`qzvkaZ5W$4*$D%0wrf5iDX{u%XQOoAG6VQ;}q;1jcHDxx1gl@&Tg z4JJ~9(OQQ{UFz6}@-k(v!?KOAk5Ev0oI-JP=70S5d*N$vF!xx<$m3jVoev2pfzl*$ zypP~&QwF^Fs^sNgH$<9+1}uBd>%i|Uupa+~n5)3gz){lUcPoqjjtrYGb_@xkKEc9) zkbh^3b9b;&ALu++buNCi?DzQON9oH^*EIlqP1kfy*Yp7<4#=`mex7m&U?8o^Ju6VW z3J71ScNO%#RBwl2m2ZV_!gan0!_1aliznY5hw1^0W1@K?qd6I(OCPxotXqZ?9P+%} zu?Si+Y+5P|qp$SL$XUf`GIs*UDEn*@Qy(I><`b)R!>MdO(LBa!J0`M!lD>daRb(2; z7@Vo_{CslHii5~0#z!<5uP7y?mw2vDB-P(34Z;X$S{$#&QkabGlU0FJC;g()*hvMr z$W1Sk*p7Iv__Xl3wGTeSK_@;3|6zcjTSGhhA#s-QbGsZyU{u-;7QQC`U&$G+qrW;Z z1MKWT=iIIHspbTZ5==V{ev*nY21r?o5l_C~V?sR{46-)*z>3yLI>;LLz#BCw7$pfD z+3Eyxk^75``gx{F#x(T+pwKZnp#)Qq&DJ*JEUB~ZBMR0$*{!vJD3v9swAu#ay3kjX z?ATPj;l0scqF#DqDh_4?Ud(rzD#PeqVXg!)2Wm3x4vurmz=`t#mutAJk`jA`U<5oW z86?AFEp-lg_V$e`r4l0CkC1=Kt^-?9QKfoHaHuvfUv(Gw{jTr$W_i(c?Ed|C{=NTD z;&@ZnPrR1d+;*mZ7&}Mtu0Uope*-5D%$+E0Y@?jfRYH!A^lyIukIS2HJ(d?u|GR(f ze;C0O{6WW~FIm)r|3%|lrGWDcR%+@^_U}TM?qfG;w^hiy6?;4E6?V9v?b1^tJv zY-}Cp)9bqXkRp}(eZ!H?=f4^7SJ|Qt@1~@a3CWnGHMO+eG%a?PKZAw-UR_6R+fA`Y zLl$&=%eC2&5nrQS)H)`Gu)}swm0Zeh%KfPkh!tv&eiFv$C)ZI_5AaEn8sRMw90os$ zXyoT$`0YLdLtFT^wQpWD1ut_NrOy4ymE(mnCR_kwNc0oB|&lK#~o<~Uv( z%&X*&k|}Yy!f|{7XZ(wa#pK2DruE%UyUN2HjEnqq0Q0m3jsQFAau_yf0R#U@d}p{! zda6l5P8W+ick)%Omrrez6OLB;tmqbDIwnz?_AP#vQC(;!Y#uY6L8hsqsRiz*tbEWu zamS*Ft=LYo|5C?>cs{vp=p&a$;C9`CIh4RzXTYvX10Q`6VgSP_F#lw;@s?JuU>+^?Xss`7NogeSxBkw` z>wMM}C*-|X3q4kqtW#ds`CGQqmR@SZE?2|Vtx&%&J*$ioInQgGpWRpY=kvU$lYW=# zw>7NKYAZC3&Ch}tXSH;(j*GY~bk30%3pJ_^71Ax0$C0Xx%(`yL$NoU0PK^i5;(a_~ z!ey%bQ!NcO%ibZI(##weHZ3nKk{SG47+)qtip`VW3zwf+j zIi6q#AfTgifK4ln8oFfLM0jki&WPzt<~$)5v61PLSkT^xZq0Wo^9JBUr^9i*-3ifa zk8b4Y(_NlCB}JY<)iDE6U&*&I?%?oUr3y^~SDG=#t0`lQbI>|yjH8+BT$mJG3&t2FZ3+uL0m|x~6NorZ1GV zG^(EN3lOi$aemIj_1y=#sD}EF6}K6Ux_nZW;seI+;UGg*Hc* zM@t2UQ4gFZRh!-``5@tZi^TUtc;L@Lj`&rb2NcNH-YGdfa2>+27IJ)4OWjMySm10Y zk>GITHd&NpS}cD>>tLjV zV>!?Ou^B{}GcpovQKr;d)67_b)J(klN2QX|evH2@uFQn|U5Hxfta zCz2`cgSy2)I&+&`WCfEdtE3A;$5`p@v=pUVQ*u`NYH9n8Y^Eh|L!P?kFlF66TKnTK zA^3ZwKk_I3j9}76Sf*gR!VYYwz22P;H-0k5067H2(E~2+`%Q`kOrzd?=kKdSn7kgB z{^hGPZ#s5|Af zE&?E2ozKo)lMch?x-Ob`h8%%C%Sj{$aohStPjXJtKZe?J$M6W`Tj;Fw@_^w+gFnx2 z@JjCNK!rU(3b|JQ#%|aahxg!{Tf05$Ja?Gy<~zMCzrkkyZBomLp|SejVKXZMRp@-s z3-u0h&TsH~rZl(8!5E3jD3Cn@qL#ZlBk*KNX|ReiKNbIjbY2>=5d_|pblJ;GX<9Vw zfurqxoiO1AZX?((gp>0D@2)=b-Oy<@5wM9od(j<8VMZLL+@)fYYJO0UBrVGBW<|%R zNz&k#^q;c*=%-@8rR>HIk=F`u@W4GYd)PV6P8jE1{eIl-EAl{{n9H0rdX=yAATZ+q`~Tp9%7KDy3b4&7}bb7cP7G5d9 zOZe*2@IhURBFp|ho;8Kx4=DK4b@)qmdn*Ut94HKnhuXluyaL*+G|_TzdyUXxj{W0Ud=kE_Hq53NlB&x zMj)-QCzsiI`MeX%^;qD5xuXR=^*#m=2|o%jmT$wycoFTuCg??)#0C;BBvS0r#6GQ4 z80J?Wj3c1meUE{rjJlXlZR3`>q~b<)J^hWEITxa7)H!@9otokCtct`ORW5cUALjgL zw2?tmk=H-;;CwlD|0c~800(+n+b!hKsVwY3d^Y5GPK)^%?=29JqN8)3#-AM5+h}KZ z!vmi``Q8dWVq*gQe@VPF7M5-err|h*|80`v3hriyH5MT&P_Te4>1a-SEO_MkQs#Jn zvR#jWzNTxsrfd3wN%sY8r$MNy^i|kloM{4t?^pG4Ue3q$^>V8Kbg%C|+~$G$>@s3- zJ?a;70F3fjyq7*qH2y^!RwtCGEiQ|}JdTnc_@!f2ClldV60E%mk>y}&dQX|uCy-9l zt;0bWPEU0#!xLdpRJb4`O)8q+`&nXkzMpY62k#tK;_$AWS85N7k zr*Q9xBoqCD7kPlt|6lJtf#MpUtN7_7C z5Oi+z5sASX8fA`C^htJa0V#BpE0a>Y(}VRGXul$*E(T-C76XRLzjGz!yOl4R&@~|v z_tdH0%dR*oO(k^#!CZKon{76!@IBd;^ESq2S_Z2av;=T~kp|UPI4QsqM&24co%B%H z+;g5?n6r=Ka4$#oXXHQn*`H5ZNa~?;CtvSR)22I; zYTD#BkdhRouor$^f^%o&(~1ciuT*~U&;OMC(x?8BylDDYzwP(Q8*jW8Z64p0$^}Uj z5HeyL9D5tbDu9pUDt1eU-7k8s+n~|T?)kub=X;abZG5Di8Pd`&ju{axK3`1W&@=Yo z)FCZ?tjNNLtbyL0`p{c-eRt&B&)_!#>BFw==TW13^M5vvupbKv5K!Mm$R7awBj|kg zkNcHpeh^(k?bJ3FxWqTtPF~tV?{T>}63}VS@`?Tl-$vkbrA-_=UNvP!QxZ-XoUg$z zuxZEljLl`N5cmZW+uGe`|8AoRK}R|AI>5q#?ij0R?&dH}-HW60Q@+s>7E4(46<&LF z4K_bAF)0-Gj^zV8v&e%Go-76aWHyDehHRq~_Vy_fOfE)!;xrHsnvwD&^%g#)Nw#f` z|4AL3bz-4H_gNWs$S7WbcbxrVr*(`eiaqBZ2Ar`hBjMNNKQ@u(&w?J^j!NRYQPdZU zF32=^-CAhHecx^DM*3iSpN*5%s{Tk55D{m<#a-OCR>7=8Za zJ(G8CM=osurG`&Tonw1lVWX{Mvr%JPjm^evlEzkJ+qP}1v2CldZDYk+$;!#Q_u2cL zUobz-=bG~w_ZYWki}bRmZ@ao#c`;JKe4E69g&1UOR-&S4%}7ZNzRZo;S}TIxU4(*X z#H8FAk=1Y6CD%0+=)oyqZo!{ZU6s(CbB^_n3IOl%TZj}|6xa{;tHgjrL{%0@| zjmy90PUtnHPOSWh&!c_rZh^BnmxpEc-|`%5=xXO5{4j#`utoGX%sxB&Fjq8p_VW0>-N{k^ zlUE#UK#<>LodmGOee2(&#`-Mtgr$ZCu8K#@?FHSJU4(w@NUcOJxW3S3@j2AT%ZB?5 z?mQP|J22A?^Yq)T%2h*9P$UJMV22J{Gdmlut0?B)5mV#7s_e2viiBcp|L=t!BFUq{ z6`jF^$g--zQ;+lb>XTzqf=6tNn(5mYq1q#OrgF=ESBB;fjdHeIQhh|oD+*8@iQV6% zo$yFtzF0D6&a(p{wPX_zB5O0&f1)cCQ2yBJm;Fceqaju#WM2oLubstcc3mOkC7!nr z%aO=}dusZwi#Kn>rfxx)MD0(~sP*sMAgd+G36R(nJ&`s~pwqlEGXdMAl2}uLX_Hv* z_Q=`G$Zq9wUb7U+B8&eoX{tqM5Lfb7UzuVp9SrYuxTO(%0t!f9Xs!MG;g{gp^M$`SZeHl$W=)!cA^-#=DYFi9 z$h&MKuU|s7lJl;0E27-Pr!eTJBZ@hov<#v$!d})g%d{OOeILEg6>9V13a@FMF>c+| z4SfFzqUPe+-XBN!)KnQMv9Vb6L0g6Rnzf>3;}xImyVblnAIXjh`BvqE=E8L(fXVd_ zU|G*I^P81$#^-Q_v?~}>=`A2DBA-jtAN}yRCD)m;!3rpVWXBAv6RP41h#S>^$|9NoyshF)7Oil--duS4-anu59eDMoPS}GN6=xZ~ z{}QDRSM!7Qnedn#K%aY4zym|`G{_z3`gZfK zuQoLdF`T9CG5V=l;C?I^#>?auMtMS#;l$Z4n{Da`x``9dE>1uOI@#n7mGatnFH1L_ z(k|9p?`Rt^{AT6y7zk-VQqoi&7d28@ z&yeu%{$^>G7%b_tCJoTK5?>t?z?|n(NB1`JwjR0 zw){nbgP}beGYZvpDmV7$ID#+jWIouOQF*i}hv;T7>RoGk5I>t+x~&o&A(-HKajxBP zKs40RJC!eRuI4K&6+Ger%z^gEt-lwg2>!Zr$@jtoS-)K2f&JfaLtzZm8n%~TIo+yY zsmM$djY0F1PTd#aKF6JlPd-V)IwuuGCP}Hl zNsHnSyUXxmT)O98!+Gsq&tj(;26*ujBPCAjeK_DsiY)IXCLSR5jYHGIVG*Gv2Ng9G zmUF(Z(H7|FE&nwqm2~>Edt;DDLx^MXF~~}08W`#^A2~>)^e29PlAT~6Z)y!S1C|QU zUg@VQsQ5KBrpJ3qcj^c^DO#ETj+X{AD|?6F2RAvZ2)l3TiO3|3{uv}u2&TyexqA_A z`o8J~t{eg;B~UlRojtTLm$EGHMfFcaoUO^Xc^`wn;|uwG_b==t7{@srJij{y(=28u zMEKf&?Et0c)X*m;B-?(#(d)^1uH4;P_K^oC9qG^3UTE2;9t)cx{dtc$Qeb-6D!r#L zCg8bnf!jm(iNk+@Boxs$$C$CVVN)#fS+Wc}AypfD+Ymo?|WbQKo`t5&j9Mrdqtpww)W|S zlQNijeipJPdQ_V*muzDN56e*qjF7E%y>7t0bnmczhUpeXPb(1cUh=5{THks9504B7 z_Le*0GeZE@dRyp?IK9lTmaA@z^%)xxr#lfyT!t%_V|tT6#e^HaFRoHY%AWzg zmX&m5Hlre*f8gn*6e7(5wG-6D|6&_XDC9qDYzuaU7MW9wNVW*^w3W z)xsoEtXoLXFOEU~ZAni?u+{*R>6xMb5+_LCYY!Db>GC4k^MLhg*83WDbQ~~oLX_17 ztdYOQU1tz1`_@HggjgEInwbo@5__RVag9ShG~X>FN?gX=v=wp@C!E7P+pKDA<8{L2K~>1dQ)>h*NwDu&BZtV0GR{B)zMv^P7U$-5PDO7 zYo(gG8$m~=%nImn1~=3o4qmrL#%-1}(VemP=gqq2FVu`_sdW>Y0g7RXCD-DmXc#2B zaDSC%^SK$l;mCBt-rg=1|0B_+&1`DGR2TC2@D-@hrQ^ks^)$+U{M=%;H37|#$D>@= zX&k*hG29$lVIUvnre>acphS9O>}%eD(Y!Sf4doZzTVy+>qS2Lm@NzOJDcJMLciQj1 zK@p`I&xqY$ae+fAi2ref$$74wP{9@XVfPea9f++X30)pF^g5Ty4?Jah@k-yG>3O`S zs4MepkCW%IFTjms*__W;y#1o3T8utb6Ya-^s9wL?b6hXK5+$hmjf)4uUA1tc+J$dh zT_;~Y!F(p6o4c8#qp>eUvYURVa)*5a4s-|0jH?K2ra`oqP?nsz8n|FcFGv49OOPp8 zx2T>XFms3itI6Em3&`Ej>%PD+t?av^+ugW-Zh7H?NNr(l9|f|HVxwi#x6V(L3Bck`|<>85o0s^I+ zn)u!;@pS{FK1@moZZ0tNH60EzD25(%#jg~Wp-=9l4zjFyEVO?7C67FR2|q*|dNt(k zp&P#C+Q)HQ4b1BT!R5X|jpC`1M>BjEBRrWGg5Y%2l>K#XU}gykjuO=oqN7W%!YC?QCB?jVi0+#Y=}BC&Gn957r2Lp0yFez>_mb$7f6w*g zlmRG2UpefAsD`=K*o$XBBL9yVky6JP=JdefYBbWImvVKcl0dc!+P9Ma^Bp0WE%LZ! zXwCwn=JONJZ0hwS)@)P8(M<))ImS+N(%#(D*ph5xO!;&&1flHwBt)&K)dFtm8;U=hCoS4fl8ruS{X zgSfG%Qbo{R*^#0zAWm%Oe$L*^0MWBgM=(WR4u$M&5nZFe`h zL`g-@M#(9<6A-$=_&W3c8%_pB%Ew4UOm2_w=(G)DfJqq-1IaR$x-wraQgMfBM5iE zy;>?gHhb)Gv;{cbYkR_^6x8L7< zmku{3QD^J-Jw>N^nq{%g44q9eIT1H*Hpu=OomfAY)>l?X;Cx7;6hd4iV*`6jx$MPx z3F&=WV?!gD+7STFrfrVdy+ZcNw7_b;Z=yiBX|K8#x%I7lsb&k;VbLkjq&=1*xiZWn zwk?DO+M=`sJb&a8clz%5Fu%%b3y3~0nxI8%{R*@xJ9#c4gB8Eg^ktQW+OFyjt7*br zRPOH<-d&!!-#>0HlzB~Ex_DQ}I{@WYG(;oLcOT)TXacW_d!be$@!#%IMk}iITnj8G z03{M-u1@0nI-0$@yAy&_BsK`uN_+W;_u>Z&1HEc)zgXG%|6DhieZ4`CQjKgmBN%de z^vD=&Me_q{o@T?;Y5O?8<{<2B*bH?T2RWBj>BVc-P`I>gk{Nv^0*uu!D{If;KyNBv z5x-~i0Oqq{SoMwcUQD0bPpY`45^|P3hGEWHs3q(iDeC$7dA}>}w=WIrRjZvbHS-8% z|5Vsj&z1w*w1dl23;T4MfuuwNgwGa`9vBO?yzRzdfG{juVCiLJ@Tl8I zZN^HW(k^W&?3EmnSbH&6+w?q1l8v`EqKg@^Gx>JBVSnj!Mta^F)3C~;5YpeYYSKlg zMU){js2&8?JB*c$sgWlWCoIvz=pVgh?1?Qd%_~YA?O}8*yN5+kKwN<5?Tb`Bqqh^R z9u%&_T9FjU&|Ag6@)Wz>-Qzaf-N13?RH28BX-{|tllF};!(R4`QAl1_e-%Y%CMlhy zG!sp(`}ymmN+#K^_U(4@L`Lm{dr;z$e-%28H#PflylGaBG35n%29?mk{Be2kp){>n z%&zl8j08u;P=)D_b>YQKp{2=z++F>gyhK*QPwjJ&1iW`L)}h_1eX&Q{$KEIGN&$X# z;acG$5yRSoRm0E%R8DcxW0~VNQbF)dUwxYvF`+o#kVBzc*1)4SP^#Vg>FdW1j{NBL zj{e(`etV$xzVo*7}52OZpp1$1kIzxbT8 zheDuUP@(t!iJmvk4VT{_Ab#hSqgRQc7kkTR?6?U{?YOa?@{WZ-wq zcu>z04y{{=!guQ1+1f^q<#)fR)lyWWgB5W^6d%9i57+`*uBdLhd1@4)q!PP852oLi zPx(0J(O0`O-x!Y53l(Y7aZTg|(rjcWdP}C1$3kTYoZeZLVa{Qh_>$G0*IAq@Zrs>O3IPOL)0_dj7NM4i8UB}|tm?}LV z#bN5C+qnbw@J#Q3_h>6R8tHinjiN%1{KeNGxlFY$V{k>{cQYA1S)c*9*Hjolt&vFr zBR~?6x17s8eKWHFDr16U*R%*>v_9yC5SnwU?D_?)-|$OWmsNf+eQ10+tUeiKq7IY6 zJo<+~^!NDlaYcyQ@40rCE8uG`_0G!nFz+Ksp8-{Gqe1@Sw^gu7u9YB$8OQX6-`*(V z8_U-T^z6iY*99`*i}Usc#1a$rS~+xp13$$z3hTD4HfHeyc(d#uKS(=W z@$>TaQ44xL9F9G+IB8nm$LO^(-NibG>%-J}>;aiG2a%Sb1=xf%tq`7H`^mlas@ftO zp4#p?l-8q^M;QT|Ik0qvb)2hQim`JB4kqRmC)ynaCGz@72&>L&`u#ocZHo`Q+9dU$ z{FPES?Qj=lZDp%d%|{nFTYM1k55p!r_t1guUKK6A5(i z2vOf1j#tYa_!YEU@=n1;9U6SHaK`_!L(gZrCs6h&=?gliiHMJSwR{#?5~>ai>0XPL z$f>8%X7CQlE~Ciq^Z#{T;X9E$nE^0Qy$Ndr)fgB!RG(fRxN*^YH$G(e$x!P24$IFZJzDAYIQ-bqbSjtRWQ+Y!^tOA+n84CG zdYd**8VPS#nY2pADNjaqcvyFHAuLnw=vj+2BB8llgy$N}@^acm6jX*0*4;nhBJ;-? z)`Q!fH_gFwD4Z(bJ7i9Z%9wtF~ioxxu$a6lJ`ZO0yg+cIuudh|EhokK_e|W)h;a6S1OS&PT%&1z(JM%;85wT|Om^w^-VuLxI(VVD%ZEechljdNlvmtu$C&71}uA1h1gZXoq4KQY& zLVA&NBxQ(qt>@kNsQ@?6hlJzxG-KBDKXCzh&>Q zg7{?=Y43r%Ilb>6sW_R0&x70*78I>lw?O#$hQIRWq}cQfKlK1yi1*y*B>?`$YX7UD zX;)CHPx`-jT7uT}ChR*?SCgF>XI_A1!~Rby#X29fJ!!X>QL0Uww|}?hw`+0}fl7Kq z;H&O)%Y6ZO4C4{XUn}6&-x`EbLh5GvjxqR)E26sAZ|16$RZ2w`x|zvDRp|yKK6Zn` zYAd`?IZ_lq-i=>-KMu13mTp1hpDFmS9YQaahjWs)U4clpb@GVZ&ZQ{uo`qQ>N~xQ-$6g+R@h7qP!yc)>$!N%vC``&JXE4Gszt@e-51Wtf6cDQL7#K z)O~B^4@}v0TR{*iUgp7XZ`p#_dZ%k;mL5!6U#YQ3A@DAZI?i`tfQmO$*c;IS&++5l z?J!g6S{BlL}T8Qe(0B6;=4u(zy8X-HrH>BFv zZ*uJ&7CFR8rW`L`JqZtjd_=EN(s|+-%8)`AcXcmgmGvb!F6!#+*>}fFc_Vm4r_jnQ zRNs@;Vcm8SSIA&B59e-+qvENDmo!{Vs7Zo1#j8=G)$-&Uct?fsYm0~it5Xkv-3nv! z!A61xL^a+TqZns2MkK!y7f|v?@`aN}nazFsT5Vj6EC!gcwQMx>day^Bm&hr3EvCJgrWZwa%fkfg z>3r{n0lx>c3Y|qTB$kX|6Bc**a=N{&%C3C?w|1U!M*8%AoTkxTrGFH^{*L&m z81E7G8>M0JSo50u$PC+CW*y1V1aB1L9^G)Ygb(h>x(B-|P$0pDD^7z9;Fmym^t=udR=Cnd9-%!gP&JqmL=SxJ@_G_8gMW_MXBTJxXnics88ZDYbh3n4Q?C zAX5CjmB{O`1McKo!~>M1p{Bd_`VuF@H>u$@=6SW85GEx3T`MrG6t3LbKXr?FTcFBc zOOhDM0#^yh%9CXJTGCTI>#nzzYBSgwDt<-$*&8dZ5(9vmaAZ}H3Z?K4Ef}#5q{nU# z{!sMSBpQWkTFmL2tt{3Dk5UpKfdjT>bJe;$8CpI$8TN+(sFvcuZvLxy!TAdG1J=Kn zeV%arREzVQCb{wZjFLdpI3H?S-4s%pe;Y+4in=zS=o>+Ce!-_8Fn?a^q*=PCjm6vc z9X;IAu9z_lnPwf39aEF+!V~AkS*pKk1PFqg^iFudgjgF z%@uwF#e2|1xg9F_!p)Lic810tzS|P8O2p(Gaw>Yl{hoX4@5fMFspEDEAQ$lHP{Hp; zb?m9Vak-#pa7OIixU-WRridBrU9v3Ot;E(ch(6pMq%MEzW~?DK*Y{}~FAA$2I~Z+s zQ2ypvPbuhFi(M<;iNgKP!_dKaV1Nrg4fcCMG3IvU~mP_?| zc^>9^0{)YVf^8#a1S*cr2;6HI;abaTP40g}q8>-xW3YDJC zz1(bC#|Ib!PCncH*MamnFUILex#_a0xb-dw)UQ2;RomovOmx}VjM^o-Te{-mf6gsKJ7uuHt$h&{zt2j}TTqV|EM%F4c- zsz!x;__F2{=6N1!9pTg&4mnpCz2iqW%#)w?ca?)#cL2t3@<#Tg!BPKMrxkp2#)~F* zFL>=Ea~C_{{^S;V3!Smr{Orp~>-P}{SwLCfH21%azo#E+&~Jzc3Jd8*EByQOa)F?o z(?^5R?U0+FO+Ly<(k7hd9}|Qr+y4+G?#KjtfVc zvnNA_9nqw#%n~6$3ua3KM_sUxQjNSZ5RA5|aul+s@>-$)Tyl47_x`uboY(b}XjG`^ znEW(q%Tkh8)DOS8o2xW@D_;+6C(A778~lf&;1b%>gq3?N=V(GQr|ZCj;LU@;&L_s* zv3A^%_`)YhALxFo)H17kkVn*3k5&1TW*CPt9>nJt@fm|@UdMTk^M=hrMZ~YN>IlW6 zx=ic7q&}oQFyMO9d~8YwQLg7Su!|!Y|b6ORV}$@g~PVE&3LtxI8-q+Ti@9tW+ieuBPL9Z6J}VC<3?|@D@y-B z-5p4!$|w>nGJ}DbL^oMiULIFNCBg^0E?%%!n`cgDg}c~^-_p2d|A@Xra#tf#O+;K; zlm%8-59Pj*D*DnGgQM>W3*OaV&$wp3Tjjh*xiY%lpKz5#5DE9e%?I|n|7rqO!3WKf z7rFj~oPYkBGs;qE6)m5K0{@AKOliuhrJSKaaV$=*d|9TSPt542D6j`IMDPpB^KK%y zS;VnGg(g(HZPCJ+xcQFx)XTmj*6(;E)*|c5{;-;_vz{CxmDA~~PaLH$2y7W&aC2H) zVE(wGzRLpv?I?2q^B4L}<0~Jiu_X2iSJ;037T81ayTfvs?3Vc=D1}6Lh(qqNj(MHF zfE)KmCZ>;T!bZPqLiz`_z$C+F7$tPrrjw2U2TQ8X(;(T1M@zvUXM%z!Uinc7?~D)- z&m5~^i7HPd-&_KvQ`~x5LM1DIQR8+A=|bq|B|Hl@dExpHA7#Ykg+QKIT5FRT$07){84+`65=!y~6(O%(a1W9E#c+vHjvQLNIR=><<20ErhTn0-jfY z2rfQf1ki2Oiygi{X5CUnkVwt!ui!m843OzMv>9dlM1R_S4ewBlQq`xEK3FpGBXsR~ z0rXnks+93(?@hO{eD)y`9VE; z$RU6?{x7x?q=5cT1Nr=#8T41DM(F2&$?*w3MUP$JiSmzEWkLe6T!&u+Us5=-vtOFp zl-#-6_=`6R{F;mUge})LRt{scHJDvd2OHj|+!)^}G^}LsrP<<^Jey7&H#dVC+_eZd zmkCmI$_CgHMJlT##gBY*Mb>#0hoHi-MpNm^e#8FTM5X8aXCRk`dYs_Q0n1p$GoqIL zI?$ScR;ARTu$sbsst#C80b%1taYD* zZItl)9*>X`K*U_lpBKHA*QEBdf^;Mp3JK=nYp3#1J4AePtV%Ujwy{B0Vj`bkb0*ld zJV4=x(WQD|MVpe_77J82N1?(i=|K z7|V||ZJli^P^USOG9!@V*-3hkFV5J7wCvgYy;pW74 zE*kGj`DwkjU+o!>>50kn4y^QU0^HheXnd}yP&S=X#T)=o%xzC;%+L${>cH~2MV?gB zkBg9B6tz#c@E+oXX*BCL=jh0ohxMdyR&o8^G8}LU87$#*bAl;u^*{*P$10Z?ocx==9aJYnv|*E5O3)q+^|uEm@Pq@Eyl{ zj7{kWiUtB*&yB?Kvf6wP9D}-=Z9<7XW&kujEjfOp2?cpxj%9%R`&ID$&l3QDY94TI zW~@^YV{`=&*xP&18<)vIwSoxCqC=PSA04{@9&&^@|&j}(*?$aX95>4=`_VA5ql zbi^Rv9Q8fYOuBW)RLx)*V%Mdy=!mW1iPJkbv70SLDE?8|pd(`7<+}elpDnWlu9ju+ zx@RY_5t*QrqMW~#7pnKGWidu-aRysm$7#9$AYhR#CEUk%-~4s+!|QqXjE~POJKlgp zJ=NKBBS}E{j%UM8rxK2N6?td9_+R_dZ7($cymvB6%j?VM%QaxHtmpB#a{)LTr56Cr zCex2N^D|EKTrfF^xOT{Hi7V;BLu{*q(Q9HkjJJM6rNi<|*f7@fX1Le?H@UW@(Yd@z{vC zpTVw6^6h4v^nbO&I(k4a0WH#YwpMB$GvF*xBBkV_k%KsDnmxw;ETJuPQcReBES(v` zqF?3fy7F_^{fsbg!kifmdM>}WfUER!HGxnd9?OyRWh*$C)g6Qlp zO>g^vQu9dZ@>~SVYQ@>!>qR=*Ukb_Ew3+nURucspDVjFeo9?bSO70F+5 zSYdiqCoaCx^>H#qmr*4oH9HNqi6ZnPW|-ss8Lx9L|19R61;Lrii92i(5O+(whlTCy zTn%Yw!zoEFTvtWh#yzDXRQ$9|yC7zxQ`y@Wo~$=5EYeK1I4tPAudY(YV=D&C-*eh5 z#zlj6Y9?pfC}yyy6kTi4yoLjdgR1{tSCzpCNi^#}9(@LTzi0L6>9KzdDSlk8e&CM* zY*nm;^8IAEDiUkz7u%_ZL3SoZrQ`OKcgCUvkLa#ciQ7`TF*%uZ#R}6G?Q6<+0LrdgLbIx!e&>vMG(bADxvb^JqKW!zF zG+1L1Xrl_(}X1zx>l4qgH}J_zt4e=ljMuQ zOCrdbIn>{J5)s;C!1=tfY~oDkxb^^u3*KEj-3}$>153rko;fOM*srVcaRv0TX7S6qbNV8OsNhZT<9KLFUMuAvm({OxDRQs{ z4uorxh`fCA86Yz8Pv=jh2Y3wQalq;lQc%SM<7Iw@varD14S-vAtd}P33Rltdiw(VIa7AG z^11by*Y(WqrcB7^-+P@UxG%C>Aq#;upM=dRkHeXIyZjf@lM7ga`JY7M;rz66rrYXn zyZXnl%yzK{H3$9D4{B)c<4WbwyWq`;$ILWdY5EDg7cKC z5;&HKTZ_0(N}MB&RKsR94YlN}o94t6_1TCagn@*$9&9sb`de#Fw^utlP0(IBzMaWL z$e)nA^+M(;pn@Xh0-R=A+rehEmKNwNKG!5q0Y2slwlkzON%FX@DOCOLgx0SqN@f{6 z9q`6Pl$A@whKMr8^#!+}kDc-lUWqybCQvcdsfXvS7sDw1yU_y|llyyW7BmF>fc{!* zxHoN=rrfCXZ-WE@$W;c+aqlxU2lAb{~|JD~OiFw7}2N+!SV2R%ID8P1e-TyLT zd;utsvIJsN!X+tglKUs`lQY0hRXzdY)?S&)4t1OQpkOO)_hsvJ`@F{`eN}qEfNT3; z62_i|ywkRlwl*&^32qm!|G%vstPtH}12fKAcJ$Gd5n=xeqcRi}QXS5e?>YxD@otq8 zm3QIOhnyyCWQXrsQ%T#c>M7F~*&RT^Q@vN1rpn+(Jq8ix2l<}%MO%PS6ldCHr9I^2 zpnEQs7H@iW&TgmurUa;7HssuZIR2eaDFYT|8O?E&>*7}WKK<3fS8tx;l`Kc;khGM3 zs^LCcgekY}Tc%XD6k_Q7C4d+0F2b5Rk`cGT$iAn6H-fpuCZ|p!InIk8 ziuqY)37PxgnY*@rI0o5sGxDrmIBdRHR($KSa6qo!MbvW=4Bs(XTTaiXnY>TN54I9{ zMUGTNc+FbYn9wdM1+-9KS-eu+L>g4QT*>gxcS$OFtMPz;HCB-k$G$1)6-a)xR0(Sm z0qqQ?a9!TMmDt7Tl|I4RmHm2X7%l|xqoUZ#+PdLfvDS(@Y6l~;Y?-V$vjsDR2ARjM zuREE(e}`1U){F02lt)!xir2s0gqfl66`1S{owFs(uk;l~=X7cao6(I>WxfU64b|T{ z61;ZhND30W*%3+#0%PmvS4!UVN3!yIQhL7v3vO2k;BbUrOSexg!c1@ z#e6z>y|ZG(o@o+j9Bx!y;B`9yDv)Z=WB@eFD;NcJ-WkmWvSg-*kWf{F z`SDi-h=}z^>mAB%K z@{lQGD-}_J&5Y}i$a@Rt--TGJDiWjETW_d$D+53$(row&`Hr4-r78}7&WJ+O>>Tp5 zeXy_+(}F;*8_D@R_IdiltRSu&oRPxm#dsG%U$m$HrH%bD=ua#X6Yn%$!6q%R zeq1L}SMsXaY~wH-^QYZS)mh*Q54LH#p-5Ux1bI^lkc3L-3eFzDw@%U`yJJ@qt#L~a z0TX@JZdk`B*^GD8zbm(~@vySHlY)@DIF%NYGy_@`T&4R11_w&)#3&$v)pjOT8hPP= zaA_E$kQj1^6in-OhsMk#6rS?IT`MVcT10glL{RJ_G3ml^YQWuGu1ABNGZ-SId$Ji0 z^pP4?9hwoNOSWxyQMQ{lRk5erRNtHK3n{9rO;$WjubA($7U3r~CCWS}!zl?3plY3F zGx>i+pt*z@)fpo>AO#ikoANJF<(TmAojn7mcOnbC`|=)OrNsuy1|rGde5l3?d;7I_ z$9c89>M>PWl9EfEj2K`Bof7nF6oi}Tv&1qc%#r-X(7dGt%N#mxD2hS}5|Qa$w9kab zkQ$w01FI5RI0)#L?v_MzgrCc)YV#xe*w|3J4}Vs&*6Y9In#z*Zswi=&8d1g}GcP$Nb z`$U@2`QwY(75v8c2RYmQw%cSSBUqK)U$;AdSdWT;!on7Nr+eL4)EhDPcZ%hGI&Eh- z9wQvcTl2TH6&;onukr0&YZivp2BXavhoq2qmw(?7z)J4;*exvS+B4D^rzFQD4N zR=|>8<3F<>iroT~uelg+PZH?vO(TeScNHB>`pVzUGrboM^R`ThqWGUu^gM{+OEE_U z^0XE_kbKAtajglO%`P3ALQJXSY?q+4n2`8Dw$J-#C`79PS@3pMH*`KYZ7{t#@51{@ zR7K2s4Y=x%GvI=JXSofToXqx=-T0h}3r{&EFImeVq|Ox)dX(f)BD8YB#C$)D*mE|T zxn>SEH;N3-UHwRRuab>tfY(buoJwCVOm;C5tuEij7 zZ?J_!46lw5RZa8TU0x%Bzq%JV?B#4wZEmOExNQO;s{StVd58|6y|B3`eN$AOpOW&_ zp3wZ!dajSopp^T7Zw8Y6?oXZYb4AJbc0pIzqztpZV;_#w~ z-K0u9h^@Pf1m&%KO?a_z0@~1} z>fnr_kIEgGaFy3Eg98$q*spB*Hn20T%B6m?-(wfp`fTeszE{79yZnGJQx$hN8}<*N zV&njgFOLB)ck6G{tjX@%SBxK+?mO6Il7e}p`k)B1aZ0O8W^BpF`XymyvVM;^J>=<} z7V%W`lCunvKh&f~u}M&1xG{_&g&uMwa~6L!fSNQ}j(y%qb_Kx0CI1y~ozBSENjy+MqJ zvxGRuG$Oz#^Yh^U!W3`I7e3`#VGa&b&`E7+qZn>Rnu5y)Rbj+?~y(QRsy(*Y% zq8;BTNYj7J*kM}1q)rAWN5lWR>8IBq5O#FCUQO%g3!=iV$cI5eyWD_^3XT2NIhAPa zrOSRSrv}{9V7E`=TSAw^VET!0_p}UIAM+f`%Ae50hca3p-q||%q|};Ru%W%brXie0 zg2XqDp>xhnO-$^^m9-7*UYVipM+xz>QZ*BG6PZ|LgkU5S;@eHWu`%nC0Wuem?`y3Q z?-A}H)gD5KyLiv}q3J)wcLJ#rcS4BX zQ`O+wBtPn$qA*Z}vkSBw_fs$K8Kj{+*>p@#9Y|kM1IL?$$=sbcZIL=Dw~J=1fNS3t zX!-}P&zbPo>c*@&7l^s{LSN|$h~HiOs2TR)`l^%U z;i`H(WLCYv=gP!$jLc?}x?7MlQjzMkDg6f82l?zOf^KfA}<-yLml}0J~N*4=! z;rNQgkAH zr<%7CmU>SU$g!H-w)cl{+2ae-i3cMb5WjT0%7Yr~zr}12PNzpO=~(6#Pfg5|{{2z$ zgTJguVl>nsklj)}2H*sSw%DFTjf4Xo93e7zxQm4bsc$jZw*(P7AaX@Ro;T*AM3FfxTNB;Y&u^{%WAn4aa zWNc&&~$cG62@Z*_+<= znJ~+PeLaE-dU(J+e8ckcJle_9$&uJ2qVf%AH-RU0bT?HIAa zu^_eeP(V69SZD?>Nx)FnU`3)JrpL~Uzqfr2VQP)3l-YV4bV`31^G?;^Sh;P-d$QWX z=;{#G3{G&_8}90W?3q&>C63)bW(Ng`81Tj1z1F68n}@7Q?RF=iMV%hJpDkx4&LHp! z2PMybFSldIVTNr)M~{caGl)e>#Y`McO}37)?f0FdBT1ObUOUVuT~(S zXEIS#@VJOZSJgf((vj2n+iO&v@sDZ^r#CXmsmPvCoaK|E*e2n z085ZPQL8N8InMfUUKB=044R$F0ik~>H(O5>>Q57M8D3?ig)ov&ghm}^{SG9B*aG`< z^*+boAbM}D^x!$i#$D)8?E=@$h|RF(1-5&icDe5~54Sq0h=sOBjc_aLAl+OQMapz2 zq#s)vJj$DWrj1jo&GK?IS^_KSb3?d9Hj|K>H#Y0G=et?GY13c&PHZEsaE z?@0r$cbxDXB6Fqf9=~Hm;K^l6Zt&@Bu&u*$tGzoZW&jhLqu^0fG}Q>>IjYpowMyxt zyPb7fDQPZ^Vl9(hf~BT2RJ(Cq&;k}HNPdam+yD7LOq~OFW>L4SW7|%r!;Wot$LiR& zZQDu5wr$(C`NrlO`{q06-gE94`yZ^aYpgYARXvukbQmft=LZ3>!vux#48Ux51LbXT zVlgsve;(35Y)(DV==V_;M&OcMie6Z$yL6k>;JL9mC8wDA&*#;hqepKG+ITDXhiPL2e&3i>EeA5}cm~6BhO7xJ2 zhBqH#;aTb-j$s`LyMStj00NOj&&>Fq>|&j!13VV+Xx4V(Qz<&Q;(v1)nI1o|p$dAg zLDP=QY6Nt-5X8^*GRBJpZ>ei&^}4^>;v4deTJ^l(gNB55{BMjifvQR1@`|$5hDsq6 z)Vqv*`VB{!yLk7jZ|F8+{m+yN$O955I$Yeb2026clWy|B^cn-^VgW&(S8R}93uc0Pm_+cTZ{-ZbxVK*tn(q5h;i|hVY+F)(m^M> zYMj8_d71T~6dL$LfCyaH-u-|d)oRym{2DK6vt%w zMqZGuH^FP##%N0y-T@s#I+p|@Fesm1NRoGNRi!bHGeUV-uUN@T=u>&zFZu4Sw-f|U zTIO4dDLW%mGSFYk4qS1;NqLnSFHEf+n$ktP>WC|D5ohybO6HgB&`g_`OuMnFhRMPQfCg3aG zPT-60ghf@ci?b+3JuXhIE?71%p z-5HwJ!`e;4w!MDTgA}Zr_3aVEK2+r$)4g*gWR{BPLU)(0W}VK$dydB&pF^hpJl?kb zO>}N#N|YqqJngZ=cz!Gwi6Q?G3BxS~1wVy};#Gq7N3Iyl;Ah-ksOD|Y=nlpD@-L>R zI2g|W>Y;=9s0NnWy~5N)MALu$NuRWVAMvj`YF~B@l46>ck11qZ7HJS#rx>^iZwqJM zbGU;gBXKh$Pb2_$)07#$ZPM9Te&XVpbnS6|+I zud!%GsoVa%ljvuXY!F?PE#&#m&%ZO;lXA8)+1;9a+?Nk|JQCP_{FZs7bLr2FBWCfP z=*|@r#AAp}G+HV~eWXcCkr$0l`1SNvXxrM!&f4Xa&nvA+zmk%D@+Q;{h7Yrca+@Mf zU)_OsU3{iK)0USS*w@B!re&1e>Pk1T3o|@LHa1V~AsbU)U5tqMR*FTBl|J(rE&T_d z@y^66EB2{2O^0_Wv^18PPCwae;o7lb%4F%+Und^R8yJ8|3Rw^wM9Cv66Je`lE2R@K zDQ=}dQv>J78PsmkK_l33i1-L{3fzvjw%ms-_$Ue&aKx-@DQ`Cw9l6z-o_^l)UX{ps zm^BS-ag0i0u`?~mUw>EqIJ^$p_H>2nmP?DZ=^>}RRGk4+5fu>KTpy=0`B%fx_%juu zucbb+Nn&JFh#vZKFw3CW7^8PikxWFSMBxz-*iZ*JH%DT&(>w3ddZ(d747jmMvTI*V zL+d>oqrT++KJvYbljGgBMwo+jxBfqxZ8wM_V)f~LWlx6_;9MQjzwJ}G_GLSFJ-Cza zrh|GT(0{-^jvLlQ(t0xH8s;pf9zikGesLlp8uLj*6c&rdc<0ZLq6LeCKj*CW1F{Y{ zo@2ZvFD50@?Ua@;=c1XE)In!4^D4WUttEVV&};z`8t3$~*mE(i%w`olv7=U(=8w*| z5r@n*6a-_oyJ4VJ{2;P!PP`I8KZu4Fgq^HCT?UYlo)?Ip_mq zY-gA=)AR#LvTOr35IoQ^VDR&7G`NONFEU8G!fU75T!j7YGNG5^;~a6a6xxUp#R*N*mpI&dgR@AlNu4TtQ9r@iGmAu zgPRG&LFe^C7deptvYq!O-4_vQ@*(#YGFIvyAqH%DheJA&8-YGdau2;#;V{$vt^F`c z4U8~)ben(P|Nrn7ls(sC2PymyG{1FE%&49=H4R5372GSirYcBS= z)wtSBZ@Z0{m*%2CTY#*n^V?9(A-mm4kQjeKt)BifbI5PRY;WvCyN)?6(IVmEMd}sh z=3m#;Atx+K&dm?Lq=W$QT(t{ScD=t~E({-%Qd^~C1!j8(yH&{@xBFk?`5*xu5RU4q zA+*fi`o0xiFkDRs;ElFHudLbVHy>EMf!z8WBq_`HO4Kk(7L8!y3f3BDVyL4*>cNQL zTlm($#VJ_GoxPY3lFMr!zC_<#%=ihZs(FKIA>vgpQNFWOHN23aAnmMsG5PiQZi7PK ztcZhH!nBxzcmXf$cfNq)9M6qdFPo{*DDae{FUAv<5{vwfXL(ds`$5^!>(pmyN9tFVH3escygS(FF08@o!y%r&cBe7!BXWG7W$DC|D zo0jkrMe1BQaV0P0KP}r{n_VdQ87a>16=b(?S=fY#P0> zx{>yR3)Hm%-+QPj;Z;Awj2U|V8h$%+x70(CPon2SS4~OxTz*b~z=MN(b!d*vVVIpa zZ%c@}p_tj27)1DOezm@#{KB%$xSM)6>dStAxx;pl8Q`WaF7oFvY{8MjgjqG$MP*rleeZA?*OacX_nb{hAbD5X6&Nm_I%CcF=hqIV z8$G{old1=}Hw}G1Juk@rs+=D>a+s<)CY8@N^OignxJQHMM(g4cwRjg2+2F>rGEkDq z9RIiWz(JBE6oLqIX@&Jomh+T#m3~GKOC@ATDkq~gn?`q#VPHzGwflCIKz;i_JRNe2 ztb8{j1z2+df()6lC$({X1S3sBLA?IjYt{;h-efMS)g=V2KdZaO2UDX!wxyLgtU4A+9on@ z+;o}5k`pF+?ro;NNEf?mp2DlJzsFc{pDrZU11V3EmyCsOsobsMRjMYh@!ABa$aqj= zwTzCCK(4B?xD7cWFsPq5hn=V+_cz;LWZtsfdCIk!=vud)nfm)rG}Hm{S`N6Fc>bNn z#fG9B3+mTACKo98s&2(&a?_s>4k!kz_CY1$ImD&+2R=}&Jhw;}emxl`RC@tQ_9TNr z%?WgNa;<11{A=Dq%1w{3Qbnrs2O`vX5YllH^re#t(lh)pJ*lOL5--1Ni5>|20Vz#y zPoX~drkxV=Ak|XLdahb?X~lEVJN}C(OhRA_o7Qw2QlxKHumdM=nN$&<_Adef2{8YF ze;{pt!*=X35?^|MmqQu5-&Ku#w*>gUQSxH}M5jgYgCc5lRO6U$b7kxlpN_835Z%a6 z$qa>mf^Fu(L)%ZcejKgrPUO}Xel;tr6ZILMA=g$F`C#4T2tZF>6F&O#xU7#uw&6$X z-3m%8`K$P#;y=hl1_@^gLm_E5)#(=DjlkK)!?W)Ia2{lDvLvK+445`<>(8hOQ*o~PGvy~<>|{`T8!{xvXL5Dq9Iq@}zf zI*n!W8$Z~mmU+)wERkrnTOhp7a)NjZF7Gpk8cxQ7B=Cl{i5)w`1jUzijHrJuQ%V)J&N1 zu}N{YwI-62DpHK&uym(=6JQQNzWVeAF4GIV85&YDx_u>)!o0r${xQ7C)WFqwiDX-) zuzvXN*<=*!A6kr1+W42smTFw< z<@eP?}0XDnIux=ii>OpX?~2sf%?&tGvE4I-CSZ}oHI2HQ(g@<#C-;ZnS% zS=pKVCwjLQ!+Uvd1y;Bfb`_D0$Z^X0g)&v0hXk{V=bQ>b;CLk(pH;~}KJ2uk>Q-w9 zp+B1{gflukvMz2j)1)8hH_fRML0;lJ75ZXQfe@P8Qm?es<_z#(17A`(0&~r0s*DU+ zAIg_ofjnDZCr#f&&W)CMdzD!Wsjf0sVksXAtQfo`9s#<2xyVXO)}8C-UYHScpEz6dNy3~ZSYNGuo<1;-4C#JTo!B^ZW=NM{EaZ5);E!@A=X8wX zdnp3csX!Inj|6L-9?<_={q9ex)6^unCCDeIv)xr|f$Z+NwsfbQ4fB|m#NKvQr2pVL zB)@o;=~fMl0U+atJf-z)e1XO$dCF!*nKbMx10ruuH1Xf})09VA-0G@arcj7Y;Y|Cs z+85OIuCp@Lr0Z{7uclk)DG-53xX9;$Wy(t582e7~{2~J;qvHM6 zo1~MRE;9P$?_a$62>I>)sJe&R_Vf)+Evw{Rr{oiKpA}OPY#GZNIiNLDhqf#YqyTl6 z??zyZI+J-GATANwom?6FjR~cs22E6gaJfmuc={ge<5GO_=KypyvM}GYv3I&7RZY6U zY#(38sy5lzy2&_V2w9pL9q-`PPmVf=`NRX+!mL2>H#*pDHk4ISK3vtTnH1whaz~Pb z;EcCcdE{}Sn2NYG>%yZ-r1lt1@&}{<^|8WfUjz5p+(E^OMKjIFzV}aFxvSW68UD{` z-7f`~ug|jUw>XG|AKWop3a9PUUMqr+3%4#MfvLCnowi1vgC>uDNV1|+>9k`bJWQ@F z`W?z{(U@E8-Hsj#s%)#5EVf;A0yhJ`$~vsxLn$8?FU{Y$)WbK$u(C4n86X2UG*$DZ z$vubQ_I#keX7X7DJ+(fP{m-4HmzW;pSijG!4CN`T`u)_Mle@beTL7vJg^a54j*KBx zL)1UYroAn4?lx7c{Tziw;>H&J1Lq#+o5p7@qD>IdG9w ztS&6b{FK|;C!Qtn9V@HZ9mjCK-(q-OTX8Q{uxPN+y&Q63 zI+BK;uR~^wDu?(BHn2?OsTB+{@xm5NLn&$jedPJl(MSs-_#!!c#x{5p~7D> zo*{w5wq9ll-;7z{{i*g%3xv$vIjGHITCXhX*A%fQOH3et zM5hBs_?O(5W6eZO7d)6FA?QH19qK>I9Pg97@j%t9Gw+duF`n#5CrCRgFF|%@VyI+R zin5xur2U8}>IwQLg>3B(qod%T>g255qc!i`%q(H>oP}dj6;jDn;y*0dQ_eZs%ZE*} zqmJuCj={*fp5J7XT#^83vWie`e*2D{9f`IgUr9B9YX+x}pEXGUDMpK$O}w1b;QB&j zo5X`5;7jSeFq8>^V*>^SZ>k`+)NcOQgA;T-9k<-Hy0_wk^n$6#P}~mXJDf9RR^7s* z1l!X%-ynP1ZO4za^x8fg96sOYv)tQ-5}p@I>uxH+MO@!{%Vsmx;`h^mM=u;w^|B4& zC!&_)=fPI(X49tMEj$!&vjwULr#v0LPuQ16o}1jhR%zaBv_~|&5L#r|gG*czbX6~t zCqW#s*FQT@ZTd=A5jRJg_Bo9o6!n}oA{0`s2%UZQQY9n;fZF3Eb}$!}^Z$;gmF9CI z+QB)Zvu0`mo;+otyFA!> zZP&L=lO6Cp&dh+oYv-If+PEBb2tVRYEQ)07g`qsO0x&hB0IlA{(uhQ6%G` zSI)nV2JyAL%1*HKitfWpN}@zaZ|jNZ@5~Wg0TkeP{fUeMa7FJ6iG^S=zDE z*0{$wRMaS<8B@e;Hc=HBH=4+AqYxw%pl;|@R)S~t-i@fBm!Eg-WOh5G2@;H#&GMmB z_0>$mdny0+j2v`)jz(U8er)vId?gD!6$sGfvR#12oDq6=yn&Sv$YSg0-hA4-`Ut4h z@oWy?&KHv)3w~J{j_9lpZiuMn(sB?RW$eN%Yu&pbm0o8PCXktZ1vwK7SrO>M@^i)b ze-_DokbdWAvjDH2htbGA?7540t&gFt|E|!HI@&0wl=j{#ZV~Al$T=-^X)dtH*@a5SDU74-qriyNR zFLp_+|GVhGmkn{^2B=ofv*vU z2m8#rAhuXnEe?5QaLNhfzFB#$=Gai_H5d8BedNv?n;A$1;ZO#46w)vM6UCAG;DvB{hZAWj@NXnhhz(U`F?)l6BF?i#Ax@(ZLh)q$hGW4 zoTA=cRO@MlGE=6BwtG8h=y<=-^|(WT3Pg@|6+?NR@YxT{Q!OL9V$mWV$?v(k-5YTg zx_GitRD?g5hfi$~N_Q8IDBCv15OW4eDdeF;rTtDn`cJ+Yd$|;DVJ3CB0AH!TO!;$hE+n6MyB&X9e#3WP8LEi7{mednH%N6pxf zCXftYLir*n=$-6*M;ujZ9Xn4rZ*JIo1u*|1rEqFH5(M3Tsd;f=A@O_FW`WLko%~5h zr+U_mo4GHmnpBmR-~o5d8p0>`IrMsZzOC9oB_*t> zT4*}axe=8de0J?v!>gj(34oe>(SmJTqRY#i zWsk3gh^0-91?kD(XC^b!dlvi+Q#}fhmgQ-&L;!zVF?w$EtB1yhTx%OQHA{DWiIS*u zVs|I^s_a~toakZBo8#>`YSnmnE#~hVQ2j+CDsv`Cmtpg-UOHyqsopsI`M^Ia@fA0A&Plde z6{L8$D^XguoDD?^a~PAn#$eCUm4QpuJV3Q9Y)oNPJy{iAZQh?9uf#3~LYTi)GQZ-8 zW)9B^ri;8YW0NuhzL9x^5NZ!E@*g;Rks$lQ&vg-m; z`fN(>m^jeBTk^zs#dfG$xWrwi&o=Pd+qK;IZ%PjvrdNykodi^$JuM^Di>aX9%mSiX zOw9Q=@_Y~4tOF3%>H*2T38c9%#x!F}c6jnpM|pLRP-g-N`+iQ0 zCGAYvBjS(MuQh~jKY2MPy>6yFiwFpfz?~{fx7#NACS-n7l@Q*ujd}gxa>T+mp12!92o%ky1ruG5ocm8)$(zwa@m!() z;MLJ*rV2E{W8E3jgHZuom1XE!{N&>|+nsr*>iLbl(|W0Rq}9e`8&s|M>pcUIfYmZr z25Q5Ii}UK~^vKzT@}9TNfW{*vT;04F3r1x4!ZG?q)IL~wHjD0(RE|!ThP`PIaj&cZ zuo}#ytfc2T)ZF~!U{|J@iwL8OZ$$P^acIVL|C?`|a9qkz)H|MF1#K9SDM)NS6LvRg zfcJF|MSkc@J1Mk%Unj2%?}4!a)9P%&c_~i6hr&|-^;7B#03dc9v7h<&qa+;#z; zw!d$~RL7F4!MFy`Y}QK=vddIN`{o8=`;VKj?a@+8SQL+y8d)wd@ji+rZ8MP*R+1+!nD%Woa9eP{6pzI%usw&)Mcy0yeM2ln3AV+CNLiU9ZnjL1&vKTCU^>$+lx7+We>Ss4)(Q< z!DZ}os=s-*N?qy~YDythT z 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≥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