diff --git a/Makefile b/Makefile index 0df09b96..d462c1c6 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,9 @@ protoImage=$(DOCKER) run --user 0 --rm -v $(CURDIR):/workspace --workdir /worksp build: go build -o ./build/yrly . +TESTMOCKS = core/mock_chain_test.go .PHONY: test -test: +test: $(TESTMOCKS) go test -v ./... proto-gen: @@ -20,4 +21,11 @@ proto-update-deps: @echo "Updating Protobuf dependencies" $(DOCKER) run --user 0 --rm -v $(CURDIR)/proto:/workspace --workdir /workspace $(protoImageName) buf mod update -.PHONY: proto-gen proto-update-deps +$(TESTMOCKS): + go generate ./... + +pre-commit: + go mod tidy + go fmt ./... + +.PHONY: proto-gen proto-update-deps pre-commit diff --git a/chains/tendermint/query.go b/chains/tendermint/query.go index 4ddf4899..c2c5ce3c 100644 --- a/chains/tendermint/query.go +++ b/chains/tendermint/query.go @@ -102,6 +102,19 @@ func (c *Chain) queryChannel(ctx context.Context, height int64, prove bool) (cha return res, nil } +// QueryNextSequenceReceive returns a info about nextSequence +func (c *Chain) QueryNextSequenceReceive(ctx core.QueryContext) (res *chantypes.QueryNextSequenceReceiveResponse, err error) { + return c.queryNextSequenceReceive(ctx.Context(), int64(ctx.Height().GetRevisionHeight()), false) +} + +func (c *Chain) queryNextSequenceReceive(ctx context.Context, height int64, prove bool) (chanRes *chantypes.QueryNextSequenceReceiveResponse, err error) { + res, err := chanutils.QueryNextSequenceReceive(c.CLIContext(height).WithCmdContext(ctx), c.PathEnd.PortID, c.PathEnd.ChannelID, prove) + if err != nil { + return nil, err + } + return res, nil +} + // QueryClientConsensusState retrieves the latest consensus state for a client in state at a given height func (c *Chain) QueryClientConsensusState( ctx core.QueryContext, dstClientConsHeight ibcexported.Height) (*clienttypes.QueryConsensusStateResponse, error) { diff --git a/cmd/config.go b/cmd/config.go index a98d483e..96fb16bf 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -1,9 +1,9 @@ package cmd import ( + "encoding/json" "fmt" "os" - "encoding/json" "github.com/hyperledger-labs/yui-relayer/config" "github.com/spf13/cobra" diff --git a/cmd/tx.go b/cmd/tx.go index 949dc5be..0eb39e0a 100644 --- a/cmd/tx.go +++ b/cmd/tx.go @@ -457,6 +457,11 @@ func relayMsgsCmd(ctx *config.Context) *cobra.Command { return err } + err = st.ProcessTimeoutPackets(cmd.Context(), c[src], c[dst], sh, sp) // update sp + if err != nil { + return err + } + msgs := core.NewRelayMsgs() doExecuteRelaySrc := len(sp.Dst) > 0 diff --git a/core/chain.go b/core/chain.go index 7bfa1e39..0ce94aea 100644 --- a/core/chain.go +++ b/core/chain.go @@ -18,6 +18,8 @@ import ( ) // Chain represents a chain that supports sending transactions and querying the state +// +//go:generate mockgen -source=chain.go -destination=mock_chain_test.go -package core type Chain interface { // GetAddress returns the address of relayer GetAddress() (sdk.AccAddress, error) @@ -106,6 +108,9 @@ type ICS04Querier interface { // QueryChannel returns the channel associated with a channelID QueryChannel(ctx QueryContext) (chanRes *chantypes.QueryChannelResponse, err error) + // QueryNextSequenceReceive returns a info about nextSequence + QueryNextSequenceReceive(ctx QueryContext) (res *chantypes.QueryNextSequenceReceiveResponse, err error) + // QueryUnreceivedPackets returns a list of unrelayed packet commitments QueryUnreceivedPackets(ctx QueryContext, seqs []uint64) ([]uint64, error) diff --git a/core/mock_chain_test.go b/core/mock_chain_test.go new file mode 100644 index 00000000..6037c2b1 --- /dev/null +++ b/core/mock_chain_test.go @@ -0,0 +1,1346 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: chain.go +// +// Generated by this command: +// +// mockgen -source=chain.go -destination=mock_chain_test.go -package core +// + +// Package core is a generated GoMock package. +package core + +import ( + context "context" + reflect "reflect" + time "time" + + codec "github.com/cosmos/cosmos-sdk/codec" + types "github.com/cosmos/cosmos-sdk/types" + types0 "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + types1 "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + types2 "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + types3 "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + exported "github.com/cosmos/ibc-go/v8/modules/core/exported" + gomock "go.uber.org/mock/gomock" +) + +// MockChain is a mock of Chain interface. +type MockChain struct { + ctrl *gomock.Controller + recorder *MockChainMockRecorder + isgomock struct{} +} + +// MockChainMockRecorder is the mock recorder for MockChain. +type MockChainMockRecorder struct { + mock *MockChain +} + +// NewMockChain creates a new mock instance. +func NewMockChain(ctrl *gomock.Controller) *MockChain { + mock := &MockChain{ctrl: ctrl} + mock.recorder = &MockChainMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockChain) EXPECT() *MockChainMockRecorder { + return m.recorder +} + +// AverageBlockTime mocks base method. +func (m *MockChain) AverageBlockTime() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AverageBlockTime") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// AverageBlockTime indicates an expected call of AverageBlockTime. +func (mr *MockChainMockRecorder) AverageBlockTime() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AverageBlockTime", reflect.TypeOf((*MockChain)(nil).AverageBlockTime)) +} + +// ChainID mocks base method. +func (m *MockChain) ChainID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChainID") + ret0, _ := ret[0].(string) + return ret0 +} + +// ChainID indicates an expected call of ChainID. +func (mr *MockChainMockRecorder) ChainID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainID", reflect.TypeOf((*MockChain)(nil).ChainID)) +} + +// Codec mocks base method. +func (m *MockChain) Codec() codec.ProtoCodecMarshaler { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Codec") + ret0, _ := ret[0].(codec.ProtoCodecMarshaler) + return ret0 +} + +// Codec indicates an expected call of Codec. +func (mr *MockChainMockRecorder) Codec() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Codec", reflect.TypeOf((*MockChain)(nil).Codec)) +} + +// GetAddress mocks base method. +func (m *MockChain) GetAddress() (types.AccAddress, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAddress") + ret0, _ := ret[0].(types.AccAddress) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAddress indicates an expected call of GetAddress. +func (mr *MockChainMockRecorder) GetAddress() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAddress", reflect.TypeOf((*MockChain)(nil).GetAddress)) +} + +// GetMsgResult mocks base method. +func (m *MockChain) GetMsgResult(ctx context.Context, id MsgID) (MsgResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMsgResult", ctx, id) + ret0, _ := ret[0].(MsgResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetMsgResult indicates an expected call of GetMsgResult. +func (mr *MockChainMockRecorder) GetMsgResult(ctx, id any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMsgResult", reflect.TypeOf((*MockChain)(nil).GetMsgResult), ctx, id) +} + +// Init mocks base method. +func (m *MockChain) Init(homePath string, timeout time.Duration, codec codec.ProtoCodecMarshaler, debug bool) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", homePath, timeout, codec, debug) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockChainMockRecorder) Init(homePath, timeout, codec, debug any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockChain)(nil).Init), homePath, timeout, codec, debug) +} + +// LatestHeight mocks base method. +func (m *MockChain) LatestHeight(ctx context.Context) (exported.Height, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LatestHeight", ctx) + ret0, _ := ret[0].(exported.Height) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LatestHeight indicates an expected call of LatestHeight. +func (mr *MockChainMockRecorder) LatestHeight(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LatestHeight", reflect.TypeOf((*MockChain)(nil).LatestHeight), ctx) +} + +// Path mocks base method. +func (m *MockChain) Path() *PathEnd { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Path") + ret0, _ := ret[0].(*PathEnd) + return ret0 +} + +// Path indicates an expected call of Path. +func (mr *MockChainMockRecorder) Path() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Path", reflect.TypeOf((*MockChain)(nil).Path)) +} + +// QueryBalance mocks base method. +func (m *MockChain) QueryBalance(ctx QueryContext, address types.AccAddress) (types.Coins, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryBalance", ctx, address) + ret0, _ := ret[0].(types.Coins) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryBalance indicates an expected call of QueryBalance. +func (mr *MockChainMockRecorder) QueryBalance(ctx, address any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBalance", reflect.TypeOf((*MockChain)(nil).QueryBalance), ctx, address) +} + +// QueryCanTransitionToFlushComplete mocks base method. +func (m *MockChain) QueryCanTransitionToFlushComplete(ctx QueryContext) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryCanTransitionToFlushComplete", ctx) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryCanTransitionToFlushComplete indicates an expected call of QueryCanTransitionToFlushComplete. +func (mr *MockChainMockRecorder) QueryCanTransitionToFlushComplete(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryCanTransitionToFlushComplete", reflect.TypeOf((*MockChain)(nil).QueryCanTransitionToFlushComplete), ctx) +} + +// QueryChannel mocks base method. +func (m *MockChain) QueryChannel(ctx QueryContext) (*types3.QueryChannelResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannel", ctx) + ret0, _ := ret[0].(*types3.QueryChannelResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannel indicates an expected call of QueryChannel. +func (mr *MockChainMockRecorder) QueryChannel(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannel", reflect.TypeOf((*MockChain)(nil).QueryChannel), ctx) +} + +// QueryChannelUpgrade mocks base method. +func (m *MockChain) QueryChannelUpgrade(ctx QueryContext) (*types3.QueryUpgradeResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannelUpgrade", ctx) + ret0, _ := ret[0].(*types3.QueryUpgradeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannelUpgrade indicates an expected call of QueryChannelUpgrade. +func (mr *MockChainMockRecorder) QueryChannelUpgrade(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannelUpgrade", reflect.TypeOf((*MockChain)(nil).QueryChannelUpgrade), ctx) +} + +// QueryChannelUpgradeError mocks base method. +func (m *MockChain) QueryChannelUpgradeError(ctx QueryContext) (*types3.QueryUpgradeErrorResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannelUpgradeError", ctx) + ret0, _ := ret[0].(*types3.QueryUpgradeErrorResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannelUpgradeError indicates an expected call of QueryChannelUpgradeError. +func (mr *MockChainMockRecorder) QueryChannelUpgradeError(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannelUpgradeError", reflect.TypeOf((*MockChain)(nil).QueryChannelUpgradeError), ctx) +} + +// QueryClientConsensusState mocks base method. +func (m *MockChain) QueryClientConsensusState(ctx QueryContext, dstClientConsHeight exported.Height) (*types1.QueryConsensusStateResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryClientConsensusState", ctx, dstClientConsHeight) + ret0, _ := ret[0].(*types1.QueryConsensusStateResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryClientConsensusState indicates an expected call of QueryClientConsensusState. +func (mr *MockChainMockRecorder) QueryClientConsensusState(ctx, dstClientConsHeight any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryClientConsensusState", reflect.TypeOf((*MockChain)(nil).QueryClientConsensusState), ctx, dstClientConsHeight) +} + +// QueryClientState mocks base method. +func (m *MockChain) QueryClientState(ctx QueryContext) (*types1.QueryClientStateResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryClientState", ctx) + ret0, _ := ret[0].(*types1.QueryClientStateResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryClientState indicates an expected call of QueryClientState. +func (mr *MockChainMockRecorder) QueryClientState(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryClientState", reflect.TypeOf((*MockChain)(nil).QueryClientState), ctx) +} + +// QueryConnection mocks base method. +func (m *MockChain) QueryConnection(ctx QueryContext, connectionID string) (*types2.QueryConnectionResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryConnection", ctx, connectionID) + ret0, _ := ret[0].(*types2.QueryConnectionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryConnection indicates an expected call of QueryConnection. +func (mr *MockChainMockRecorder) QueryConnection(ctx, connectionID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryConnection", reflect.TypeOf((*MockChain)(nil).QueryConnection), ctx, connectionID) +} + +// QueryDenomTraces mocks base method. +func (m *MockChain) QueryDenomTraces(ctx QueryContext, offset, limit uint64) (*types0.QueryDenomTracesResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryDenomTraces", ctx, offset, limit) + ret0, _ := ret[0].(*types0.QueryDenomTracesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryDenomTraces indicates an expected call of QueryDenomTraces. +func (mr *MockChainMockRecorder) QueryDenomTraces(ctx, offset, limit any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryDenomTraces", reflect.TypeOf((*MockChain)(nil).QueryDenomTraces), ctx, offset, limit) +} + +// QueryNextSequenceReceive mocks base method. +func (m *MockChain) QueryNextSequenceReceive(ctx QueryContext) (*types3.QueryNextSequenceReceiveResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryNextSequenceReceive", ctx) + ret0, _ := ret[0].(*types3.QueryNextSequenceReceiveResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryNextSequenceReceive indicates an expected call of QueryNextSequenceReceive. +func (mr *MockChainMockRecorder) QueryNextSequenceReceive(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryNextSequenceReceive", reflect.TypeOf((*MockChain)(nil).QueryNextSequenceReceive), ctx) +} + +// QueryUnfinalizedRelayAcknowledgements mocks base method. +func (m *MockChain) QueryUnfinalizedRelayAcknowledgements(ctx QueryContext, counterparty LightClientICS04Querier) (PacketInfoList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnfinalizedRelayAcknowledgements", ctx, counterparty) + ret0, _ := ret[0].(PacketInfoList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnfinalizedRelayAcknowledgements indicates an expected call of QueryUnfinalizedRelayAcknowledgements. +func (mr *MockChainMockRecorder) QueryUnfinalizedRelayAcknowledgements(ctx, counterparty any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnfinalizedRelayAcknowledgements", reflect.TypeOf((*MockChain)(nil).QueryUnfinalizedRelayAcknowledgements), ctx, counterparty) +} + +// QueryUnfinalizedRelayPackets mocks base method. +func (m *MockChain) QueryUnfinalizedRelayPackets(ctx QueryContext, counterparty LightClientICS04Querier) (PacketInfoList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnfinalizedRelayPackets", ctx, counterparty) + ret0, _ := ret[0].(PacketInfoList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnfinalizedRelayPackets indicates an expected call of QueryUnfinalizedRelayPackets. +func (mr *MockChainMockRecorder) QueryUnfinalizedRelayPackets(ctx, counterparty any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnfinalizedRelayPackets", reflect.TypeOf((*MockChain)(nil).QueryUnfinalizedRelayPackets), ctx, counterparty) +} + +// QueryUnreceivedAcknowledgements mocks base method. +func (m *MockChain) QueryUnreceivedAcknowledgements(ctx QueryContext, seqs []uint64) ([]uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnreceivedAcknowledgements", ctx, seqs) + ret0, _ := ret[0].([]uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnreceivedAcknowledgements indicates an expected call of QueryUnreceivedAcknowledgements. +func (mr *MockChainMockRecorder) QueryUnreceivedAcknowledgements(ctx, seqs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnreceivedAcknowledgements", reflect.TypeOf((*MockChain)(nil).QueryUnreceivedAcknowledgements), ctx, seqs) +} + +// QueryUnreceivedPackets mocks base method. +func (m *MockChain) QueryUnreceivedPackets(ctx QueryContext, seqs []uint64) ([]uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnreceivedPackets", ctx, seqs) + ret0, _ := ret[0].([]uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnreceivedPackets indicates an expected call of QueryUnreceivedPackets. +func (mr *MockChainMockRecorder) QueryUnreceivedPackets(ctx, seqs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnreceivedPackets", reflect.TypeOf((*MockChain)(nil).QueryUnreceivedPackets), ctx, seqs) +} + +// RegisterMsgEventListener mocks base method. +func (m *MockChain) RegisterMsgEventListener(arg0 MsgEventListener) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RegisterMsgEventListener", arg0) +} + +// RegisterMsgEventListener indicates an expected call of RegisterMsgEventListener. +func (mr *MockChainMockRecorder) RegisterMsgEventListener(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterMsgEventListener", reflect.TypeOf((*MockChain)(nil).RegisterMsgEventListener), arg0) +} + +// SendMsgs mocks base method. +func (m *MockChain) SendMsgs(ctx context.Context, msgs []types.Msg) ([]MsgID, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendMsgs", ctx, msgs) + ret0, _ := ret[0].([]MsgID) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SendMsgs indicates an expected call of SendMsgs. +func (mr *MockChainMockRecorder) SendMsgs(ctx, msgs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsgs", reflect.TypeOf((*MockChain)(nil).SendMsgs), ctx, msgs) +} + +// SetRelayInfo mocks base method. +func (m *MockChain) SetRelayInfo(path *PathEnd, counterparty *ProvableChain, counterpartyPath *PathEnd) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetRelayInfo", path, counterparty, counterpartyPath) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetRelayInfo indicates an expected call of SetRelayInfo. +func (mr *MockChainMockRecorder) SetRelayInfo(path, counterparty, counterpartyPath any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRelayInfo", reflect.TypeOf((*MockChain)(nil).SetRelayInfo), path, counterparty, counterpartyPath) +} + +// SetupForRelay mocks base method. +func (m *MockChain) SetupForRelay(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetupForRelay", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetupForRelay indicates an expected call of SetupForRelay. +func (mr *MockChainMockRecorder) SetupForRelay(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetupForRelay", reflect.TypeOf((*MockChain)(nil).SetupForRelay), ctx) +} + +// Timestamp mocks base method. +func (m *MockChain) Timestamp(ctx context.Context, height exported.Height) (time.Time, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Timestamp", ctx, height) + ret0, _ := ret[0].(time.Time) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Timestamp indicates an expected call of Timestamp. +func (mr *MockChainMockRecorder) Timestamp(ctx, height any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Timestamp", reflect.TypeOf((*MockChain)(nil).Timestamp), ctx, height) +} + +// MockChainInfo is a mock of ChainInfo interface. +type MockChainInfo struct { + ctrl *gomock.Controller + recorder *MockChainInfoMockRecorder + isgomock struct{} +} + +// MockChainInfoMockRecorder is the mock recorder for MockChainInfo. +type MockChainInfoMockRecorder struct { + mock *MockChainInfo +} + +// NewMockChainInfo creates a new mock instance. +func NewMockChainInfo(ctrl *gomock.Controller) *MockChainInfo { + mock := &MockChainInfo{ctrl: ctrl} + mock.recorder = &MockChainInfoMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockChainInfo) EXPECT() *MockChainInfoMockRecorder { + return m.recorder +} + +// AverageBlockTime mocks base method. +func (m *MockChainInfo) AverageBlockTime() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AverageBlockTime") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// AverageBlockTime indicates an expected call of AverageBlockTime. +func (mr *MockChainInfoMockRecorder) AverageBlockTime() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AverageBlockTime", reflect.TypeOf((*MockChainInfo)(nil).AverageBlockTime)) +} + +// ChainID mocks base method. +func (m *MockChainInfo) ChainID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChainID") + ret0, _ := ret[0].(string) + return ret0 +} + +// ChainID indicates an expected call of ChainID. +func (mr *MockChainInfoMockRecorder) ChainID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainID", reflect.TypeOf((*MockChainInfo)(nil).ChainID)) +} + +// LatestHeight mocks base method. +func (m *MockChainInfo) LatestHeight(ctx context.Context) (exported.Height, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LatestHeight", ctx) + ret0, _ := ret[0].(exported.Height) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LatestHeight indicates an expected call of LatestHeight. +func (mr *MockChainInfoMockRecorder) LatestHeight(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LatestHeight", reflect.TypeOf((*MockChainInfo)(nil).LatestHeight), ctx) +} + +// Timestamp mocks base method. +func (m *MockChainInfo) Timestamp(ctx context.Context, height exported.Height) (time.Time, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Timestamp", ctx, height) + ret0, _ := ret[0].(time.Time) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Timestamp indicates an expected call of Timestamp. +func (mr *MockChainInfoMockRecorder) Timestamp(ctx, height any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Timestamp", reflect.TypeOf((*MockChainInfo)(nil).Timestamp), ctx, height) +} + +// MockMsgEventListener is a mock of MsgEventListener interface. +type MockMsgEventListener struct { + ctrl *gomock.Controller + recorder *MockMsgEventListenerMockRecorder + isgomock struct{} +} + +// MockMsgEventListenerMockRecorder is the mock recorder for MockMsgEventListener. +type MockMsgEventListenerMockRecorder struct { + mock *MockMsgEventListener +} + +// NewMockMsgEventListener creates a new mock instance. +func NewMockMsgEventListener(ctrl *gomock.Controller) *MockMsgEventListener { + mock := &MockMsgEventListener{ctrl: ctrl} + mock.recorder = &MockMsgEventListenerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockMsgEventListener) EXPECT() *MockMsgEventListenerMockRecorder { + return m.recorder +} + +// OnSentMsg mocks base method. +func (m *MockMsgEventListener) OnSentMsg(ctx context.Context, msgs []types.Msg) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnSentMsg", ctx, msgs) + ret0, _ := ret[0].(error) + return ret0 +} + +// OnSentMsg indicates an expected call of OnSentMsg. +func (mr *MockMsgEventListenerMockRecorder) OnSentMsg(ctx, msgs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnSentMsg", reflect.TypeOf((*MockMsgEventListener)(nil).OnSentMsg), ctx, msgs) +} + +// MockIBCQuerier is a mock of IBCQuerier interface. +type MockIBCQuerier struct { + ctrl *gomock.Controller + recorder *MockIBCQuerierMockRecorder + isgomock struct{} +} + +// MockIBCQuerierMockRecorder is the mock recorder for MockIBCQuerier. +type MockIBCQuerierMockRecorder struct { + mock *MockIBCQuerier +} + +// NewMockIBCQuerier creates a new mock instance. +func NewMockIBCQuerier(ctrl *gomock.Controller) *MockIBCQuerier { + mock := &MockIBCQuerier{ctrl: ctrl} + mock.recorder = &MockIBCQuerierMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIBCQuerier) EXPECT() *MockIBCQuerierMockRecorder { + return m.recorder +} + +// QueryCanTransitionToFlushComplete mocks base method. +func (m *MockIBCQuerier) QueryCanTransitionToFlushComplete(ctx QueryContext) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryCanTransitionToFlushComplete", ctx) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryCanTransitionToFlushComplete indicates an expected call of QueryCanTransitionToFlushComplete. +func (mr *MockIBCQuerierMockRecorder) QueryCanTransitionToFlushComplete(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryCanTransitionToFlushComplete", reflect.TypeOf((*MockIBCQuerier)(nil).QueryCanTransitionToFlushComplete), ctx) +} + +// QueryChannel mocks base method. +func (m *MockIBCQuerier) QueryChannel(ctx QueryContext) (*types3.QueryChannelResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannel", ctx) + ret0, _ := ret[0].(*types3.QueryChannelResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannel indicates an expected call of QueryChannel. +func (mr *MockIBCQuerierMockRecorder) QueryChannel(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannel", reflect.TypeOf((*MockIBCQuerier)(nil).QueryChannel), ctx) +} + +// QueryChannelUpgrade mocks base method. +func (m *MockIBCQuerier) QueryChannelUpgrade(ctx QueryContext) (*types3.QueryUpgradeResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannelUpgrade", ctx) + ret0, _ := ret[0].(*types3.QueryUpgradeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannelUpgrade indicates an expected call of QueryChannelUpgrade. +func (mr *MockIBCQuerierMockRecorder) QueryChannelUpgrade(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannelUpgrade", reflect.TypeOf((*MockIBCQuerier)(nil).QueryChannelUpgrade), ctx) +} + +// QueryChannelUpgradeError mocks base method. +func (m *MockIBCQuerier) QueryChannelUpgradeError(ctx QueryContext) (*types3.QueryUpgradeErrorResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannelUpgradeError", ctx) + ret0, _ := ret[0].(*types3.QueryUpgradeErrorResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannelUpgradeError indicates an expected call of QueryChannelUpgradeError. +func (mr *MockIBCQuerierMockRecorder) QueryChannelUpgradeError(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannelUpgradeError", reflect.TypeOf((*MockIBCQuerier)(nil).QueryChannelUpgradeError), ctx) +} + +// QueryClientConsensusState mocks base method. +func (m *MockIBCQuerier) QueryClientConsensusState(ctx QueryContext, dstClientConsHeight exported.Height) (*types1.QueryConsensusStateResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryClientConsensusState", ctx, dstClientConsHeight) + ret0, _ := ret[0].(*types1.QueryConsensusStateResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryClientConsensusState indicates an expected call of QueryClientConsensusState. +func (mr *MockIBCQuerierMockRecorder) QueryClientConsensusState(ctx, dstClientConsHeight any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryClientConsensusState", reflect.TypeOf((*MockIBCQuerier)(nil).QueryClientConsensusState), ctx, dstClientConsHeight) +} + +// QueryClientState mocks base method. +func (m *MockIBCQuerier) QueryClientState(ctx QueryContext) (*types1.QueryClientStateResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryClientState", ctx) + ret0, _ := ret[0].(*types1.QueryClientStateResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryClientState indicates an expected call of QueryClientState. +func (mr *MockIBCQuerierMockRecorder) QueryClientState(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryClientState", reflect.TypeOf((*MockIBCQuerier)(nil).QueryClientState), ctx) +} + +// QueryConnection mocks base method. +func (m *MockIBCQuerier) QueryConnection(ctx QueryContext, connectionID string) (*types2.QueryConnectionResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryConnection", ctx, connectionID) + ret0, _ := ret[0].(*types2.QueryConnectionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryConnection indicates an expected call of QueryConnection. +func (mr *MockIBCQuerierMockRecorder) QueryConnection(ctx, connectionID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryConnection", reflect.TypeOf((*MockIBCQuerier)(nil).QueryConnection), ctx, connectionID) +} + +// QueryNextSequenceReceive mocks base method. +func (m *MockIBCQuerier) QueryNextSequenceReceive(ctx QueryContext) (*types3.QueryNextSequenceReceiveResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryNextSequenceReceive", ctx) + ret0, _ := ret[0].(*types3.QueryNextSequenceReceiveResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryNextSequenceReceive indicates an expected call of QueryNextSequenceReceive. +func (mr *MockIBCQuerierMockRecorder) QueryNextSequenceReceive(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryNextSequenceReceive", reflect.TypeOf((*MockIBCQuerier)(nil).QueryNextSequenceReceive), ctx) +} + +// QueryUnfinalizedRelayAcknowledgements mocks base method. +func (m *MockIBCQuerier) QueryUnfinalizedRelayAcknowledgements(ctx QueryContext, counterparty LightClientICS04Querier) (PacketInfoList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnfinalizedRelayAcknowledgements", ctx, counterparty) + ret0, _ := ret[0].(PacketInfoList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnfinalizedRelayAcknowledgements indicates an expected call of QueryUnfinalizedRelayAcknowledgements. +func (mr *MockIBCQuerierMockRecorder) QueryUnfinalizedRelayAcknowledgements(ctx, counterparty any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnfinalizedRelayAcknowledgements", reflect.TypeOf((*MockIBCQuerier)(nil).QueryUnfinalizedRelayAcknowledgements), ctx, counterparty) +} + +// QueryUnfinalizedRelayPackets mocks base method. +func (m *MockIBCQuerier) QueryUnfinalizedRelayPackets(ctx QueryContext, counterparty LightClientICS04Querier) (PacketInfoList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnfinalizedRelayPackets", ctx, counterparty) + ret0, _ := ret[0].(PacketInfoList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnfinalizedRelayPackets indicates an expected call of QueryUnfinalizedRelayPackets. +func (mr *MockIBCQuerierMockRecorder) QueryUnfinalizedRelayPackets(ctx, counterparty any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnfinalizedRelayPackets", reflect.TypeOf((*MockIBCQuerier)(nil).QueryUnfinalizedRelayPackets), ctx, counterparty) +} + +// QueryUnreceivedAcknowledgements mocks base method. +func (m *MockIBCQuerier) QueryUnreceivedAcknowledgements(ctx QueryContext, seqs []uint64) ([]uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnreceivedAcknowledgements", ctx, seqs) + ret0, _ := ret[0].([]uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnreceivedAcknowledgements indicates an expected call of QueryUnreceivedAcknowledgements. +func (mr *MockIBCQuerierMockRecorder) QueryUnreceivedAcknowledgements(ctx, seqs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnreceivedAcknowledgements", reflect.TypeOf((*MockIBCQuerier)(nil).QueryUnreceivedAcknowledgements), ctx, seqs) +} + +// QueryUnreceivedPackets mocks base method. +func (m *MockIBCQuerier) QueryUnreceivedPackets(ctx QueryContext, seqs []uint64) ([]uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnreceivedPackets", ctx, seqs) + ret0, _ := ret[0].([]uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnreceivedPackets indicates an expected call of QueryUnreceivedPackets. +func (mr *MockIBCQuerierMockRecorder) QueryUnreceivedPackets(ctx, seqs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnreceivedPackets", reflect.TypeOf((*MockIBCQuerier)(nil).QueryUnreceivedPackets), ctx, seqs) +} + +// MockICS02Querier is a mock of ICS02Querier interface. +type MockICS02Querier struct { + ctrl *gomock.Controller + recorder *MockICS02QuerierMockRecorder + isgomock struct{} +} + +// MockICS02QuerierMockRecorder is the mock recorder for MockICS02Querier. +type MockICS02QuerierMockRecorder struct { + mock *MockICS02Querier +} + +// NewMockICS02Querier creates a new mock instance. +func NewMockICS02Querier(ctrl *gomock.Controller) *MockICS02Querier { + mock := &MockICS02Querier{ctrl: ctrl} + mock.recorder = &MockICS02QuerierMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockICS02Querier) EXPECT() *MockICS02QuerierMockRecorder { + return m.recorder +} + +// QueryClientConsensusState mocks base method. +func (m *MockICS02Querier) QueryClientConsensusState(ctx QueryContext, dstClientConsHeight exported.Height) (*types1.QueryConsensusStateResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryClientConsensusState", ctx, dstClientConsHeight) + ret0, _ := ret[0].(*types1.QueryConsensusStateResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryClientConsensusState indicates an expected call of QueryClientConsensusState. +func (mr *MockICS02QuerierMockRecorder) QueryClientConsensusState(ctx, dstClientConsHeight any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryClientConsensusState", reflect.TypeOf((*MockICS02Querier)(nil).QueryClientConsensusState), ctx, dstClientConsHeight) +} + +// QueryClientState mocks base method. +func (m *MockICS02Querier) QueryClientState(ctx QueryContext) (*types1.QueryClientStateResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryClientState", ctx) + ret0, _ := ret[0].(*types1.QueryClientStateResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryClientState indicates an expected call of QueryClientState. +func (mr *MockICS02QuerierMockRecorder) QueryClientState(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryClientState", reflect.TypeOf((*MockICS02Querier)(nil).QueryClientState), ctx) +} + +// MockICS03Querier is a mock of ICS03Querier interface. +type MockICS03Querier struct { + ctrl *gomock.Controller + recorder *MockICS03QuerierMockRecorder + isgomock struct{} +} + +// MockICS03QuerierMockRecorder is the mock recorder for MockICS03Querier. +type MockICS03QuerierMockRecorder struct { + mock *MockICS03Querier +} + +// NewMockICS03Querier creates a new mock instance. +func NewMockICS03Querier(ctrl *gomock.Controller) *MockICS03Querier { + mock := &MockICS03Querier{ctrl: ctrl} + mock.recorder = &MockICS03QuerierMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockICS03Querier) EXPECT() *MockICS03QuerierMockRecorder { + return m.recorder +} + +// QueryConnection mocks base method. +func (m *MockICS03Querier) QueryConnection(ctx QueryContext, connectionID string) (*types2.QueryConnectionResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryConnection", ctx, connectionID) + ret0, _ := ret[0].(*types2.QueryConnectionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryConnection indicates an expected call of QueryConnection. +func (mr *MockICS03QuerierMockRecorder) QueryConnection(ctx, connectionID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryConnection", reflect.TypeOf((*MockICS03Querier)(nil).QueryConnection), ctx, connectionID) +} + +// MockICS04Querier is a mock of ICS04Querier interface. +type MockICS04Querier struct { + ctrl *gomock.Controller + recorder *MockICS04QuerierMockRecorder + isgomock struct{} +} + +// MockICS04QuerierMockRecorder is the mock recorder for MockICS04Querier. +type MockICS04QuerierMockRecorder struct { + mock *MockICS04Querier +} + +// NewMockICS04Querier creates a new mock instance. +func NewMockICS04Querier(ctrl *gomock.Controller) *MockICS04Querier { + mock := &MockICS04Querier{ctrl: ctrl} + mock.recorder = &MockICS04QuerierMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockICS04Querier) EXPECT() *MockICS04QuerierMockRecorder { + return m.recorder +} + +// QueryCanTransitionToFlushComplete mocks base method. +func (m *MockICS04Querier) QueryCanTransitionToFlushComplete(ctx QueryContext) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryCanTransitionToFlushComplete", ctx) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryCanTransitionToFlushComplete indicates an expected call of QueryCanTransitionToFlushComplete. +func (mr *MockICS04QuerierMockRecorder) QueryCanTransitionToFlushComplete(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryCanTransitionToFlushComplete", reflect.TypeOf((*MockICS04Querier)(nil).QueryCanTransitionToFlushComplete), ctx) +} + +// QueryChannel mocks base method. +func (m *MockICS04Querier) QueryChannel(ctx QueryContext) (*types3.QueryChannelResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannel", ctx) + ret0, _ := ret[0].(*types3.QueryChannelResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannel indicates an expected call of QueryChannel. +func (mr *MockICS04QuerierMockRecorder) QueryChannel(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannel", reflect.TypeOf((*MockICS04Querier)(nil).QueryChannel), ctx) +} + +// QueryChannelUpgrade mocks base method. +func (m *MockICS04Querier) QueryChannelUpgrade(ctx QueryContext) (*types3.QueryUpgradeResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannelUpgrade", ctx) + ret0, _ := ret[0].(*types3.QueryUpgradeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannelUpgrade indicates an expected call of QueryChannelUpgrade. +func (mr *MockICS04QuerierMockRecorder) QueryChannelUpgrade(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannelUpgrade", reflect.TypeOf((*MockICS04Querier)(nil).QueryChannelUpgrade), ctx) +} + +// QueryChannelUpgradeError mocks base method. +func (m *MockICS04Querier) QueryChannelUpgradeError(ctx QueryContext) (*types3.QueryUpgradeErrorResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannelUpgradeError", ctx) + ret0, _ := ret[0].(*types3.QueryUpgradeErrorResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannelUpgradeError indicates an expected call of QueryChannelUpgradeError. +func (mr *MockICS04QuerierMockRecorder) QueryChannelUpgradeError(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannelUpgradeError", reflect.TypeOf((*MockICS04Querier)(nil).QueryChannelUpgradeError), ctx) +} + +// QueryNextSequenceReceive mocks base method. +func (m *MockICS04Querier) QueryNextSequenceReceive(ctx QueryContext) (*types3.QueryNextSequenceReceiveResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryNextSequenceReceive", ctx) + ret0, _ := ret[0].(*types3.QueryNextSequenceReceiveResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryNextSequenceReceive indicates an expected call of QueryNextSequenceReceive. +func (mr *MockICS04QuerierMockRecorder) QueryNextSequenceReceive(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryNextSequenceReceive", reflect.TypeOf((*MockICS04Querier)(nil).QueryNextSequenceReceive), ctx) +} + +// QueryUnfinalizedRelayAcknowledgements mocks base method. +func (m *MockICS04Querier) QueryUnfinalizedRelayAcknowledgements(ctx QueryContext, counterparty LightClientICS04Querier) (PacketInfoList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnfinalizedRelayAcknowledgements", ctx, counterparty) + ret0, _ := ret[0].(PacketInfoList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnfinalizedRelayAcknowledgements indicates an expected call of QueryUnfinalizedRelayAcknowledgements. +func (mr *MockICS04QuerierMockRecorder) QueryUnfinalizedRelayAcknowledgements(ctx, counterparty any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnfinalizedRelayAcknowledgements", reflect.TypeOf((*MockICS04Querier)(nil).QueryUnfinalizedRelayAcknowledgements), ctx, counterparty) +} + +// QueryUnfinalizedRelayPackets mocks base method. +func (m *MockICS04Querier) QueryUnfinalizedRelayPackets(ctx QueryContext, counterparty LightClientICS04Querier) (PacketInfoList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnfinalizedRelayPackets", ctx, counterparty) + ret0, _ := ret[0].(PacketInfoList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnfinalizedRelayPackets indicates an expected call of QueryUnfinalizedRelayPackets. +func (mr *MockICS04QuerierMockRecorder) QueryUnfinalizedRelayPackets(ctx, counterparty any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnfinalizedRelayPackets", reflect.TypeOf((*MockICS04Querier)(nil).QueryUnfinalizedRelayPackets), ctx, counterparty) +} + +// QueryUnreceivedAcknowledgements mocks base method. +func (m *MockICS04Querier) QueryUnreceivedAcknowledgements(ctx QueryContext, seqs []uint64) ([]uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnreceivedAcknowledgements", ctx, seqs) + ret0, _ := ret[0].([]uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnreceivedAcknowledgements indicates an expected call of QueryUnreceivedAcknowledgements. +func (mr *MockICS04QuerierMockRecorder) QueryUnreceivedAcknowledgements(ctx, seqs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnreceivedAcknowledgements", reflect.TypeOf((*MockICS04Querier)(nil).QueryUnreceivedAcknowledgements), ctx, seqs) +} + +// QueryUnreceivedPackets mocks base method. +func (m *MockICS04Querier) QueryUnreceivedPackets(ctx QueryContext, seqs []uint64) ([]uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnreceivedPackets", ctx, seqs) + ret0, _ := ret[0].([]uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnreceivedPackets indicates an expected call of QueryUnreceivedPackets. +func (mr *MockICS04QuerierMockRecorder) QueryUnreceivedPackets(ctx, seqs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnreceivedPackets", reflect.TypeOf((*MockICS04Querier)(nil).QueryUnreceivedPackets), ctx, seqs) +} + +// MockICS20Querier is a mock of ICS20Querier interface. +type MockICS20Querier struct { + ctrl *gomock.Controller + recorder *MockICS20QuerierMockRecorder + isgomock struct{} +} + +// MockICS20QuerierMockRecorder is the mock recorder for MockICS20Querier. +type MockICS20QuerierMockRecorder struct { + mock *MockICS20Querier +} + +// NewMockICS20Querier creates a new mock instance. +func NewMockICS20Querier(ctrl *gomock.Controller) *MockICS20Querier { + mock := &MockICS20Querier{ctrl: ctrl} + mock.recorder = &MockICS20QuerierMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockICS20Querier) EXPECT() *MockICS20QuerierMockRecorder { + return m.recorder +} + +// QueryBalance mocks base method. +func (m *MockICS20Querier) QueryBalance(ctx QueryContext, address types.AccAddress) (types.Coins, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryBalance", ctx, address) + ret0, _ := ret[0].(types.Coins) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryBalance indicates an expected call of QueryBalance. +func (mr *MockICS20QuerierMockRecorder) QueryBalance(ctx, address any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBalance", reflect.TypeOf((*MockICS20Querier)(nil).QueryBalance), ctx, address) +} + +// QueryDenomTraces mocks base method. +func (m *MockICS20Querier) QueryDenomTraces(ctx QueryContext, offset, limit uint64) (*types0.QueryDenomTracesResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryDenomTraces", ctx, offset, limit) + ret0, _ := ret[0].(*types0.QueryDenomTracesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryDenomTraces indicates an expected call of QueryDenomTraces. +func (mr *MockICS20QuerierMockRecorder) QueryDenomTraces(ctx, offset, limit any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryDenomTraces", reflect.TypeOf((*MockICS20Querier)(nil).QueryDenomTraces), ctx, offset, limit) +} + +// MockLightClientICS04Querier is a mock of LightClientICS04Querier interface. +type MockLightClientICS04Querier struct { + ctrl *gomock.Controller + recorder *MockLightClientICS04QuerierMockRecorder + isgomock struct{} +} + +// MockLightClientICS04QuerierMockRecorder is the mock recorder for MockLightClientICS04Querier. +type MockLightClientICS04QuerierMockRecorder struct { + mock *MockLightClientICS04Querier +} + +// NewMockLightClientICS04Querier creates a new mock instance. +func NewMockLightClientICS04Querier(ctrl *gomock.Controller) *MockLightClientICS04Querier { + mock := &MockLightClientICS04Querier{ctrl: ctrl} + mock.recorder = &MockLightClientICS04QuerierMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLightClientICS04Querier) EXPECT() *MockLightClientICS04QuerierMockRecorder { + return m.recorder +} + +// CheckRefreshRequired mocks base method. +func (m *MockLightClientICS04Querier) CheckRefreshRequired(ctx context.Context, counterparty ChainInfoICS02Querier) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckRefreshRequired", ctx, counterparty) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CheckRefreshRequired indicates an expected call of CheckRefreshRequired. +func (mr *MockLightClientICS04QuerierMockRecorder) CheckRefreshRequired(ctx, counterparty any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckRefreshRequired", reflect.TypeOf((*MockLightClientICS04Querier)(nil).CheckRefreshRequired), ctx, counterparty) +} + +// CreateInitialLightClientState mocks base method. +func (m *MockLightClientICS04Querier) CreateInitialLightClientState(ctx context.Context, height exported.Height) (exported.ClientState, exported.ConsensusState, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateInitialLightClientState", ctx, height) + ret0, _ := ret[0].(exported.ClientState) + ret1, _ := ret[1].(exported.ConsensusState) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// CreateInitialLightClientState indicates an expected call of CreateInitialLightClientState. +func (mr *MockLightClientICS04QuerierMockRecorder) CreateInitialLightClientState(ctx, height any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateInitialLightClientState", reflect.TypeOf((*MockLightClientICS04Querier)(nil).CreateInitialLightClientState), ctx, height) +} + +// GetLatestFinalizedHeader mocks base method. +func (m *MockLightClientICS04Querier) GetLatestFinalizedHeader(ctx context.Context) (Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLatestFinalizedHeader", ctx) + ret0, _ := ret[0].(Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLatestFinalizedHeader indicates an expected call of GetLatestFinalizedHeader. +func (mr *MockLightClientICS04QuerierMockRecorder) GetLatestFinalizedHeader(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestFinalizedHeader", reflect.TypeOf((*MockLightClientICS04Querier)(nil).GetLatestFinalizedHeader), ctx) +} + +// QueryCanTransitionToFlushComplete mocks base method. +func (m *MockLightClientICS04Querier) QueryCanTransitionToFlushComplete(ctx QueryContext) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryCanTransitionToFlushComplete", ctx) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryCanTransitionToFlushComplete indicates an expected call of QueryCanTransitionToFlushComplete. +func (mr *MockLightClientICS04QuerierMockRecorder) QueryCanTransitionToFlushComplete(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryCanTransitionToFlushComplete", reflect.TypeOf((*MockLightClientICS04Querier)(nil).QueryCanTransitionToFlushComplete), ctx) +} + +// QueryChannel mocks base method. +func (m *MockLightClientICS04Querier) QueryChannel(ctx QueryContext) (*types3.QueryChannelResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannel", ctx) + ret0, _ := ret[0].(*types3.QueryChannelResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannel indicates an expected call of QueryChannel. +func (mr *MockLightClientICS04QuerierMockRecorder) QueryChannel(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannel", reflect.TypeOf((*MockLightClientICS04Querier)(nil).QueryChannel), ctx) +} + +// QueryChannelUpgrade mocks base method. +func (m *MockLightClientICS04Querier) QueryChannelUpgrade(ctx QueryContext) (*types3.QueryUpgradeResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannelUpgrade", ctx) + ret0, _ := ret[0].(*types3.QueryUpgradeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannelUpgrade indicates an expected call of QueryChannelUpgrade. +func (mr *MockLightClientICS04QuerierMockRecorder) QueryChannelUpgrade(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannelUpgrade", reflect.TypeOf((*MockLightClientICS04Querier)(nil).QueryChannelUpgrade), ctx) +} + +// QueryChannelUpgradeError mocks base method. +func (m *MockLightClientICS04Querier) QueryChannelUpgradeError(ctx QueryContext) (*types3.QueryUpgradeErrorResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryChannelUpgradeError", ctx) + ret0, _ := ret[0].(*types3.QueryUpgradeErrorResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryChannelUpgradeError indicates an expected call of QueryChannelUpgradeError. +func (mr *MockLightClientICS04QuerierMockRecorder) QueryChannelUpgradeError(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryChannelUpgradeError", reflect.TypeOf((*MockLightClientICS04Querier)(nil).QueryChannelUpgradeError), ctx) +} + +// QueryNextSequenceReceive mocks base method. +func (m *MockLightClientICS04Querier) QueryNextSequenceReceive(ctx QueryContext) (*types3.QueryNextSequenceReceiveResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryNextSequenceReceive", ctx) + ret0, _ := ret[0].(*types3.QueryNextSequenceReceiveResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryNextSequenceReceive indicates an expected call of QueryNextSequenceReceive. +func (mr *MockLightClientICS04QuerierMockRecorder) QueryNextSequenceReceive(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryNextSequenceReceive", reflect.TypeOf((*MockLightClientICS04Querier)(nil).QueryNextSequenceReceive), ctx) +} + +// QueryUnfinalizedRelayAcknowledgements mocks base method. +func (m *MockLightClientICS04Querier) QueryUnfinalizedRelayAcknowledgements(ctx QueryContext, counterparty LightClientICS04Querier) (PacketInfoList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnfinalizedRelayAcknowledgements", ctx, counterparty) + ret0, _ := ret[0].(PacketInfoList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnfinalizedRelayAcknowledgements indicates an expected call of QueryUnfinalizedRelayAcknowledgements. +func (mr *MockLightClientICS04QuerierMockRecorder) QueryUnfinalizedRelayAcknowledgements(ctx, counterparty any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnfinalizedRelayAcknowledgements", reflect.TypeOf((*MockLightClientICS04Querier)(nil).QueryUnfinalizedRelayAcknowledgements), ctx, counterparty) +} + +// QueryUnfinalizedRelayPackets mocks base method. +func (m *MockLightClientICS04Querier) QueryUnfinalizedRelayPackets(ctx QueryContext, counterparty LightClientICS04Querier) (PacketInfoList, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnfinalizedRelayPackets", ctx, counterparty) + ret0, _ := ret[0].(PacketInfoList) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnfinalizedRelayPackets indicates an expected call of QueryUnfinalizedRelayPackets. +func (mr *MockLightClientICS04QuerierMockRecorder) QueryUnfinalizedRelayPackets(ctx, counterparty any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnfinalizedRelayPackets", reflect.TypeOf((*MockLightClientICS04Querier)(nil).QueryUnfinalizedRelayPackets), ctx, counterparty) +} + +// QueryUnreceivedAcknowledgements mocks base method. +func (m *MockLightClientICS04Querier) QueryUnreceivedAcknowledgements(ctx QueryContext, seqs []uint64) ([]uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnreceivedAcknowledgements", ctx, seqs) + ret0, _ := ret[0].([]uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnreceivedAcknowledgements indicates an expected call of QueryUnreceivedAcknowledgements. +func (mr *MockLightClientICS04QuerierMockRecorder) QueryUnreceivedAcknowledgements(ctx, seqs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnreceivedAcknowledgements", reflect.TypeOf((*MockLightClientICS04Querier)(nil).QueryUnreceivedAcknowledgements), ctx, seqs) +} + +// QueryUnreceivedPackets mocks base method. +func (m *MockLightClientICS04Querier) QueryUnreceivedPackets(ctx QueryContext, seqs []uint64) ([]uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryUnreceivedPackets", ctx, seqs) + ret0, _ := ret[0].([]uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryUnreceivedPackets indicates an expected call of QueryUnreceivedPackets. +func (mr *MockLightClientICS04QuerierMockRecorder) QueryUnreceivedPackets(ctx, seqs any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryUnreceivedPackets", reflect.TypeOf((*MockLightClientICS04Querier)(nil).QueryUnreceivedPackets), ctx, seqs) +} + +// SetupHeadersForUpdate mocks base method. +func (m *MockLightClientICS04Querier) SetupHeadersForUpdate(ctx context.Context, counterparty FinalityAwareChain, latestFinalizedHeader Header) ([]Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetupHeadersForUpdate", ctx, counterparty, latestFinalizedHeader) + ret0, _ := ret[0].([]Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SetupHeadersForUpdate indicates an expected call of SetupHeadersForUpdate. +func (mr *MockLightClientICS04QuerierMockRecorder) SetupHeadersForUpdate(ctx, counterparty, latestFinalizedHeader any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetupHeadersForUpdate", reflect.TypeOf((*MockLightClientICS04Querier)(nil).SetupHeadersForUpdate), ctx, counterparty, latestFinalizedHeader) +} + +// MockQueryContext is a mock of QueryContext interface. +type MockQueryContext struct { + ctrl *gomock.Controller + recorder *MockQueryContextMockRecorder + isgomock struct{} +} + +// MockQueryContextMockRecorder is the mock recorder for MockQueryContext. +type MockQueryContextMockRecorder struct { + mock *MockQueryContext +} + +// NewMockQueryContext creates a new mock instance. +func NewMockQueryContext(ctrl *gomock.Controller) *MockQueryContext { + mock := &MockQueryContext{ctrl: ctrl} + mock.recorder = &MockQueryContextMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockQueryContext) EXPECT() *MockQueryContextMockRecorder { + return m.recorder +} + +// Context mocks base method. +func (m *MockQueryContext) Context() context.Context { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Context") + ret0, _ := ret[0].(context.Context) + return ret0 +} + +// Context indicates an expected call of Context. +func (mr *MockQueryContextMockRecorder) Context() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockQueryContext)(nil).Context)) +} + +// Height mocks base method. +func (m *MockQueryContext) Height() exported.Height { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Height") + ret0, _ := ret[0].(exported.Height) + return ret0 +} + +// Height indicates an expected call of Height. +func (mr *MockQueryContextMockRecorder) Height() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Height", reflect.TypeOf((*MockQueryContext)(nil).Height)) +} diff --git a/core/naive-strategy.go b/core/naive-strategy.go index eba1a72c..a3cc7404 100644 --- a/core/naive-strategy.go +++ b/core/naive-strategy.go @@ -2,6 +2,7 @@ package core import ( "context" + "encoding/binary" "fmt" "log/slog" "time" @@ -10,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" "github.com/hyperledger-labs/yui-relayer/internal/telemetry" "github.com/hyperledger-labs/yui-relayer/otelcore/semconv" "go.opentelemetry.io/otel/attribute" @@ -201,6 +203,141 @@ func (st *NaiveStrategy) UnrelayedPackets(ctx context.Context, src, dst *Provabl }, nil } +func (st *NaiveStrategy) ProcessTimeoutPackets(ctx context.Context, src, dst *ProvableChain, sh SyncHeaders, rp *RelayPackets) error { + logger := GetChannelPairLogger(src, dst) + var ( + srcPackets PacketInfoList + dstPackets PacketInfoList + srcLatestHeight ibcexported.Height + srcLatestTimestamp uint64 + srcLatestFinalizedHeight ibcexported.Height + srcLatestFinalizedTimestamp uint64 + dstLatestHeight ibcexported.Height + dstLatestTimestamp uint64 + dstLatestFinalizedHeight ibcexported.Height + dstLatestFinalizedTimestamp uint64 + ) + + if 0 < len(rp.Src) { + if h, err := dst.LatestHeight(ctx); err != nil { + logger.Error("fail to get dst.LatestHeight", err) + return err + } else { + dstLatestHeight = h + } + + if t, err := dst.Timestamp(ctx, dstLatestHeight); err != nil { + logger.Error("fail to get dst.Timestamp of latestHeight", err) + return err + } else { + dstLatestTimestamp = uint64(t.UnixNano()) + } + + dstLatestFinalizedHeight = sh.GetLatestFinalizedHeader(dst.ChainID()).GetHeight() + if t, err := dst.Timestamp(ctx, dstLatestFinalizedHeight); err != nil { + logger.Error("fail to get dst.Timestamp of latestFinalizedHeight", err) + return err + } else { + dstLatestFinalizedTimestamp = uint64(t.UnixNano()) + } + } + if 0 < len(rp.Dst) { + if h, err := src.LatestHeight(ctx); err != nil { + logger.Error("fail to get src.LatestHeight", err) + return err + } else { + srcLatestHeight = h + } + if t, err := src.Timestamp(ctx, srcLatestHeight); err != nil { + logger.Error("fail to get src.Timestamp of latestHeight", err) + return err + } else { + srcLatestTimestamp = uint64(t.UnixNano()) + } + + srcLatestFinalizedHeight = sh.GetLatestFinalizedHeader(src.ChainID()).GetHeight() + if t, err := src.Timestamp(ctx, srcLatestFinalizedHeight); err != nil { + logger.Error("fail to get src.Timestamp of latestFinalizedHeight", err) + return err + } else { + srcLatestFinalizedTimestamp = uint64(t.UnixNano()) + } + } + + isTimeout := func(p *PacketInfo, height ibcexported.Height, timestamp uint64) bool { + return (!p.TimeoutHeight.IsZero() && p.TimeoutHeight.LTE(height)) || + (p.TimeoutTimestamp != 0 && p.TimeoutTimestamp <= timestamp) + } + + var srcTimeoutPackets, dstTimeoutPackets []*PacketInfo + for i, p := range rp.Src { + if isTimeout(p, dstLatestFinalizedHeight, dstLatestFinalizedTimestamp) { + p.TimedOut = true + if src.Path().GetOrder() == chantypes.ORDERED { + // For ordered channel, a timeout notification will cause the channel to be closed. + // Packets proceeding the timeout packet is relayed first + // so that they can be proceeded before the channel is closed. + // In ordered channels, only the first timed-out packet is selected because + // a timeout notification will close the channel. Subsequent packets cannot + // be processed once the channel is closed. + if i == 0 { + // queue timeout notify packet only if previous packet is finally received on dst chain. + res, err := dst.QueryNextSequenceReceive(NewQueryContext(ctx, dstLatestFinalizedHeight)) + if err != nil { + logger.Error("failed to QueryNextSequenceRecv for src timeout", err, "height", dstLatestFinalizedHeight) + } else { + if res.NextSequenceReceive == p.Sequence { + srcTimeoutPackets = []*PacketInfo{p} + } + } + } + break + } else { + srcTimeoutPackets = append(srcTimeoutPackets, p) + } + } else if isTimeout(p, dstLatestHeight, dstLatestTimestamp) { + break + } else { + p.TimedOut = false + srcPackets = append(srcPackets, p) + } + } + for i, p := range rp.Dst { + if isTimeout(p, srcLatestFinalizedHeight, srcLatestFinalizedTimestamp) { + p.TimedOut = true + if dst.Path().GetOrder() == chantypes.ORDERED { + if i == 0 { + res, err := src.QueryNextSequenceReceive(NewQueryContext(ctx, srcLatestFinalizedHeight)) + if err != nil { + logger.Error("failed to QueryNextSequenceRecv for dst timeout", err, "height", srcLatestFinalizedHeight) + } else { + if res.NextSequenceReceive == p.Sequence { + dstTimeoutPackets = []*PacketInfo{p} + } + } + } + break + } else { + dstTimeoutPackets = append(dstTimeoutPackets, p) + } + } else if isTimeout(p, srcLatestHeight, srcLatestTimestamp) { + break + } else { + p.TimedOut = false + dstPackets = append(dstPackets, p) + } + } + if len(srcTimeoutPackets) > 0 { + dstPackets = append(dstPackets, srcTimeoutPackets...) + } + if len(dstTimeoutPackets) > 0 { + srcPackets = append(srcPackets, dstTimeoutPackets...) + } + rp.Src = srcPackets + rp.Dst = dstPackets + return nil +} + func (st *NaiveStrategy) RelayPackets(ctx context.Context, src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders, doExecuteRelaySrc, doExecuteRelayDst bool) (*RelayMsgs, error) { ctx, span := tracer.Start(ctx, "NaiveStrategy.RelayPackets", WithChannelPairAttributes(src, dst)) defer span.End() @@ -213,14 +350,14 @@ func (st *NaiveStrategy) RelayPackets(ctx context.Context, src, dst *ProvableCha dstCtx := sh.GetQueryContext(ctx, dst.ChainID()) srcAddress, err := src.GetAddress() if err != nil { - logger.ErrorContext(ctx, "error getting address", err) + logger.ErrorContext(ctx, "error getting src address", err) span.SetStatus(codes.Error, err.Error()) return nil, err } dstAddress, err := dst.GetAddress() if err != nil { - logger.ErrorContext(ctx, "error getting address", err) + logger.ErrorContext(ctx, "error getting dst address", err) span.SetStatus(codes.Error, err.Error()) return nil, err } @@ -228,7 +365,7 @@ func (st *NaiveStrategy) RelayPackets(ctx context.Context, src, dst *ProvableCha if doExecuteRelayDst { msgs.Dst, err = collectPackets(srcCtx, src, rp.Src, dstAddress) if err != nil { - logger.ErrorContext(ctx, "error collecting packets", err) + logger.ErrorContext(ctx, "error collecting src packets", err) span.SetStatus(codes.Error, err.Error()) return nil, err } @@ -237,7 +374,7 @@ func (st *NaiveStrategy) RelayPackets(ctx context.Context, src, dst *ProvableCha if doExecuteRelaySrc { msgs.Src, err = collectPackets(dstCtx, dst, rp.Dst, srcAddress) if err != nil { - logger.ErrorContext(ctx, "error collecting packets", err) + logger.ErrorContext(ctx, "error collecting dst packets", err) span.SetStatus(codes.Error, err.Error()) return nil, err } @@ -390,23 +527,51 @@ func (st *NaiveStrategy) UnrelayedAcknowledgements(ctx context.Context, src, dst }, nil } -// TODO add packet-timeout support func collectPackets(ctx QueryContext, chain *ProvableChain, packets PacketInfoList, signer sdk.AccAddress) ([]sdk.Msg, error) { logger := GetChannelLogger(chain) + var msgs []sdk.Msg for _, p := range packets { - commitment := chantypes.CommitPacket(chain.Codec(), &p.Packet) - path := host.PacketCommitmentPath(p.SourcePort, p.SourceChannel, p.Sequence) - proof, proofHeight, err := chain.ProveState(ctx, path, commitment) - if err != nil { - logger.ErrorContext(ctx.Context(), "failed to ProveState", err, - "height", ctx.Height(), - "path", path, - "commitment", commitment, - ) - return nil, err + var msg sdk.Msg + if p.TimedOut { + // make path of original packet's destination port and channel + var path string + var commitment []byte + var nextSequenceRecvOfTimeout uint64 + if chain.Path().GetOrder() == chantypes.ORDERED { + path = host.NextSequenceRecvPath(p.SourcePort, p.SourceChannel) + commitment = make([]byte, 8) + binary.BigEndian.PutUint64(commitment[0:], p.Sequence) + nextSequenceRecvOfTimeout = p.Sequence + } else { + path = host.PacketReceiptPath(p.SourcePort, p.SourceChannel, p.Sequence) + commitment = []byte{} // Represents absence of a commitment in unordered channels + nextSequenceRecvOfTimeout = 1 // nextSequenceRecv has no effect in unordered channel but ibc-go expect it is not zero. + } + proof, proofHeight, err := chain.ProveState(ctx, path, commitment) + if err != nil { + logger.ErrorContext(ctx.Context(), "failed to ProveState", err, + "height", ctx.Height(), + "path", path, + "commitment", commitment, + ) + return nil, err + } + msg = chantypes.NewMsgTimeout(p.Packet, nextSequenceRecvOfTimeout, proof, proofHeight, signer.String()) + } else { + path := host.PacketCommitmentPath(p.SourcePort, p.SourceChannel, p.Sequence) + commitment := chantypes.CommitPacket(chain.Codec(), &p.Packet) + proof, proofHeight, err := chain.ProveState(ctx, path, commitment) + if err != nil { + logger.ErrorContext(ctx.Context(), "failed to ProveState", err, + "height", ctx.Height(), + "path", path, + "commitment", commitment, + ) + return nil, err + } + msg = chantypes.NewMsgRecvPacket(p.Packet, proof, proofHeight, signer.String()) } - msg := chantypes.NewMsgRecvPacket(p.Packet, proof, proofHeight, signer.String()) msgs = append(msgs, msg) } return msgs, nil @@ -433,13 +598,13 @@ func (st *NaiveStrategy) RelayAcknowledgements(ctx context.Context, src, dst *Pr dstCtx := sh.GetQueryContext(ctx, dst.ChainID()) srcAddress, err := src.GetAddress() if err != nil { - logger.ErrorContext(ctx, "error getting address", err) + logger.ErrorContext(ctx, "error getting src address", err) span.SetStatus(codes.Error, err.Error()) return nil, err } dstAddress, err := dst.GetAddress() if err != nil { - logger.ErrorContext(ctx, "error getting address", err) + logger.ErrorContext(ctx, "error getting dst address", err) span.SetStatus(codes.Error, err.Error()) return nil, err } diff --git a/core/provers.go b/core/provers.go index db8cec38..e2762191 100644 --- a/core/provers.go +++ b/core/provers.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" ) // Prover represents a prover that supports generating a commitment proof @@ -31,7 +31,7 @@ type StateProver interface { // ProveHostConsensusState returns an existence proof of the consensus state at `height` // This proof would be ignored in ibc-go, but it is required to `getSelfConsensusState` of ibc-solidity. - ProveHostConsensusState(ctx QueryContext, height exported.Height, consensusState exported.ConsensusState) (proof []byte, err error) + ProveHostConsensusState(ctx QueryContext, height ibcexported.Height, consensusState ibcexported.ConsensusState) (proof []byte, err error) } // LightClient provides functions for creating and updating on-chain light clients on the counterparty chain @@ -41,7 +41,7 @@ type LightClient interface { // CreateInitialLightClientState returns a pair of ClientState and ConsensusState based on the state of the self chain at `height`. // These states will be submitted to the counterparty chain as MsgCreateClient. // If `height` is nil, the latest finalized height is selected automatically. - CreateInitialLightClientState(ctx context.Context, height exported.Height) (exported.ClientState, exported.ConsensusState, error) + CreateInitialLightClientState(ctx context.Context, height ibcexported.Height) (ibcexported.ClientState, ibcexported.ConsensusState, error) // SetupHeadersForUpdate returns the finalized header and any intermediate headers needed to apply it to the client on the counterpaty chain // The order of the returned header slice should be as: [..., ] diff --git a/core/service.go b/core/service.go index d4a00867..beca74b8 100644 --- a/core/service.go +++ b/core/service.go @@ -124,6 +124,12 @@ func (srv *RelayService) Serve(ctx context.Context) error { return err } + err = srv.st.ProcessTimeoutPackets(ctx, srv.src, srv.dst, srv.sh, pseqs) // update pseqs + if err != nil { + logger.Error("failed to process timeout packets", err) + return err + } + // get unrelayed acks aseqs, err := srv.st.UnrelayedAcknowledgements(ctx, srv.src, srv.dst, srv.sh, false) if err != nil { diff --git a/core/service_test.go b/core/service_test.go new file mode 100644 index 00000000..ee849c7b --- /dev/null +++ b/core/service_test.go @@ -0,0 +1,461 @@ +package core_test + +import ( + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" + "testing" + + "context" + "fmt" + "os" + "reflect" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + mocktypes "github.com/datachainlab/ibc-mock-client/modules/light-clients/xx-mock/types" + + "github.com/hyperledger-labs/yui-relayer/chains/tendermint" + "github.com/hyperledger-labs/yui-relayer/core" + "github.com/hyperledger-labs/yui-relayer/internal/telemetry" + "github.com/hyperledger-labs/yui-relayer/log" + "github.com/hyperledger-labs/yui-relayer/provers/mock" +) + +type NaiveStrategyWrap struct { + inner *core.NaiveStrategy + + unrelayedPacketsOut *core.RelayPackets + processTimeoutPacketsOut *core.RelayPackets + unrelayedAcknowledgementsOut *core.RelayPackets + relayPacketsOut *core.RelayMsgs + relayAcknowledgementsOut *core.RelayMsgs + updateClientsOut *core.RelayMsgs + sendInSrc []string + sendInDst []string +} + +func (s *NaiveStrategyWrap) GetType() string { return s.inner.GetType() } +func (s *NaiveStrategyWrap) SetupRelay(ctx context.Context, src, dst *core.ProvableChain) error { + return s.inner.SetupRelay(ctx, src, dst) +} +func (s *NaiveStrategyWrap) UnrelayedPackets(ctx context.Context, src, dst *core.ProvableChain, sh core.SyncHeaders, includeRelayedButUnfinalized bool) (*core.RelayPackets, error) { + ret, err := s.inner.UnrelayedPackets(ctx, src, dst, sh, includeRelayedButUnfinalized) + s.unrelayedPacketsOut = ret + return ret, err +} + +func (s *NaiveStrategyWrap) ProcessTimeoutPackets(ctx context.Context, src, dst *core.ProvableChain, sh core.SyncHeaders, rp *core.RelayPackets) error { + err := s.inner.ProcessTimeoutPackets(ctx, src, dst, sh, rp) + s.processTimeoutPacketsOut = rp + return err +} + +func (s *NaiveStrategyWrap) RelayPackets(ctx context.Context, src, dst *core.ProvableChain, rp *core.RelayPackets, sh core.SyncHeaders, doExecuteRelaySrc, doExecuteRelayDst bool) (*core.RelayMsgs, error) { + ret, err := s.inner.RelayPackets(ctx, src, dst, rp, sh, doExecuteRelaySrc, doExecuteRelayDst) + s.relayPacketsOut = ret + return ret, err +} +func (s *NaiveStrategyWrap) UnrelayedAcknowledgements(ctx context.Context, src, dst *core.ProvableChain, sh core.SyncHeaders, includeRelayedButUnfinalized bool) (*core.RelayPackets, error) { + ret, err := s.inner.UnrelayedAcknowledgements(ctx, src, dst, sh, includeRelayedButUnfinalized) + s.unrelayedAcknowledgementsOut = ret + return ret, err +} +func (s *NaiveStrategyWrap) RelayAcknowledgements(ctx context.Context, src, dst *core.ProvableChain, rp *core.RelayPackets, sh core.SyncHeaders, doExecuteAckSrc, doExecuteAckDst bool) (*core.RelayMsgs, error) { + ret, err := s.inner.RelayAcknowledgements(ctx, src, dst, rp, sh, doExecuteAckSrc, doExecuteAckDst) + s.relayAcknowledgementsOut = ret + return ret, err +} +func (s *NaiveStrategyWrap) UpdateClients(ctx context.Context, src, dst *core.ProvableChain, doExecuteRelaySrc, doExecuteRelayDst, doExecuteAckSrc, doExecuteAckDst bool, sh core.SyncHeaders, doRefresh bool) (*core.RelayMsgs, error) { + ret, err := s.inner.UpdateClients(ctx, src, dst, doExecuteRelaySrc, doExecuteRelayDst, doExecuteAckSrc, doExecuteAckDst, sh, doRefresh) + s.updateClientsOut = ret + return ret, err +} +func (s *NaiveStrategyWrap) Send(ctx context.Context, src, dst core.Chain, msgs *core.RelayMsgs) { + // format message object as string to be easily comparable + format := func(msgs []sdk.Msg) []string { + ret := []string{} + for _, msg := range msgs { + var desc string + switch m := msg.(type) { + case *clienttypes.MsgUpdateClient: + desc = fmt.Sprintf("MsgUpdateClient(%s)", m.ClientId) + case *chantypes.MsgRecvPacket: + desc = fmt.Sprintf("MsgRecvPacket(%v)", m.Packet.GetSequence()) + case *chantypes.MsgTimeout: + desc = fmt.Sprintf("MsgTimeout(%v)", m.Packet.GetSequence()) + default: + desc = fmt.Sprintf("%s()", reflect.TypeOf(msg).Elem().Name()) + } + ret = append(ret, desc) + } + return ret + } + s.sendInSrc = format(msgs.Src) + s.sendInDst = format(msgs.Dst) + s.inner.Send(ctx, src, dst, msgs) +} + +/** + * create mock ProvableChain with our MockProver and gomock's MockChain. + * about height: + * LatestHeight: 100 + * NextSequenceRecv: 20 + * LatestFinalizedHeight: 90 + * NextSequenceRecv: 10 + * Timestamp: height + 10000 + */ +var _CHAIN_STATE = struct { + latestHeader mocktypes.Header + finalityDelay uint64 + sequenceRecvs map[uint64]uint64 +}{ + latestHeader: mocktypes.Header{ + Height: clienttypes.NewHeight(1, 100), + Timestamp: uint64(10100), + }, + finalityDelay: 10, + sequenceRecvs: map[uint64]uint64{ //note that nextSequenceRecv is +1 + 100: 20, + 90: 10, + }, +} + +func NewMockProvableChain( + ctrl *gomock.Controller, + name, order string, + unfinalizedRelayPackets core.PacketInfoList, + unreceivedPackets []uint64, +) *core.ProvableChain { + chain := core.NewMockChain(ctrl) + prover := mock.NewProver(chain, mock.ProverConfig{FinalityDelay: _CHAIN_STATE.finalityDelay}) + + chain.EXPECT().ChainID().Return(name + "Chain").AnyTimes() + chain.EXPECT().Codec().Return(nil).AnyTimes() + chain.EXPECT().GetAddress().Return(sdk.AccAddress{}, nil).AnyTimes() + chain.EXPECT().Path().Return(&core.PathEnd{ + ChainID: name + "Chain", + ClientID: name + "Client", + ConnectionID: name + "Conn", + ChannelID: name + "Chan", + PortID: name + "Port", + Order: order, + Version: name + "Version", + }).AnyTimes() + chain.EXPECT().LatestHeight(gomock.Any()).Return(_CHAIN_STATE.latestHeader.Height, nil).AnyTimes() + chain.EXPECT().Timestamp(gomock.Any(), gomock.Any()).DoAndReturn( + func(ctx context.Context, h ibcexported.Height) (time.Time, error) { + return time.Unix(0, int64(10000+h.GetRevisionHeight())), nil + }).AnyTimes() + chain.EXPECT().QueryNextSequenceReceive(gomock.Any()).DoAndReturn( + func(ctx core.QueryContext) (*chantypes.QueryNextSequenceReceiveResponse, error) { + // get most recent sequence earlier than targetHeight + var lastHeight uint64 = 0 + var lastSequence uint64 = 0 + for h, s := range _CHAIN_STATE.sequenceRecvs { + if h <= ctx.Height().GetRevisionHeight() && lastHeight < h { + lastHeight = h + lastSequence = s + } + } + return &chantypes.QueryNextSequenceReceiveResponse{ + NextSequenceReceive: lastSequence + 1, + Proof: []byte{}, + ProofHeight: ctx.Height().(clienttypes.Height), + }, nil + }).AnyTimes() + chain.EXPECT().QueryUnfinalizedRelayPackets(gomock.Any(), gomock.Any()).Return(unfinalizedRelayPackets, nil).AnyTimes() + chain.EXPECT().QueryUnreceivedPackets(gomock.Any(), gomock.Any()).Return(unreceivedPackets, nil).AnyTimes() + chain.EXPECT().QueryUnreceivedAcknowledgements(gomock.Any(), gomock.Any()).Return([]uint64{}, nil).AnyTimes() + chain.EXPECT().QueryUnfinalizedRelayAcknowledgements(gomock.Any(), gomock.Any()).Return([]*core.PacketInfo{}, nil).AnyTimes() + chain.EXPECT().SendMsgs(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, msgs []sdk.Msg) ([]core.MsgID, error) { + var msgIDs []core.MsgID + for _, _ = range msgs { + msgIDs = append(msgIDs, &tendermint.MsgID{TxHash: "", MsgIndex: 0}) + } + return msgIDs, nil + }).AnyTimes() + return core.NewProvableChain(chain, prover) +} + +type testCase struct { + order string + optimizeCount uint64 + unfinalizedRelayPacketsSrc core.PacketInfoList + unfinalizedRelayPacketsDst core.PacketInfoList + expectSendSrc []string + expectSendDst []string +} + +func newPacketInfo(seq uint64, timeoutHeight uint64) *core.PacketInfo { + return &core.PacketInfo{ + Packet: chantypes.NewPacket( + []byte{}, + seq, + "srcPort", + "srcChannel", + "dstPort", + "dstChannel", + clienttypes.NewHeight(1, timeoutHeight), + 0, // timeoutTimestamp + ), + EventHeight: clienttypes.NewHeight(1, 1), + } +} + +func TestServe(t *testing.T) { + cases := map[string]testCase{ + "empty": { + "ORDERED", + 1, + []*core.PacketInfo{}, + []*core.PacketInfo{}, + []string{}, + []string{}, + }, + "single": { // all src packets are relayed to dst with leading UpdateClient message + "ORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(1, 9999), // note that nextSequenceRecv is not checked in relaying normal packets + }, + []*core.PacketInfo{}, + []string{}, + []string{ + "MsgUpdateClient(dstClient)", + "MsgRecvPacket(1)", + }, + }, + "multi": { // multiple packets. The rest is the same as the "single" case. + "ORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(1, 9999), + newPacketInfo(2, 9999), + newPacketInfo(3, 9999), + }, + []*core.PacketInfo{}, + []string{}, + []string{ + "MsgUpdateClient(dstClient)", + "MsgRecvPacket(1)", + "MsgRecvPacket(2)", + "MsgRecvPacket(3)", + }, + }, + "queued": { // packets less than optimizeCount are queed and not relayed + "ORDERED", + 9, + []*core.PacketInfo{ + newPacketInfo(1, 9999), + }, + []*core.PacketInfo{}, + []string{}, + []string{}, + }, + "not timeout(at border height)": { // An packet which timeouted at 101 are normally relayed at 100th block. + "ORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(1, 101), + }, + []*core.PacketInfo{}, + []string{}, + []string{ + "MsgUpdateClient(dstClient)", + "MsgRecvPacket(1)", + }, + }, + "timeout and previous packet is finalized": { // timeout. Relay back to src channel as MsgTimeout with UpdateClient. + "ORDERED", + 1, + []*core.PacketInfo{ + // timeout height of the packet is 90 and latest finalized height is 90. So it is timed out. + // nextSequenceRecv at finalized height(=90) is 11 in _STATE_CHAIN config. + newPacketInfo(11, 90), + }, + []*core.PacketInfo{}, + []string{"MsgUpdateClient(srcClient)", "MsgTimeout(11)"}, + []string{}, + }, + "timeout but previous packet is not finalized": { + "ORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(12, 90), + }, + []*core.PacketInfo{}, + []string{}, + []string{}, + }, + "timeout at latest block but not at finalized block(at lower border)": { // waiting relay in finalized block + "ORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(11, 91), + }, + []*core.PacketInfo{}, + []string{}, + []string{}, + }, + "timeout at latest block but not at finalized block(at heigher border)": { // waiting relay in finalized block + "ORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(11, 100), + }, + []*core.PacketInfo{}, + []string{}, + []string{}, + }, + "multiple timeouts packets in ordered channel": { // In ordered channel, later packets from timeouted packets are not relayerd + "ORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(11, 9), + newPacketInfo(12, 9999), + newPacketInfo(13, 9), + }, + []*core.PacketInfo{}, + []string{ + "MsgUpdateClient(srcClient)", + "MsgTimeout(11)", + }, + []string{}, + }, + "relay preceding packets before timeouted one": { // In ordered channel, only preceding packets before timeout packets are relayed. + "ORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(11, 9999), + newPacketInfo(12, 9999), + newPacketInfo(13, 9), + }, + []*core.PacketInfo{}, + []string{}, + []string{ + "MsgUpdateClient(dstClient)", + "MsgRecvPacket(11)", + "MsgRecvPacket(12)", + }, + }, + "multiple timeouts packets in ordered channel(both side)": { + "ORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(11, 9), + newPacketInfo(12, 9999), + newPacketInfo(13, 9), + }, + []*core.PacketInfo{ + newPacketInfo(11, 9999), + newPacketInfo(12, 9999), + newPacketInfo(13, 9), + }, + []string{ + "MsgUpdateClient(srcClient)", + "MsgRecvPacket(11)", + "MsgRecvPacket(12)", + "MsgTimeout(11)", + }, + []string{}, + }, + "multiple timeout packets in unordered channel": { // In unordered channel, all timeout packets are backed and others are relayed. + "UNORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(11, 9999), + newPacketInfo(12, 9), + newPacketInfo(13, 9999), + newPacketInfo(14, 9), + }, + []*core.PacketInfo{}, + []string{ + "MsgUpdateClient(srcClient)", + "MsgTimeout(12)", + "MsgTimeout(14)", + }, + []string{ + "MsgUpdateClient(dstClient)", + "MsgRecvPacket(11)", + "MsgRecvPacket(13)", + }, + }, + "multiple timeout packets in nordered channel(both side)": { // In unordered channel, all timeout packets are backed and others are relayed. + "UNORDERED", + 1, + []*core.PacketInfo{ + newPacketInfo(11, 9999), + newPacketInfo(12, 9), + newPacketInfo(13, 9999), + newPacketInfo(14, 9), + }, + []*core.PacketInfo{ + newPacketInfo(11, 9999), + newPacketInfo(12, 9), + newPacketInfo(13, 9999), + newPacketInfo(14, 9), + }, + []string{ + "MsgUpdateClient(srcClient)", + "MsgRecvPacket(11)", + "MsgRecvPacket(13)", + "MsgTimeout(12)", + "MsgTimeout(14)", + }, + []string{ + "MsgUpdateClient(dstClient)", + "MsgRecvPacket(11)", + "MsgRecvPacket(13)", + "MsgTimeout(12)", + "MsgTimeout(14)", + }, + }, + } + for n, c := range cases { + if n[0] == '_' { + continue + } + t.Run(n, func(t2 *testing.T) { testServe(t2, c) }) + } +} + +func testServe(t *testing.T, tc testCase) { + log.InitLoggerWithWriter("debug", "text", os.Stdout, false) + telemetry.InitializeMetrics() + + ctrl := gomock.NewController(t) + + var unreceivedPacketsSrc, unreceivedPacketsDst []uint64 + for _, p := range tc.unfinalizedRelayPacketsSrc { + unreceivedPacketsSrc = append(unreceivedPacketsSrc, p.Sequence) + } + for _, p := range tc.unfinalizedRelayPacketsDst { + unreceivedPacketsDst = append(unreceivedPacketsDst, p.Sequence) + } + src := NewMockProvableChain(ctrl, "src", tc.order, tc.unfinalizedRelayPacketsSrc, unreceivedPacketsDst) + dst := NewMockProvableChain(ctrl, "dst", tc.order, tc.unfinalizedRelayPacketsDst, unreceivedPacketsSrc) + + st := &NaiveStrategyWrap{inner: core.NewNaiveStrategy(false, false)} + sh, err := core.NewSyncHeaders(context.TODO(), src, dst) + if err != nil { + fmt.Printf("NewSyncHeders: %v\n", err) + } + var forever time.Duration = 1<<63 - 1 + srv := core.NewRelayService(st, src, dst, sh, time.Minute, forever, tc.optimizeCount, forever, tc.optimizeCount) + + srv.Serve(context.TODO()) + + t.Logf("UnrelayedPackets: %v\n", st.unrelayedPacketsOut) + t.Logf("UnrelayedAcknowledgementsOut: %v\n", st.unrelayedAcknowledgementsOut) + t.Logf("RelayPacketsOut: %v\n", st.relayPacketsOut) + t.Logf("RelayAcknowledgementsOut: %v\n", st.relayAcknowledgementsOut) + t.Logf("UpdateClientsOut: %v\n", st.updateClientsOut) + t.Logf("Send.Src: %v\n", st.sendInSrc) + t.Logf("Send.Dst: %v\n", st.sendInDst) + + assert.Equal(t, tc.expectSendSrc, st.sendInSrc, "Send.Src") + assert.Equal(t, tc.expectSendDst, st.sendInDst, "Send.Dst") +} diff --git a/core/strategies.go b/core/strategies.go index e070ab9a..0bd8b62c 100644 --- a/core/strategies.go +++ b/core/strategies.go @@ -24,6 +24,9 @@ type StrategyI interface { // `includeRelayedButUnfinalized` decides if the result includes packets of which acknowledgePacket has been executed but not finalized UnrelayedAcknowledgements(ctx context.Context, src, dst *ProvableChain, sh SyncHeaders, includeRelayedButUnfinalized bool) (*RelayPackets, error) + // ProcessTimeoutPackets processes timeout packets in given RelayPackets and returns sorted RelayPackets. Note that input Packet object may be modified. + ProcessTimeoutPackets(ctx context.Context, src, dst *ProvableChain, sh SyncHeaders, rp *RelayPackets) error + // RelayAcknowledgements executes AcknowledgePacket to the packets contained in `rp` on both chains (`src` and `dst`). RelayAcknowledgements(ctx context.Context, src, dst *ProvableChain, rp *RelayPackets, sh SyncHeaders, doExecuteAckSrc, doExecuteAckDst bool) (*RelayMsgs, error) diff --git a/core/types.go b/core/types.go index d5a520ed..c4efbe3c 100644 --- a/core/types.go +++ b/core/types.go @@ -13,6 +13,10 @@ type PacketInfo struct { chantypes.Packet Acknowledgement []byte `json:"acknowledgement"` EventHeight clienttypes.Height `json:"event_height"` + + // TimedOut indicates whether the packet has timed out. This is determined based on + // the absence of a corresponding acknowledgment or receipt within the expected timeframe. + TimedOut bool `json:"timed_out"` } // PacketInfoList represents a list of PacketInfo that is sorted in the order in which diff --git a/go.mod b/go.mod index 50656635..cac3206c 100644 --- a/go.mod +++ b/go.mod @@ -16,13 +16,15 @@ require ( github.com/cosmos/gogoproto v1.4.11 github.com/cosmos/ibc-go/modules/capability v1.0.0 github.com/cosmos/ibc-go/v8 v8.2.1 - github.com/datachainlab/ibc-mock-client v0.4.2 + github.com/datachainlab/ibc-mock-client v0.4.3 github.com/prometheus/client_golang v1.20.5 github.com/samber/slog-multi v1.4.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 + github.com/stretchr/testify v1.10.0 go.opentelemetry.io/contrib/bridges/otelslog v0.10.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 go.opentelemetry.io/otel v1.35.0 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.11.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 @@ -37,6 +39,7 @@ require ( go.opentelemetry.io/otel/sdk/log v0.11.0 go.opentelemetry.io/otel/sdk/metric v1.35.0 go.opentelemetry.io/otel/trace v1.35.0 + go.uber.org/mock v0.5.0 golang.org/x/sync v0.11.0 golang.org/x/sys v0.30.0 google.golang.org/grpc v1.71.0 @@ -176,7 +179,6 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect - github.com/stretchr/testify v1.10.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect @@ -188,7 +190,6 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/multierr v1.10.0 // indirect diff --git a/go.sum b/go.sum index c9617991..be5864fd 100644 --- a/go.sum +++ b/go.sum @@ -377,8 +377,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= -github.com/datachainlab/ibc-mock-client v0.4.2 h1:0BbQFwLUUbKknCsUO6m80VogRbJop5kA0u9/3Hma9n0= -github.com/datachainlab/ibc-mock-client v0.4.2/go.mod h1:Fn37FzeevLp5gmla4TSoDY56Jm2tBcqz+p0lIyRCOsg= +github.com/datachainlab/ibc-mock-client v0.4.3 h1:vFl8P4lx0aAgvnZIMfmwhDcj8atps1aP+sthzKdVNo8= +github.com/datachainlab/ibc-mock-client v0.4.3/go.mod h1:Fn37FzeevLp5gmla4TSoDY56Jm2tBcqz+p0lIyRCOsg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -1107,6 +1107,8 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= 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=