Skip to content

Commit c0456f8

Browse files
chore: Revert #6782 (#8137)
* Revert "chore: remove legacy proposal types. (#6782)" This reverts commit e76766a. * move legacy proposal out from proto file * add back UpgradeProposal * Change error expected * revert client proto file --------- Co-authored-by: Gjermund Garaba <gjermund@garaba.net>
1 parent d316a8b commit c0456f8

File tree

8 files changed

+1113
-3
lines changed

8 files changed

+1113
-3
lines changed

e2e/tests/core/02-client/client_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ func (s *ClientTestSuite) TestScheduleIBCUpgrade_Succeeds() {
7474
chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
7575

7676
const planHeight = int64(300)
77+
const legacyPlanHeight = planHeight * 2
7778
var newChainID string
7879

7980
t.Run("execute proposal for MsgIBCSoftwareUpgrade", func(t *testing.T) {
@@ -131,6 +132,34 @@ func (s *ClientTestSuite) TestScheduleIBCUpgrade_Succeeds() {
131132
s.Require().Equal("upgrade-client", plan.Name)
132133
s.Require().Equal(planHeight, plan.Height)
133134
})
135+
136+
t.Run("ensure legacy proposal does not succeed", func(t *testing.T) {
137+
authority, err := query.ModuleAccountAddress(ctx, govtypes.ModuleName, chainA)
138+
s.Require().NoError(err)
139+
s.Require().NotNil(authority)
140+
141+
clientState, err := query.ClientState(ctx, chainB, ibctesting.FirstClientID)
142+
s.Require().NoError(err)
143+
144+
originalChainID := clientState.(*ibctm.ClientState).ChainId
145+
revisionNumber := clienttypes.ParseChainID(originalChainID)
146+
// increment revision number even with new chain ID to prevent loss of misbehaviour detection support
147+
newChainID, err = clienttypes.SetRevisionNumber(originalChainID, revisionNumber+1)
148+
s.Require().NoError(err)
149+
s.Require().NotEqual(originalChainID, newChainID)
150+
151+
upgradedClientState := clientState.(*ibctm.ClientState).ZeroCustomFields()
152+
upgradedClientState.ChainId = newChainID
153+
154+
legacyUpgradeProposal, err := clienttypes.NewUpgradeProposal(ibctesting.Title, ibctesting.Description, upgradetypes.Plan{
155+
Name: "upgrade-client-legacy",
156+
Height: legacyPlanHeight,
157+
}, upgradedClientState)
158+
159+
s.Require().NoError(err)
160+
txResp := s.ExecuteGovV1Beta1Proposal(ctx, chainA, chainAWallet, legacyUpgradeProposal)
161+
s.AssertTxFailure(txResp, govtypes.ErrInvalidProposalType)
162+
})
134163
}
135164

136165
// TestRecoverClient_Succeeds tests that a governance proposal to recover a client using a MsgRecoverClient is successful.

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ require (
177177
go.opentelemetry.io/otel/trace v1.31.0 // indirect
178178
go.uber.org/multierr v1.11.0 // indirect
179179
golang.org/x/crypto v0.28.0 // indirect
180-
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect
180+
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
181181
golang.org/x/net v0.30.0 // indirect
182182
golang.org/x/oauth2 v0.23.0 // indirect
183183
golang.org/x/sync v0.8.0 // indirect

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -1055,8 +1055,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
10551055
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
10561056
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
10571057
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
1058-
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8=
1059-
golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
1058+
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
1059+
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
10601060
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
10611061
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
10621062
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=

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

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
99
sdk "github.com/cosmos/cosmos-sdk/types"
1010
"github.com/cosmos/cosmos-sdk/types/msgservice"
11+
govtypesv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
1112

1213
ibcerrors "github.com/cosmos/ibc-go/v10/modules/core/errors"
1314
"github.com/cosmos/ibc-go/v10/modules/core/exported"
@@ -46,6 +47,11 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
4647
&MsgIBCSoftwareUpgrade{},
4748
&MsgUpdateParams{},
4849
)
50+
registry.RegisterImplementations(
51+
(*govtypesv1beta1.Content)(nil),
52+
&ClientUpdateProposal{},
53+
&UpgradeProposal{},
54+
)
4955

5056
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
5157
}

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

+10
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,16 @@ func (suite *TypesTestSuite) TestCodecTypeRegistration() {
214214
sdk.MsgTypeURL(&types.MsgUpdateParams{}),
215215
nil,
216216
},
217+
{
218+
"success: ClientUpdateProposal",
219+
sdk.MsgTypeURL(&types.ClientUpdateProposal{}),
220+
nil,
221+
},
222+
{
223+
"success: UpgradeProposal",
224+
sdk.MsgTypeURL(&types.UpgradeProposal{}),
225+
nil,
226+
},
217227
{
218228
"type not registered on codec",
219229
"ibc.invalid.MsgTypeURL",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package types
2+
3+
import (
4+
"fmt"
5+
6+
errorsmod "cosmossdk.io/errors"
7+
upgradetypes "cosmossdk.io/x/upgrade/types"
8+
9+
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
10+
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
11+
12+
"github.com/cosmos/ibc-go/v10/modules/core/exported"
13+
)
14+
15+
const (
16+
// ProposalTypeClientUpdate defines the type for a ClientUpdateProposal
17+
ProposalTypeClientUpdate = "ClientUpdate"
18+
// ProposalTypeUpgrade defines the type for an UpgradeProposal
19+
ProposalTypeUpgrade = "IBCUpgrade"
20+
)
21+
22+
var (
23+
_ govtypes.Content = &ClientUpdateProposal{}
24+
_ govtypes.Content = &UpgradeProposal{}
25+
_ codectypes.UnpackInterfacesMessage = &UpgradeProposal{}
26+
)
27+
28+
// func init() {
29+
// govtypes.RegisterProposalType(ProposalTypeClientUpdate)
30+
// govtypes.RegisterProposalType(ProposalTypeUpgrade)
31+
// }
32+
33+
// NewClientUpdateProposal creates a new client update proposal.
34+
//
35+
// Deprecated: The legacy v1beta1 gov ClientUpdateProposal is deprecated
36+
// and will be removed in a future release. Please use MsgRecoverClient instead.
37+
func NewClientUpdateProposal(title, description, subjectClientID, substituteClientID string) govtypes.Content {
38+
return &ClientUpdateProposal{
39+
Title: title,
40+
Description: description,
41+
SubjectClientId: subjectClientID,
42+
SubstituteClientId: substituteClientID,
43+
}
44+
}
45+
46+
// GetTitle returns the title of a client update proposal.
47+
func (cup *ClientUpdateProposal) GetTitle() string { return cup.Title }
48+
49+
// GetDescription returns the description of a client update proposal.
50+
func (cup *ClientUpdateProposal) GetDescription() string { return cup.Description }
51+
52+
// ProposalRoute returns the routing key of a client update proposal.
53+
func (*ClientUpdateProposal) ProposalRoute() string { return RouterKey }
54+
55+
// ProposalType returns the type of a client update proposal.
56+
func (*ClientUpdateProposal) ProposalType() string { return ProposalTypeClientUpdate }
57+
58+
// ValidateBasic runs basic stateless validity checks
59+
func (cup *ClientUpdateProposal) ValidateBasic() error {
60+
err := govtypes.ValidateAbstract(cup)
61+
if err != nil {
62+
return err
63+
}
64+
65+
if cup.SubjectClientId == cup.SubstituteClientId {
66+
return errorsmod.Wrap(ErrInvalidSubstitute, "subject and substitute client identifiers are equal")
67+
}
68+
if _, _, err := ParseClientIdentifier(cup.SubjectClientId); err != nil {
69+
return err
70+
}
71+
if _, _, err := ParseClientIdentifier(cup.SubstituteClientId); err != nil {
72+
return err
73+
}
74+
75+
return nil
76+
}
77+
78+
// NewUpgradeProposal creates a new IBC breaking upgrade proposal.
79+
//
80+
// Deprecated: The legacy v1beta1 gov UpgradeProposal is deprecated
81+
// and will be removed in a future release. Please use MsgIBCSoftwareUpgrade instead.
82+
func NewUpgradeProposal(title, description string, plan upgradetypes.Plan, upgradedClientState exported.ClientState) (govtypes.Content, error) {
83+
clientAny, err := PackClientState(upgradedClientState)
84+
if err != nil {
85+
return nil, err
86+
}
87+
88+
return &UpgradeProposal{
89+
Title: title,
90+
Description: description,
91+
Plan: plan,
92+
UpgradedClientState: clientAny,
93+
}, nil
94+
}
95+
96+
// GetTitle returns the title of a upgrade proposal.
97+
func (up *UpgradeProposal) GetTitle() string { return up.Title }
98+
99+
// GetDescription returns the description of a upgrade proposal.
100+
func (up *UpgradeProposal) GetDescription() string { return up.Description }
101+
102+
// ProposalRoute returns the routing key of a upgrade proposal.
103+
func (*UpgradeProposal) ProposalRoute() string { return RouterKey }
104+
105+
// ProposalType returns the upgrade proposal type.
106+
func (*UpgradeProposal) ProposalType() string { return ProposalTypeUpgrade }
107+
108+
// ValidateBasic runs basic stateless validity checks
109+
func (up *UpgradeProposal) ValidateBasic() error {
110+
if err := govtypes.ValidateAbstract(up); err != nil {
111+
return err
112+
}
113+
114+
if err := up.Plan.ValidateBasic(); err != nil {
115+
return err
116+
}
117+
118+
if up.UpgradedClientState == nil {
119+
return errorsmod.Wrap(ErrInvalidUpgradeProposal, "upgraded client state cannot be nil")
120+
}
121+
122+
_, err := UnpackClientState(up.UpgradedClientState)
123+
if err != nil {
124+
return errorsmod.Wrap(err, "failed to unpack upgraded client state")
125+
}
126+
127+
return nil
128+
}
129+
130+
// String returns the string representation of the UpgradeProposal.
131+
func (up UpgradeProposal) String() string {
132+
var upgradedClientStr string
133+
upgradedClient, err := UnpackClientState(up.UpgradedClientState)
134+
if err != nil {
135+
upgradedClientStr = "invalid IBC Client State"
136+
} else {
137+
upgradedClientStr = upgradedClient.String()
138+
}
139+
140+
return fmt.Sprintf(`IBC Upgrade Proposal
141+
Title: %s
142+
Description: %s
143+
%s
144+
Upgraded IBC Client: %s`, up.Title, up.Description, up.Plan.String(), upgradedClientStr)
145+
}
146+
147+
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
148+
func (up UpgradeProposal) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
149+
return unpacker.UnpackAny(up.UpgradedClientState, new(exported.ClientState))
150+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package types_test
2+
3+
import (
4+
"github.com/cosmos/cosmos-sdk/codec"
5+
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
6+
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
7+
8+
"github.com/cosmos/ibc-go/v10/modules/core/02-client/types"
9+
ibctesting "github.com/cosmos/ibc-go/v10/testing"
10+
)
11+
12+
func (suite *TypesTestSuite) TestValidateBasic() {
13+
subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB)
14+
subjectPath.SetupClients()
15+
subject := subjectPath.EndpointA.ClientID
16+
17+
substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB)
18+
substitutePath.SetupClients()
19+
substitute := substitutePath.EndpointA.ClientID
20+
21+
testCases := []struct {
22+
name string
23+
proposal govtypes.Content
24+
expPass bool
25+
}{
26+
{
27+
"success",
28+
types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, substitute),
29+
true,
30+
},
31+
{
32+
"fails validate abstract - empty title",
33+
types.NewClientUpdateProposal("", ibctesting.Description, subject, substitute),
34+
false,
35+
},
36+
{
37+
"subject and substitute use the same identifier",
38+
types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, subject),
39+
false,
40+
},
41+
{
42+
"invalid subject clientID",
43+
types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, ibctesting.InvalidID, substitute),
44+
false,
45+
},
46+
{
47+
"invalid substitute clientID",
48+
types.NewClientUpdateProposal(ibctesting.Title, ibctesting.Description, subject, ibctesting.InvalidID),
49+
false,
50+
},
51+
}
52+
53+
for _, tc := range testCases {
54+
55+
err := tc.proposal.ValidateBasic()
56+
57+
if tc.expPass {
58+
suite.Require().NoError(err, tc.name)
59+
} else {
60+
suite.Require().Error(err, tc.name)
61+
}
62+
}
63+
}
64+
65+
// tests a client update proposal can be marshaled and unmarshaled
66+
func (suite *TypesTestSuite) TestMarshalClientUpdateProposalProposal() {
67+
// create proposal
68+
proposal := types.NewClientUpdateProposal("update IBC client", "description", "subject", "substitute")
69+
70+
// create codec
71+
ir := codectypes.NewInterfaceRegistry()
72+
types.RegisterInterfaces(ir)
73+
govtypes.RegisterInterfaces(ir)
74+
cdc := codec.NewProtoCodec(ir)
75+
76+
// marshal message
77+
content, ok := proposal.(*types.ClientUpdateProposal)
78+
suite.Require().True(ok)
79+
bz, err := cdc.MarshalJSON(content)
80+
suite.Require().NoError(err)
81+
82+
// unmarshal proposal
83+
newProposal := &types.ClientUpdateProposal{}
84+
err = cdc.UnmarshalJSON(bz, newProposal)
85+
suite.Require().NoError(err)
86+
}

0 commit comments

Comments
 (0)