Skip to content

Commit 5296070

Browse files
feat: clientv2 module (#7936)
* init * move logic * fix all tests and types * genesis proto and gen * gen * godoc * core genesis * core genesis wiring * wire and test * lint fix * fmt * fmt * add defensive checks * fix all --------- Co-authored-by: Aditya <[email protected]>
1 parent ec66b11 commit 5296070

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2827
-569
lines changed

modules/core/02-client/keeper/keeper.go

-19
Original file line numberDiff line numberDiff line change
@@ -142,25 +142,6 @@ func (k *Keeper) DeleteClientCreator(ctx context.Context, clientID string) {
142142
store.Delete(types.CreatorKey())
143143
}
144144

145-
// SetClientCounterparty sets counterpartyInfo for a given clientID
146-
func (k *Keeper) SetClientCounterparty(ctx context.Context, clientID string, counterparty types.CounterpartyInfo) {
147-
store := k.ClientStore(ctx, clientID)
148-
store.Set(types.CounterpartyKey(), k.cdc.MustMarshal(&counterparty))
149-
}
150-
151-
// GetClientCounterparty gets counterpartyInfo for a given clientID
152-
func (k *Keeper) GetClientCounterparty(ctx context.Context, clientID string) (types.CounterpartyInfo, bool) {
153-
store := k.ClientStore(ctx, clientID)
154-
bz := store.Get(types.CounterpartyKey())
155-
if len(bz) == 0 {
156-
return types.CounterpartyInfo{}, false
157-
}
158-
159-
var counterparty types.CounterpartyInfo
160-
k.cdc.MustUnmarshal(bz, &counterparty)
161-
return counterparty, true
162-
}
163-
164145
// GetClientConsensusState gets the stored consensus state from a client at a given height.
165146
func (k *Keeper) GetClientConsensusState(ctx context.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) {
166147
store := k.ClientStore(ctx, clientID)

modules/core/02-client/keeper/keeper_test.go

-9
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,6 @@ func (suite *KeeperTestSuite) TestSetClientCreator() {
139139
suite.Require().Equal(sdk.AccAddress(nil), getCreator)
140140
}
141141

142-
func (suite *KeeperTestSuite) TestSetClientCounterparty() {
143-
counterparty := types.NewCounterpartyInfo([][]byte{[]byte("ibc"), []byte("channel-7")}, testClientID2)
144-
suite.keeper.SetClientCounterparty(suite.ctx, testClientID, counterparty)
145-
146-
retrievedCounterparty, found := suite.keeper.GetClientCounterparty(suite.ctx, testClientID)
147-
suite.Require().True(found, "GetCounterparty failed")
148-
suite.Require().Equal(counterparty, retrievedCounterparty, "Counterparties are not equal")
149-
}
150-
151142
func (suite *KeeperTestSuite) TestSetClientConsensusState() {
152143
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState)
153144

modules/core/02-client/types/codec.go

-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
4545
&MsgRecoverClient{},
4646
&MsgIBCSoftwareUpgrade{},
4747
&MsgUpdateParams{},
48-
&MsgRegisterCounterparty{},
4948
)
5049

5150
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)

modules/core/02-client/types/errors.go

-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,4 @@ var (
3838
ErrFailedNonMembershipVerification = errorsmod.Register(SubModuleName, 31, "non-membership verification failed")
3939
ErrRouteNotFound = errorsmod.Register(SubModuleName, 32, "light client module route not found")
4040
ErrClientTypeNotSupported = errorsmod.Register(SubModuleName, 33, "client type not supported")
41-
ErrInvalidCounterparty = errorsmod.Register(SubModuleName, 34, "invalid counterparty")
42-
ErrCounterpartyNotFound = errorsmod.Register(SubModuleName, 35, "counterparty not found")
4341
)

modules/core/02-client/types/genesis.go

-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ func (gs GenesisState) Validate() error {
116116
}
117117

118118
validClients := make(map[string]string)
119-
120119
for i, client := range gs.Clients {
121120
if err := host.ClientIdentifierValidator(client.ClientId); err != nil {
122121
return fmt.Errorf("invalid client consensus state identifier %s index %d: %w", client.ClientId, i, err)

modules/core/02-client/types/keys.go

-8
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ const (
3232
// KeyCreator is the key for the creator in the client-specific store
3333
KeyCreator = "creator"
3434

35-
// KeyCounterparty is the key for the counterpartyInfo in the client-specific store
36-
KeyCounterparty = "counterparty"
37-
3835
// AllowAllClients is the value that if set in AllowedClients param
3936
// would allow any wired up light client modules to be allowed
4037
AllowAllClients = "*"
@@ -102,8 +99,3 @@ func MustParseClientIdentifier(clientID string) string {
10299
func CreatorKey() []byte {
103100
return []byte(KeyCreator)
104101
}
105-
106-
// CounterpartyKey returns the key under which the counterparty is stored in the client store
107-
func CounterpartyKey() []byte {
108-
return []byte(KeyCounterparty)
109-
}

modules/core/02-client/types/msgs.go

-27
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,13 @@ var (
2121
_ sdk.Msg = (*MsgIBCSoftwareUpgrade)(nil)
2222
_ sdk.Msg = (*MsgRecoverClient)(nil)
2323

24-
_ sdk.Msg = (*MsgRegisterCounterparty)(nil)
25-
2624
_ sdk.HasValidateBasic = (*MsgCreateClient)(nil)
2725
_ sdk.HasValidateBasic = (*MsgUpdateClient)(nil)
2826
_ sdk.HasValidateBasic = (*MsgSubmitMisbehaviour)(nil)
2927
_ sdk.HasValidateBasic = (*MsgUpgradeClient)(nil)
3028
_ sdk.HasValidateBasic = (*MsgUpdateParams)(nil)
3129
_ sdk.HasValidateBasic = (*MsgIBCSoftwareUpgrade)(nil)
3230
_ sdk.HasValidateBasic = (*MsgRecoverClient)(nil)
33-
_ sdk.HasValidateBasic = (*MsgRegisterCounterparty)(nil)
3431

3532
_ codectypes.UnpackInterfacesMessage = (*MsgCreateClient)(nil)
3633
_ codectypes.UnpackInterfacesMessage = (*MsgUpdateClient)(nil)
@@ -321,27 +318,3 @@ func (msg *MsgUpdateParams) ValidateBasic() error {
321318
}
322319
return msg.Params.Validate()
323320
}
324-
325-
// NewMsgRegisterCounterparty creates a new instance of MsgRegisterCounterparty.
326-
func NewMsgRegisterCounterparty(clientID string, merklePrefix [][]byte, counterpartyClientID string, signer string) *MsgRegisterCounterparty {
327-
return &MsgRegisterCounterparty{
328-
ClientId: clientID,
329-
CounterpartyMerklePrefix: merklePrefix,
330-
CounterpartyClientId: counterpartyClientID,
331-
Signer: signer,
332-
}
333-
}
334-
335-
// ValidateBasic performs basic checks on a MsgRegisterCounterparty.
336-
func (msg *MsgRegisterCounterparty) ValidateBasic() error {
337-
if _, err := sdk.AccAddressFromBech32(msg.Signer); err != nil {
338-
return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err)
339-
}
340-
if len(msg.CounterpartyMerklePrefix) == 0 {
341-
return errorsmod.Wrap(ErrInvalidCounterparty, "counterparty messaging key cannot be empty")
342-
}
343-
if err := host.ClientIdentifierValidator(msg.ClientId); err != nil {
344-
return err
345-
}
346-
return host.ClientIdentifierValidator(msg.CounterpartyClientId)
347-
}

modules/core/02-client/types/msgs_test.go

-71
Original file line numberDiff line numberDiff line change
@@ -978,74 +978,3 @@ func TestMsgUpdateParamsGetSigners(t *testing.T) {
978978
}
979979
}
980980
}
981-
982-
func TestMsgRegisterCounterpartyValidateBasic(t *testing.T) {
983-
signer := ibctesting.TestAccAddress
984-
testCases := []struct {
985-
name string
986-
msg *types.MsgRegisterCounterparty
987-
expError error
988-
}{
989-
{
990-
"success",
991-
types.NewMsgRegisterCounterparty(
992-
"testclientid",
993-
[][]byte{[]byte("ibc"), []byte("channel-9")},
994-
"testclientid3",
995-
signer,
996-
),
997-
nil,
998-
},
999-
{
1000-
"failure: empty client id",
1001-
types.NewMsgRegisterCounterparty(
1002-
"",
1003-
[][]byte{[]byte("ibc"), []byte("channel-9")},
1004-
"testclientid3",
1005-
signer,
1006-
),
1007-
host.ErrInvalidID,
1008-
},
1009-
{
1010-
"failure: empty counterparty client id",
1011-
types.NewMsgRegisterCounterparty(
1012-
"testclientid",
1013-
[][]byte{[]byte("ibc"), []byte("channel-9")},
1014-
"",
1015-
signer,
1016-
),
1017-
host.ErrInvalidID,
1018-
},
1019-
{
1020-
"failure: empty counterparty messaging key",
1021-
types.NewMsgRegisterCounterparty(
1022-
"testclientid",
1023-
[][]byte{},
1024-
"testclientid3",
1025-
signer,
1026-
),
1027-
types.ErrInvalidCounterparty,
1028-
},
1029-
{
1030-
"failure: empty signer",
1031-
types.NewMsgRegisterCounterparty(
1032-
"testclientid",
1033-
[][]byte{[]byte("ibc"), []byte("channel-9")},
1034-
"testclientid3",
1035-
"badsigner",
1036-
),
1037-
ibcerrors.ErrInvalidAddress,
1038-
},
1039-
}
1040-
for _, tc := range testCases {
1041-
tc := tc
1042-
t.Run(tc.name, func(t *testing.T) {
1043-
err := tc.msg.ValidateBasic()
1044-
if tc.expError == nil {
1045-
require.NoError(t, err)
1046-
} else {
1047-
require.ErrorIs(t, err, tc.expError)
1048-
}
1049-
})
1050-
}
1051-
}

modules/core/02-client/v2/genesis.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package clientv2
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
sdk "github.com/cosmos/cosmos-sdk/types"
8+
9+
"github.com/cosmos/ibc-go/v9/modules/core/02-client/v2/keeper"
10+
"github.com/cosmos/ibc-go/v9/modules/core/02-client/v2/types"
11+
)
12+
13+
// InitGenesis initializes the ibc client/v2 submodule's state from a provided genesis
14+
// state.
15+
func InitGenesis(ctx context.Context, k *keeper.Keeper, gs types.GenesisState) {
16+
sdkCtx := sdk.UnwrapSDKContext(ctx)
17+
18+
if err := gs.Validate(); err != nil {
19+
panic(fmt.Errorf("invalid genesis state: %w", err))
20+
}
21+
22+
for _, info := range gs.CounterpartyInfos {
23+
k.SetClientCounterparty(sdkCtx, info.ClientId, info.CounterpartyInfo)
24+
}
25+
}
26+
27+
// ExportGenesis returns the ibc client/v2 submodule's exported genesis.
28+
func ExportGenesis(ctx context.Context, k *keeper.Keeper) types.GenesisState {
29+
sdkCtx := sdk.UnwrapSDKContext(ctx)
30+
31+
clients := k.ClientV1Keeper.GetAllGenesisClients(ctx)
32+
gs := types.GenesisState{
33+
CounterpartyInfos: make([]types.GenesisCounterpartyInfo, 0),
34+
}
35+
for _, client := range clients {
36+
counterpartyInfo, found := k.GetClientCounterparty(sdkCtx, client.ClientId)
37+
if found {
38+
gs.CounterpartyInfos = append(gs.CounterpartyInfos, types.GenesisCounterpartyInfo{
39+
ClientId: client.ClientId,
40+
CounterpartyInfo: counterpartyInfo,
41+
})
42+
}
43+
}
44+
45+
return gs
46+
}
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package clientv2_test
2+
3+
import (
4+
clientv2 "github.com/cosmos/ibc-go/v9/modules/core/02-client/v2"
5+
"github.com/cosmos/ibc-go/v9/modules/core/02-client/v2/types"
6+
ibctesting "github.com/cosmos/ibc-go/v9/testing"
7+
)
8+
9+
// TestInitExportGenesis tests the import and export flow for the channel v2 keeper.
10+
func (suite *ModuleTestSuite) TestInitExportGenesis() {
11+
path := ibctesting.NewPath(suite.chainA, suite.chainB)
12+
path.SetupV2()
13+
14+
path2 := ibctesting.NewPath(suite.chainA, suite.chainC)
15+
path2.SetupV2()
16+
17+
path3 := ibctesting.NewPath(suite.chainB, suite.chainC)
18+
path3.SetupV2()
19+
20+
app := suite.chainA.App
21+
22+
emptyGenesis := types.DefaultGenesisState()
23+
24+
// create a valid genesis state that uses the counterparty info set during setup
25+
existingGS := clientv2.ExportGenesis(suite.chainA.GetContext(), app.GetIBCKeeper().ClientV2Keeper)
26+
27+
tests := []struct {
28+
name string
29+
genState types.GenesisState
30+
expectedState types.GenesisState
31+
}{
32+
{
33+
name: "no modifications genesis",
34+
genState: emptyGenesis,
35+
expectedState: existingGS,
36+
},
37+
{
38+
name: "valid - default genesis",
39+
genState: types.DefaultGenesisState(),
40+
expectedState: existingGS,
41+
},
42+
}
43+
44+
for _, tt := range tests {
45+
suite.Run(tt.name, func() {
46+
clientV2Keeper := app.GetIBCKeeper().ClientV2Keeper
47+
48+
clientv2.InitGenesis(suite.chainA.GetContext(), clientV2Keeper, tt.genState)
49+
50+
exported := clientv2.ExportGenesis(suite.chainA.GetContext(), clientV2Keeper)
51+
suite.Require().Equal(tt.expectedState, exported)
52+
})
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package keeper
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"google.golang.org/grpc/codes"
8+
"google.golang.org/grpc/status"
9+
10+
sdk "github.com/cosmos/cosmos-sdk/types"
11+
12+
"github.com/cosmos/ibc-go/v9/modules/core/02-client/v2/types"
13+
host "github.com/cosmos/ibc-go/v9/modules/core/24-host"
14+
)
15+
16+
var _ types.QueryServer = (*queryServer)(nil)
17+
18+
// queryServer implements the 02-client/v2 types.QueryServer interface.
19+
// It embeds the client keeper to leverage store access while limiting the api of the client keeper.
20+
type queryServer struct {
21+
*Keeper
22+
}
23+
24+
// NewQueryServer returns a new 02-client/v2 types.QueryServer implementation.
25+
func NewQueryServer(k *Keeper) types.QueryServer {
26+
return &queryServer{
27+
Keeper: k,
28+
}
29+
}
30+
31+
// CounterpartyInfo gets the CounterpartyInfo from the store corresponding to the request client ID.
32+
func (q queryServer) CounterpartyInfo(ctx context.Context, req *types.QueryCounterpartyInfoRequest) (*types.QueryCounterpartyInfoResponse, error) {
33+
if req == nil {
34+
return nil, status.Error(codes.InvalidArgument, "empty request")
35+
}
36+
37+
if err := host.ClientIdentifierValidator(req.ClientId); err != nil {
38+
return nil, status.Error(codes.InvalidArgument, err.Error())
39+
}
40+
41+
sdkCtx := sdk.UnwrapSDKContext(ctx)
42+
43+
info, found := q.GetClientCounterparty(sdkCtx, req.ClientId)
44+
if !found {
45+
return nil, status.Error(codes.NotFound, fmt.Sprintf("client %s counterparty not found", req.ClientId))
46+
}
47+
48+
return &types.QueryCounterpartyInfoResponse{CounterpartyInfo: &info}, nil
49+
}

0 commit comments

Comments
 (0)