Skip to content

Commit b4766b0

Browse files
fix(statemachine)!: use path within IBC store without escaping characters in solomachine (backport #4429) (#4453)
* fix(statemachine)!: use key within IBC store without escaping characters in solomachine (#4429) (cherry picked from commit 98b0c99) # Conflicts: # modules/light-clients/06-solomachine/client_state.go # modules/light-clients/07-tendermint/upgrade.go * fix conflicts * fix package usage * use sdkerrors * add changelog * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md --------- Co-authored-by: Carlos Rodriguez <[email protected]>
1 parent 812a364 commit b4766b0

File tree

7 files changed

+131
-36
lines changed

7 files changed

+131
-36
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ Ref: https://keepachangelog.com/en/1.0.0/
4747
### Improvements
4848

4949
* [\#4187](https://github.com/cosmos/ibc-go/pull/4187) Adds function 'WithICS4Wrapper' to keepers to allow to set the middleware after the keeper's creation.
50+
* (light-clients/06-solomachine) [\#4429](https://github.com/cosmos/ibc-go/pull/4429) Remove IBC key from path of bytes signed by solomachine and not escape the path.
5051

5152
### Features
5253

53-
* [\#3796](https://github.com/cosmos/ibc-go/pull/3796) Adds support for json tx encoding for interchain accounts.
54+
* (apps/27-interchain-accounts) [\#3796](https://github.com/cosmos/ibc-go/pull/3796) Adds support for json tx encoding for interchain accounts.
5455
* [\#4188](https://github.com/cosmos/ibc-go/pull/4188) Adds optional `PacketDataUnmarshaler` interface that allows a middleware to request the packet data to be unmarshaled by the base application.
5556
* [\#4199](https://github.com/cosmos/ibc-go/pull/4199) Adds optional `PacketDataProvider` interface for retrieving custom packet data stored on behalf of another application.
5657
* [\#4200](https://github.com/cosmos/ibc-go/pull/4200) Adds optional `PacketData` interface which application's packet data may implement.

modules/core/23-commitment/types/merkle.go

+13-6
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ func NewMerklePath(keyPath ...string) MerklePath {
7979
// This represents the path in the same way the tendermint KeyPath will
8080
// represent a key path. The backslashes partition the key path into
8181
// the respective stores they belong to.
82+
//
83+
// Deprecated: This function makes assumptions about the way a merkle path
84+
// in a multistore should be represented as a string that are not standardized.
85+
// The decision on how to represent the merkle path as a string will be deferred
86+
// to upstream users of the type.
87+
// This function will be removed in a next release.
8288
func (mp MerklePath) String() string {
8389
pathStr := ""
8490
for _, k := range mp.KeyPath {
@@ -91,6 +97,12 @@ func (mp MerklePath) String() string {
9197
// This function will unescape any backslash within a particular store key.
9298
// This makes the keypath more human-readable while removing information
9399
// about the exact partitions in the key path.
100+
//
101+
// Deprecated: This function makes assumptions about the way a merkle path
102+
// in a multistore should be represented as a string that are not standardized.
103+
// The decision on how to represent the merkle path as a string will be deferred
104+
// to upstream users of the type.
105+
// This function will be removed in a next release.
94106
func (mp MerklePath) Pretty() string {
95107
path, err := url.PathUnescape(mp.String())
96108
if err != nil {
@@ -100,16 +112,11 @@ func (mp MerklePath) Pretty() string {
100112
}
101113

102114
// GetKey will return a byte representation of the key
103-
// after URL escaping the key element
104115
func (mp MerklePath) GetKey(i uint64) ([]byte, error) {
105116
if i >= uint64(len(mp.KeyPath)) {
106117
return nil, fmt.Errorf("index out of range. %d (index) >= %d (len)", i, len(mp.KeyPath))
107118
}
108-
key, err := url.PathUnescape(mp.KeyPath[i])
109-
if err != nil {
110-
return nil, err
111-
}
112-
return []byte(key), nil
119+
return []byte(mp.KeyPath[i]), nil
113120
}
114121

115122
// Empty returns true if the path is empty

modules/core/exported/commitment.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type Prefix interface {
2828
// Path implements spec:CommitmentPath.
2929
// A path is the additional information provided to the verification function.
3030
type Path interface {
31-
String() string
31+
String() string // deprecated
3232
Empty() bool
3333
}
3434

modules/light-clients/06-solomachine/client_state.go

+20-4
Original file line numberDiff line numberDiff line change
@@ -125,15 +125,21 @@ func (cs *ClientState) VerifyMembership(
125125
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", commitmenttypes.MerklePath{}, path)
126126
}
127127

128-
if merklePath.Empty() {
129-
return sdkerrors.Wrap(commitmenttypes.ErrInvalidProof, "path is empty")
128+
if len(merklePath.GetKeyPath()) != 2 {
129+
return sdkerrors.Wrapf(host.ErrInvalidPath, "path must be of length 2: %s", merklePath.GetKeyPath())
130+
}
131+
132+
// in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
133+
key, err := merklePath.GetKey(1)
134+
if err != nil {
135+
return sdkerrors.Wrapf(host.ErrInvalidPath, "key not found at index 1: %v", err)
130136
}
131137

132138
signBytes := &SignBytes{
133139
Sequence: sequence,
134140
Timestamp: timestamp,
135141
Diversifier: cs.ConsensusState.Diversifier,
136-
Path: []byte(merklePath.String()),
142+
Path: key,
137143
Data: value,
138144
}
139145

@@ -175,11 +181,21 @@ func (cs *ClientState) VerifyNonMembership(
175181
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", commitmenttypes.MerklePath{}, path)
176182
}
177183

184+
if len(merklePath.GetKeyPath()) != 2 {
185+
return sdkerrors.Wrapf(host.ErrInvalidPath, "path must be of length 2: %s", merklePath.GetKeyPath())
186+
}
187+
188+
// in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
189+
key, err := merklePath.GetKey(1)
190+
if err != nil {
191+
return sdkerrors.Wrapf(host.ErrInvalidPath, "key not found at index 1: %v", err)
192+
}
193+
178194
signBytes := &SignBytes{
179195
Sequence: sequence,
180196
Timestamp: timestamp,
181197
Diversifier: cs.ConsensusState.Diversifier,
182-
Path: []byte(merklePath.String()),
198+
Path: key,
183199
Data: nil,
184200
}
185201

modules/light-clients/06-solomachine/client_state_test.go

+60-14
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,15 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
176176
suite.Require().NoError(err)
177177

178178
path = suite.solomachine.GetClientStatePath(counterpartyClientIdentifier)
179+
merklePath, ok := path.(commitmenttypes.MerklePath)
180+
suite.Require().True(ok)
181+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
182+
suite.Require().NoError(err)
179183
signBytes = solomachine.SignBytes{
180184
Sequence: sm.GetHeight().GetRevisionHeight(),
181185
Timestamp: sm.Time,
182186
Diversifier: sm.Diversifier,
183-
Path: []byte(path.String()),
187+
Path: key,
184188
Data: clientStateBz,
185189
}
186190

@@ -208,11 +212,15 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
208212
suite.Require().NoError(err)
209213

210214
path = sm.GetConsensusStatePath(counterpartyClientIdentifier, clienttypes.NewHeight(0, 1))
215+
merklePath, ok := path.(commitmenttypes.MerklePath)
216+
suite.Require().True(ok)
217+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
218+
suite.Require().NoError(err)
211219
signBytes = solomachine.SignBytes{
212220
Sequence: sm.Sequence,
213221
Timestamp: sm.Time,
214222
Diversifier: sm.Diversifier,
215-
Path: []byte(path.String()),
223+
Path: key,
216224
Data: consensusStateBz,
217225
}
218226

@@ -243,11 +251,15 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
243251
suite.Require().NoError(err)
244252

245253
path = sm.GetConnectionStatePath(ibctesting.FirstConnectionID)
254+
merklePath, ok := path.(commitmenttypes.MerklePath)
255+
suite.Require().True(ok)
256+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
257+
suite.Require().NoError(err)
246258
signBytes = solomachine.SignBytes{
247259
Sequence: sm.Sequence,
248260
Timestamp: sm.Time,
249261
Diversifier: sm.Diversifier,
250-
Path: []byte(path.String()),
262+
Path: key,
251263
Data: connectionEndBz,
252264
}
253265

@@ -279,11 +291,15 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
279291
suite.Require().NoError(err)
280292

281293
path = sm.GetChannelStatePath(ibctesting.MockPort, ibctesting.FirstChannelID)
294+
merklePath, ok := path.(commitmenttypes.MerklePath)
295+
suite.Require().True(ok)
296+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
297+
suite.Require().NoError(err)
282298
signBytes = solomachine.SignBytes{
283299
Sequence: sm.Sequence,
284300
Timestamp: sm.Time,
285301
Diversifier: sm.Diversifier,
286-
Path: []byte(path.String()),
302+
Path: key,
287303
Data: channelEndBz,
288304
}
289305

@@ -312,11 +328,15 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
312328
suite.Require().True(found)
313329

314330
path = sm.GetNextSequenceRecvPath(ibctesting.MockPort, ibctesting.FirstChannelID)
331+
merklePath, ok := path.(commitmenttypes.MerklePath)
332+
suite.Require().True(ok)
333+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
334+
suite.Require().NoError(err)
315335
signBytes = solomachine.SignBytes{
316336
Sequence: sm.Sequence,
317337
Timestamp: sm.Time,
318338
Diversifier: sm.Diversifier,
319-
Path: []byte(path.String()),
339+
Path: key,
320340
Data: sdk.Uint64ToBigEndian(nextSeqRecv),
321341
}
322342

@@ -351,11 +371,15 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
351371

352372
commitmentBz := channeltypes.CommitPacket(suite.chainA.Codec, packet)
353373
path = sm.GetPacketCommitmentPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
374+
merklePath, ok := path.(commitmenttypes.MerklePath)
375+
suite.Require().True(ok)
376+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
377+
suite.Require().NoError(err)
354378
signBytes = solomachine.SignBytes{
355379
Sequence: sm.Sequence,
356380
Timestamp: sm.Time,
357381
Diversifier: sm.Diversifier,
358-
Path: []byte(path.String()),
382+
Path: key,
359383
Data: commitmentBz,
360384
}
361385

@@ -378,11 +402,15 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
378402
"success: packet acknowledgement verification",
379403
func() {
380404
path = sm.GetPacketAcknowledgementPath(ibctesting.MockPort, ibctesting.FirstChannelID, 1)
405+
merklePath, ok := path.(commitmenttypes.MerklePath)
406+
suite.Require().True(ok)
407+
key, err := merklePath.GetKey(1) // index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
408+
suite.Require().NoError(err)
381409
signBytes = solomachine.SignBytes{
382410
Sequence: sm.Sequence,
383411
Timestamp: sm.Time,
384412
Diversifier: sm.Diversifier,
385-
Path: []byte(path.String()),
413+
Path: key,
386414
Data: ibctesting.MockAcknowledgement,
387415
}
388416

@@ -405,11 +433,15 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
405433
"success: packet receipt verification",
406434
func() {
407435
path = sm.GetPacketReceiptPath(ibctesting.MockPort, ibctesting.FirstChannelID, 1)
436+
merklePath, ok := path.(commitmenttypes.MerklePath)
437+
suite.Require().True(ok)
438+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
439+
suite.Require().NoError(err)
408440
signBytes = solomachine.SignBytes{
409441
Sequence: sm.Sequence,
410442
Timestamp: sm.Time,
411443
Diversifier: sm.Diversifier,
412-
Path: []byte(path.String()),
444+
Path: key,
413445
Data: []byte{byte(1)}, // packet receipt is stored as a single byte
414446
}
415447

@@ -429,7 +461,7 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
429461
true,
430462
},
431463
{
432-
"invalid path type",
464+
"invalid path type - empty",
433465
func() {
434466
path = ibcmock.KeyPath{}
435467
},
@@ -521,11 +553,15 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
521553
clientState = sm.ClientState()
522554

523555
path = commitmenttypes.NewMerklePath("ibc", "solomachine")
556+
merklePath, ok := path.(commitmenttypes.MerklePath)
557+
suite.Require().True(ok)
558+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
559+
suite.Require().NoError(err)
524560
signBytes = solomachine.SignBytes{
525561
Sequence: sm.GetHeight().GetRevisionHeight(),
526562
Timestamp: sm.Time,
527563
Diversifier: sm.Diversifier,
528-
Path: []byte(path.String()),
564+
Path: key,
529565
Data: []byte("solomachine"),
530566
}
531567

@@ -570,19 +606,21 @@ func (suite *SoloMachineTestSuite) TestVerifyMembership() {
570606
func (suite *SoloMachineTestSuite) TestSignBytesMarshalling() {
571607
sm := suite.solomachine
572608
merklePath := commitmenttypes.NewMerklePath("ibc", "solomachine")
609+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
610+
suite.Require().NoError(err)
573611
signBytesNilData := solomachine.SignBytes{
574612
Sequence: sm.GetHeight().GetRevisionHeight(),
575613
Timestamp: sm.Time,
576614
Diversifier: sm.Diversifier,
577-
Path: []byte(merklePath.String()),
615+
Path: key,
578616
Data: nil,
579617
}
580618

581619
signBytesEmptyArray := solomachine.SignBytes{
582620
Sequence: sm.GetHeight().GetRevisionHeight(),
583621
Timestamp: sm.Time,
584622
Diversifier: sm.Diversifier,
585-
Path: []byte(merklePath.String()),
623+
Path: key,
586624
Data: []byte{},
587625
}
588626

@@ -621,11 +659,15 @@ func (suite *SoloMachineTestSuite) TestVerifyNonMembership() {
621659
"success: packet receipt absence verification",
622660
func() {
623661
path = suite.solomachine.GetPacketReceiptPath(ibctesting.MockPort, ibctesting.FirstChannelID, 1)
662+
merklePath, ok := path.(commitmenttypes.MerklePath)
663+
suite.Require().True(ok)
664+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
665+
suite.Require().NoError(err)
624666
signBytes = solomachine.SignBytes{
625667
Sequence: sm.GetHeight().GetRevisionHeight(),
626668
Timestamp: sm.Time,
627669
Diversifier: sm.Diversifier,
628-
Path: []byte(path.String()),
670+
Path: key,
629671
Data: nil,
630672
}
631673

@@ -740,11 +782,15 @@ func (suite *SoloMachineTestSuite) TestVerifyNonMembership() {
740782
clientState = sm.ClientState()
741783

742784
path = commitmenttypes.NewMerklePath("ibc", "solomachine")
785+
merklePath, ok := path.(commitmenttypes.MerklePath)
786+
suite.Require().True(ok)
787+
key, err := merklePath.GetKey(1) // in a multistore context: index 0 is the key for the IBC store in the multistore, index 1 is the key in the IBC store
788+
suite.Require().NoError(err)
743789
signBytes = solomachine.SignBytes{
744790
Sequence: sm.GetHeight().GetRevisionHeight(),
745791
Timestamp: sm.Time,
746792
Diversifier: sm.Diversifier,
747-
Path: []byte(path.String()),
793+
Path: key,
748794
Data: nil,
749795
}
750796

modules/light-clients/07-tendermint/upgrade.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func (cs ClientState) VerifyUpgradeAndUpdateState(
8080
// construct clientState Merkle path
8181
upgradeClientPath := constructUpgradeClientMerklePath(cs.UpgradePath, lastHeight)
8282
if err := merkleProofClient.VerifyMembership(cs.ProofSpecs, consState.GetRoot(), upgradeClientPath, bz); err != nil {
83-
return sdkerrors.Wrapf(err, "client state proof failed. Path: %s", upgradeClientPath.Pretty())
83+
return sdkerrors.Wrapf(err, "client state proof failed. Path: %s", upgradeClientPath.GetKeyPath())
8484
}
8585

8686
// Verify consensus state proof
@@ -91,7 +91,7 @@ func (cs ClientState) VerifyUpgradeAndUpdateState(
9191
// construct consensus state Merkle path
9292
upgradeConsStatePath := constructUpgradeConsStateMerklePath(cs.UpgradePath, lastHeight)
9393
if err := merkleProofConsState.VerifyMembership(cs.ProofSpecs, consState.GetRoot(), upgradeConsStatePath, bz); err != nil {
94-
return sdkerrors.Wrapf(err, "consensus state proof failed. Path: %s", upgradeConsStatePath.Pretty())
94+
return sdkerrors.Wrapf(err, "consensus state proof failed. Path: %s", upgradeConsStatePath.GetKeyPath())
9595
}
9696

9797
// Construct new client state and consensus state

0 commit comments

Comments
 (0)