Skip to content

Commit

Permalink
refactor!: add v2 MerklePath with bytes in favour of strings (#6644)
Browse files Browse the repository at this point in the history
* refactor: adapt merkle path to use repeated bytes in favour of strings

* refactor: update NewMerklePath func sig to take bytes

* nit: rm unnecessary variable

* nit: rename var

* chore: add changelog

* fix: introduce legacy merkle path type for encoding compatibility with existing 08-wasm contracts

* refactor: adapt code to handle v2 proto MerklePath

* chore: add deprecation notices for v1 merkle path

* chore: update changelog

* fix: use pointer to leverage omitempty correctly in contract api

* test: add tests for 08-wasm contract api encoding

* refactor: adapt IsValidUTF func per review suggestion and add more tests

* refactor: use v2.MerklePath in contract api and update 08-wasm changelog

* Update CHANGELOG.md

---------

Co-authored-by: Carlos Rodriguez <carlos@interchain.io>
  • Loading branch information
damiannolan and crodriguezvega authored Jul 3, 2024
1 parent 30550c2 commit 2bd5920
Show file tree
Hide file tree
Showing 26 changed files with 742 additions and 344 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (apps/transfer) [\#6440](https://github.com/cosmos/ibc-go/pull/6440) Remove `GetPrefixedDenom`.
* (apps/transfer) [\#6508](https://github.com/cosmos/ibc-go/pull/6508) Remove the `DenomTrace` type.
* (apps/27-interchain-accounts) [\#6598](https://github.com/cosmos/ibc-go/pull/6598) Mark the `requests` repeated field of `MsgModuleQuerySafe` non-nullable.
* (23-commmitment) [\#6644](https://github.com/cosmos/ibc-go/pull/6644) Introduce commitment/v2 `MerklePath` to include `repeated bytes` in favour of `repeated string`. This supports using merkle path keys which include non UTF-8 encoded runes.
* (23-commmitment) [\#6633](https://github.com/cosmos/ibc-go/pull/6633) MerklePath has been changed to use `repeated bytes` in favour of `repeated strings`.

### State Machine Breaking
Expand Down
8 changes: 4 additions & 4 deletions modules/core/02-client/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ func (suite *KeeperTestSuite) TestQueryVerifyMembershipProof() {

channelProof, proofHeight := path.EndpointB.QueryProof(host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID))

merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID))
merklePath := commitmenttypes.NewMerklePath(host.ChannelKey(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID))
merklePath, err = commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath)
suite.Require().NoError(err)

Expand Down Expand Up @@ -890,7 +890,7 @@ func (suite *KeeperTestSuite) TestQueryVerifyMembershipProof() {
ClientId: ibctesting.FirstClientID,
Proof: []byte{0x01},
ProofHeight: types.NewHeight(1, 100),
MerklePath: commitmenttypes.NewMerklePath("/ibc", host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)),
MerklePath: commitmenttypes.NewMerklePath([]byte("/ibc"), host.ChannelKey(mock.PortID, ibctesting.FirstChannelID)),
}
},
errors.New("empty value"),
Expand All @@ -902,7 +902,7 @@ func (suite *KeeperTestSuite) TestQueryVerifyMembershipProof() {
ClientId: wasmClientID, // use a client type that is not registered
Proof: []byte{0x01},
ProofHeight: types.NewHeight(1, 100),
MerklePath: commitmenttypes.NewMerklePath("/ibc", host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)),
MerklePath: commitmenttypes.NewMerklePath([]byte("/ibc"), host.ChannelKey(mock.PortID, ibctesting.FirstChannelID)),
Value: []byte{0x01},
}
},
Expand All @@ -918,7 +918,7 @@ func (suite *KeeperTestSuite) TestQueryVerifyMembershipProof() {
ClientId: path.EndpointA.ClientID,
Proof: []byte{0x01},
ProofHeight: types.NewHeight(1, 100),
MerklePath: commitmenttypes.NewMerklePath("/ibc", host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)),
MerklePath: commitmenttypes.NewMerklePath([]byte("/ibc"), host.ChannelKey(mock.PortID, ibctesting.FirstChannelID)),
Value: []byte{0x01},
}
},
Expand Down
269 changes: 135 additions & 134 deletions modules/core/02-client/types/query.pb.go

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions modules/core/03-connection/keeper/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (k *Keeper) VerifyClientState(
return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID)
}

merklePath := commitmenttypes.NewMerklePath(host.FullClientStatePath(connection.Counterparty.ClientId))
merklePath := commitmenttypes.NewMerklePath(host.FullClientStateKey(connection.Counterparty.ClientId))
merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down Expand Up @@ -76,7 +76,7 @@ func (k *Keeper) VerifyClientConsensusState(
return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID)
}

merklePath := commitmenttypes.NewMerklePath(host.FullConsensusStatePath(connection.Counterparty.ClientId, consensusHeight))
merklePath := commitmenttypes.NewMerklePath(host.FullConsensusStateKey(connection.Counterparty.ClientId, consensusHeight))
merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down Expand Up @@ -118,7 +118,7 @@ func (k *Keeper) VerifyConnectionState(
return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID)
}

merklePath := commitmenttypes.NewMerklePath(host.ConnectionPath(connectionID))
merklePath := commitmenttypes.NewMerklePath(host.ConnectionKey(connectionID))
merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down Expand Up @@ -161,7 +161,7 @@ func (k *Keeper) VerifyChannelState(
return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID)
}

merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID))
merklePath := commitmenttypes.NewMerklePath(host.ChannelKey(portID, channelID))
merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down Expand Up @@ -209,7 +209,7 @@ func (k *Keeper) VerifyPacketCommitment(
timeDelay := connection.DelayPeriod
blockDelay := k.getBlockDelay(ctx, connection)

merklePath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, sequence))
merklePath := commitmenttypes.NewMerklePath(host.PacketCommitmentKey(portID, channelID, sequence))
merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down Expand Up @@ -250,7 +250,7 @@ func (k *Keeper) VerifyPacketAcknowledgement(
timeDelay := connection.DelayPeriod
blockDelay := k.getBlockDelay(ctx, connection)

merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, sequence))
merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementKey(portID, channelID, sequence))
merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down Expand Up @@ -297,7 +297,7 @@ func (k *Keeper) VerifyPacketReceiptAbsence(
timeDelay := connection.DelayPeriod
blockDelay := k.getBlockDelay(ctx, connection)

merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(portID, channelID, sequence))
merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptKey(portID, channelID, sequence))
merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down Expand Up @@ -337,7 +337,7 @@ func (k *Keeper) VerifyNextSequenceRecv(
timeDelay := connection.DelayPeriod
blockDelay := k.getBlockDelay(ctx, connection)

merklePath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(portID, channelID))
merklePath := commitmenttypes.NewMerklePath(host.NextSequenceRecvKey(portID, channelID))
merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down Expand Up @@ -374,7 +374,7 @@ func (k *Keeper) VerifyChannelUpgradeError(
return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID)
}

merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradeErrorPath(portID, channelID))
merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradeErrorKey(portID, channelID))
merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down Expand Up @@ -416,7 +416,7 @@ func (k *Keeper) VerifyChannelUpgrade(
return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID)
}

merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradePath(portID, channelID))
merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradeKey(portID, channelID))
merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath)
if err != nil {
return err
Expand Down
62 changes: 31 additions & 31 deletions modules/core/23-commitment/types/commitment.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 14 additions & 19 deletions modules/core/23-commitment/types/merkle.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

cmtcrypto "github.com/cometbft/cometbft/proto/tendermint/crypto"

"github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types/v2"
"github.com/cosmos/ibc-go/v8/modules/core/exported"
)

Expand Down Expand Up @@ -69,39 +70,33 @@ func (mp MerklePrefix) Empty() bool {
var _ exported.Path = (*MerklePath)(nil)

// NewMerklePath creates a new MerklePath instance
// The keys must be passed in from root-to-leaf order
func NewMerklePath(keyPath ...string) MerklePath {
var path [][]byte
for _, key := range keyPath {
path = append(path, []byte(key))
}

return MerklePath{
KeyPath: path,
}
}
// The keys must be passed in from root-to-leaf order.
// NOTE: NewMerklePath returns a commitment/v2 MerklePath.
var NewMerklePath = v2.NewMerklePath

// GetKey will return a byte representation of the key
func (mp MerklePath) GetKey(i uint64) ([]byte, error) {
// Deprecated: Please use commitment/v2 MerklePath instead.
func (mp MerklePath) GetKey(i uint64) (string, error) {
if i >= uint64(len(mp.KeyPath)) {
return nil, fmt.Errorf("index out of range. %d (index) >= %d (len)", i, len(mp.KeyPath))
return "", fmt.Errorf("index out of range. %d (index) >= %d (len)", i, len(mp.KeyPath))
}
return mp.KeyPath[i], nil
}

// Empty returns true if the path is empty
// Deprecated: Please use commitment/v2 MerklePath instead.
func (mp MerklePath) Empty() bool {
return len(mp.KeyPath) == 0
}

// ApplyPrefix constructs a new commitment path from the arguments. It prepends the prefix key
// with the given path.
func ApplyPrefix(prefix exported.Prefix, path MerklePath) (MerklePath, error) {
func ApplyPrefix(prefix exported.Prefix, path v2.MerklePath) (v2.MerklePath, error) {
if prefix == nil || prefix.Empty() {
return MerklePath{}, errorsmod.Wrap(ErrInvalidPrefix, "prefix can't be empty")
return v2.MerklePath{}, errorsmod.Wrap(ErrInvalidPrefix, "prefix can't be empty")
}

return MerklePath{
return v2.MerklePath{
KeyPath: append([][]byte{prefix.Bytes()}, path.KeyPath...),
}, nil
}
Expand All @@ -114,7 +109,7 @@ func (proof MerkleProof) VerifyMembership(specs []*ics23.ProofSpec, root exporte
}

// VerifyMembership specific argument validation
mpath, ok := path.(MerklePath)
mpath, ok := path.(v2.MerklePath)
if !ok {
return errorsmod.Wrapf(ErrInvalidProof, "path %v is not of type MerklePath", path)
}
Expand All @@ -140,7 +135,7 @@ func (proof MerkleProof) VerifyNonMembership(specs []*ics23.ProofSpec, root expo
}

// VerifyNonMembership specific argument validation
mpath, ok := path.(MerklePath)
mpath, ok := path.(v2.MerklePath)
if !ok {
return errorsmod.Wrapf(ErrInvalidProof, "path %v is not of type MerkleProof", path)
}
Expand Down Expand Up @@ -196,7 +191,7 @@ func (MerkleProof) BatchVerifyNonMembership(specs []*ics23.ProofSpec, root expor
// The proofs and specs are passed in from lowest subtree to the highest subtree, but the keys are passed in from highest subtree to lowest.
// The index specifies what index to start chaining the membership proofs, this is useful since the lowest proof may not be a membership proof, thus we
// will want to start the membership proof chaining from index 1 with value being the lowest subroot
func verifyChainedMembershipProof(root []byte, specs []*ics23.ProofSpec, proofs []*ics23.CommitmentProof, keys MerklePath, value []byte, index int) error {
func verifyChainedMembershipProof(root []byte, specs []*ics23.ProofSpec, proofs []*ics23.CommitmentProof, keys v2.MerklePath, value []byte, index int) error {
var (
subroot []byte
err error
Expand Down
Loading

0 comments on commit 2bd5920

Please sign in to comment.