From e36015c94122faddb2e6cacec464b6c6f9749c91 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Fri, 12 Jul 2024 08:10:42 -0700 Subject: [PATCH] imp: Enable custom paths for light client proof verifications (#1273) * refactor: allow using custom path for light client proof verification * imp: 2nd try, place serialize_path under the ClientStateCommon * feat: define concat() for PathBytes * fix: update cw-check cargo.lock * chore: add docs and unclog * misc: apply some fixes * imp: group serialize_path and verify_(non_)membership_raw methods * nit: reword changelog * fix grammar * imp: rename to flatten + revert to Path::*(*) * fix typo * fix: make clippy happy * fix: move changelog to features --------- Co-authored-by: Ranadeep Biswas --- ...le-custom-paths-for-proof-verificaitons.md | 4 ++ ci/cw-check/Cargo.lock | 1 + ci/no-std-check/Cargo.lock | 1 + ibc-clients/cw-context/src/handlers.rs | 4 +- ibc-clients/cw-context/src/types/msgs.rs | 29 ++++------- .../src/client_state/common.rs | 45 +++++++++++----- .../ics02-client/context/src/client_state.rs | 43 +++++++++++++--- ibc-core/ics23-commitment/types/Cargo.toml | 12 +++-- ibc-core/ics23-commitment/types/src/merkle.rs | 51 ++++++++++++++++--- ibc-core/ics24-host/types/src/path.rs | 33 ++++++++++++ .../traits/client_state_common.rs | 50 ++++++++++++++++++ ibc-derive/src/utils.rs | 5 ++ .../testapp/ibc/clients/mock/client_state.rs | 14 +++-- 13 files changed, 236 insertions(+), 56 deletions(-) create mode 100644 .changelog/unreleased/features/1255-enable-custom-paths-for-proof-verificaitons.md diff --git a/.changelog/unreleased/features/1255-enable-custom-paths-for-proof-verificaitons.md b/.changelog/unreleased/features/1255-enable-custom-paths-for-proof-verificaitons.md new file mode 100644 index 000000000..3caf85de4 --- /dev/null +++ b/.changelog/unreleased/features/1255-enable-custom-paths-for-proof-verificaitons.md @@ -0,0 +1,4 @@ +- [ibc-core-client] Enable proof verification methods to accept custom paths as + bytes by defining a new `serializer_path()` API allowing light client + developers to introduce the path serialization behavior of their system. + ([\#1255](https://github.com/cosmos/ibc-rs/issues/1255)) diff --git a/ci/cw-check/Cargo.lock b/ci/cw-check/Cargo.lock index 448a85f68..04c40474e 100644 --- a/ci/cw-check/Cargo.lock +++ b/ci/cw-check/Cargo.lock @@ -930,6 +930,7 @@ version = "0.53.0" dependencies = [ "derive_more 0.99.18", "displaydoc", + "ibc-core-host-types", "ibc-primitives", "ibc-proto", "ics23", diff --git a/ci/no-std-check/Cargo.lock b/ci/no-std-check/Cargo.lock index a7ea8c640..01ea501f8 100644 --- a/ci/no-std-check/Cargo.lock +++ b/ci/no-std-check/Cargo.lock @@ -1357,6 +1357,7 @@ version = "0.53.0" dependencies = [ "derive_more", "displaydoc", + "ibc-core-host-types", "ibc-primitives", "ibc-proto", "ics23", diff --git a/ibc-clients/cw-context/src/handlers.rs b/ibc-clients/cw-context/src/handlers.rs index 4b4798d1e..eb92e0928 100644 --- a/ibc-clients/cw-context/src/handlers.rs +++ b/ibc-clients/cw-context/src/handlers.rs @@ -70,7 +70,7 @@ where let consensus_state = self.consensus_state(&client_cons_state_path)?; - client_state.verify_membership( + client_state.verify_membership_raw( &msg.prefix, &msg.proof, consensus_state.root(), @@ -91,7 +91,7 @@ where let consensus_state = self.consensus_state(&client_cons_state_path)?; - client_state.verify_non_membership( + client_state.verify_non_membership_raw( &msg.prefix, &msg.proof, consensus_state.root(), diff --git a/ibc-clients/cw-context/src/types/msgs.rs b/ibc-clients/cw-context/src/types/msgs.rs index 2f15258aa..1a7da1a4c 100644 --- a/ibc-clients/cw-context/src/types/msgs.rs +++ b/ibc-clients/cw-context/src/types/msgs.rs @@ -1,13 +1,12 @@ //! Defines the messages sent to the CosmWasm contract by the 08-wasm proxy //! light client. -use std::str::FromStr; - use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::{Binary, Checksum}; use ibc_core::client::types::proto::v1::Height as RawHeight; use ibc_core::client::types::Height; use ibc_core::commitment_types::commitment::{CommitmentPrefix, CommitmentProofBytes}; -use ibc_core::host::types::path::Path; +use ibc_core::commitment_types::merkle::MerklePath; +use ibc_core::host::types::path::PathBytes; use ibc_core::primitives::proto::Any; use prost::Message; @@ -116,11 +115,6 @@ impl TryFrom for VerifyUpgradeAndUpdateStateM } } -#[cw_serde] -pub struct MerklePath { - pub key_path: Vec, -} - #[cw_serde] pub struct VerifyMembershipMsgRaw { pub proof: Binary, @@ -134,7 +128,7 @@ pub struct VerifyMembershipMsgRaw { pub struct VerifyMembershipMsg { pub prefix: CommitmentPrefix, pub proof: CommitmentProofBytes, - pub path: Path, + pub path: PathBytes, pub value: Vec, pub height: Height, pub delay_block_period: u64, @@ -146,9 +140,8 @@ impl TryFrom for VerifyMembershipMsg { fn try_from(mut raw: VerifyMembershipMsgRaw) -> Result { let proof = CommitmentProofBytes::try_from(raw.proof.to_vec())?; - let prefix = raw.path.key_path.remove(0).into_bytes(); - let path_str = raw.path.key_path.join(""); - let path = Path::from_str(&path_str)?; + let prefix = CommitmentPrefix::from(raw.path.key_path.remove(0).into_vec()); + let path = PathBytes::flatten(raw.path.key_path); let height = Height::try_from(raw.height)?; Ok(Self { @@ -156,7 +149,7 @@ impl TryFrom for VerifyMembershipMsg { path, value: raw.value.into(), height, - prefix: CommitmentPrefix::from(prefix), + prefix, delay_block_period: raw.delay_block_period, delay_time_period: raw.delay_time_period, }) @@ -175,7 +168,7 @@ pub struct VerifyNonMembershipMsgRaw { pub struct VerifyNonMembershipMsg { pub prefix: CommitmentPrefix, pub proof: CommitmentProofBytes, - pub path: Path, + pub path: PathBytes, pub height: Height, pub delay_block_period: u64, pub delay_time_period: u64, @@ -186,15 +179,15 @@ impl TryFrom for VerifyNonMembershipMsg { fn try_from(mut raw: VerifyNonMembershipMsgRaw) -> Result { let proof = CommitmentProofBytes::try_from(raw.proof.to_vec())?; - let prefix = raw.path.key_path.remove(0).into_bytes(); - let path_str = raw.path.key_path.join(""); - let path = Path::from_str(&path_str)?; + let prefix = CommitmentPrefix::from(raw.path.key_path.remove(0).into_vec()); + let path = PathBytes::flatten(raw.path.key_path); let height = raw.height.try_into()?; + Ok(Self { proof, path, height, - prefix: CommitmentPrefix::from(prefix), + prefix, delay_block_period: raw.delay_block_period, delay_time_period: raw.delay_time_period, }) diff --git a/ibc-clients/ics07-tendermint/src/client_state/common.rs b/ibc-clients/ics07-tendermint/src/client_state/common.rs index c7b9a9525..c4726871e 100644 --- a/ibc-clients/ics07-tendermint/src/client_state/common.rs +++ b/ibc-clients/ics07-tendermint/src/client_state/common.rs @@ -7,11 +7,11 @@ use ibc_core_commitment_types::commitment::{ CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, }; use ibc_core_commitment_types::error::CommitmentError; -use ibc_core_commitment_types::merkle::{apply_prefix, MerkleProof}; +use ibc_core_commitment_types::merkle::{MerklePath, MerkleProof}; use ibc_core_commitment_types::proto::ics23::{HostFunctionsManager, HostFunctionsProvider}; use ibc_core_commitment_types::specs::ProofSpecs; use ibc_core_host::types::identifiers::ClientType; -use ibc_core_host::types::path::{Path, UpgradeClientPath}; +use ibc_core_host::types::path::{Path, PathBytes, UpgradeClientPath}; use ibc_primitives::prelude::*; use ibc_primitives::proto::Any; use ibc_primitives::ToVec; @@ -44,22 +44,38 @@ impl ClientStateCommon for ClientState { proof_upgrade_consensus_state: CommitmentProofBytes, root: &CommitmentRoot, ) -> Result<(), ClientError> { + let last_height = self.latest_height().revision_height(); + + let upgrade_client_path_bytes = self.serialize_path(Path::UpgradeClient( + UpgradeClientPath::UpgradedClientState(last_height), + ))?; + + let upgrade_consensus_path_bytes = self.serialize_path(Path::UpgradeClient( + UpgradeClientPath::UpgradedClientConsensusState(last_height), + ))?; + verify_upgrade_client::( self.inner(), upgraded_client_state, upgraded_consensus_state, proof_upgrade_client, proof_upgrade_consensus_state, + upgrade_client_path_bytes, + upgrade_consensus_path_bytes, root, ) } - fn verify_membership( + fn serialize_path(&self, path: Path) -> Result { + Ok(path.to_string().into_bytes().into()) + } + + fn verify_membership_raw( &self, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, root: &CommitmentRoot, - path: Path, + path: PathBytes, value: Vec, ) -> Result<(), ClientError> { verify_membership::( @@ -72,12 +88,12 @@ impl ClientStateCommon for ClientState { ) } - fn verify_non_membership( + fn verify_non_membership_raw( &self, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, root: &CommitmentRoot, - path: Path, + path: PathBytes, ) -> Result<(), ClientError> { verify_non_membership::( &self.inner().proof_specs, @@ -140,12 +156,15 @@ pub fn validate_proof_height( /// Note that this function is typically implemented as part of the /// [`ClientStateCommon`] trait, but has been made a standalone function /// in order to make the ClientState APIs more flexible. +#[allow(clippy::too_many_arguments)] pub fn verify_upgrade_client( client_state: &ClientStateType, upgraded_client_state: Any, upgraded_consensus_state: Any, proof_upgrade_client: CommitmentProofBytes, proof_upgrade_consensus_state: CommitmentProofBytes, + upgrade_client_path_bytes: PathBytes, + upgrade_consensus_path_bytes: PathBytes, root: &CommitmentRoot, ) -> Result<(), ClientError> { // Make sure that the client type is of Tendermint type `ClientState` @@ -178,15 +197,13 @@ pub fn verify_upgrade_client( let upgrade_path_prefix = CommitmentPrefix::from(upgrade_path[0].clone().into_bytes()); - let last_height = latest_height.revision_height(); - // Verify the proof of the upgraded client state verify_membership::( &client_state.proof_specs, &upgrade_path_prefix, &proof_upgrade_client, root, - Path::UpgradeClient(UpgradeClientPath::UpgradedClientState(last_height)), + upgrade_client_path_bytes, upgraded_client_state.to_vec(), )?; @@ -196,7 +213,7 @@ pub fn verify_upgrade_client( &upgrade_path_prefix, &proof_upgrade_consensus_state, root, - Path::UpgradeClient(UpgradeClientPath::UpgradedClientConsensusState(last_height)), + upgrade_consensus_path_bytes, upgraded_consensus_state.to_vec(), )?; @@ -213,7 +230,7 @@ pub fn verify_membership( prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, root: &CommitmentRoot, - path: Path, + path: PathBytes, value: Vec, ) -> Result<(), ClientError> { if prefix.is_empty() { @@ -222,7 +239,7 @@ pub fn verify_membership( )); } - let merkle_path = apply_prefix(prefix, vec![path.to_string()]); + let merkle_path = MerklePath::new(vec![prefix.as_bytes().to_vec().into(), path]); let merkle_proof = MerkleProof::try_from(proof).map_err(ClientError::InvalidCommitmentProof)?; merkle_proof @@ -240,9 +257,9 @@ pub fn verify_non_membership( prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, root: &CommitmentRoot, - path: Path, + path: PathBytes, ) -> Result<(), ClientError> { - let merkle_path = apply_prefix(prefix, vec![path.to_string()]); + let merkle_path = MerklePath::new(vec![prefix.as_bytes().to_vec().into(), path]); let merkle_proof = MerkleProof::try_from(proof).map_err(ClientError::InvalidCommitmentProof)?; merkle_proof diff --git a/ibc-core/ics02-client/context/src/client_state.rs b/ibc-core/ics02-client/context/src/client_state.rs index 974d9b43b..3464e37cb 100644 --- a/ibc-core/ics02-client/context/src/client_state.rs +++ b/ibc-core/ics02-client/context/src/client_state.rs @@ -6,7 +6,7 @@ use ibc_core_commitment_types::commitment::{ CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, }; use ibc_core_host_types::identifiers::{ClientId, ClientType}; -use ibc_core_host_types::path::Path; +use ibc_core_host_types::path::{Path, PathBytes}; use ibc_primitives::prelude::*; use ibc_primitives::proto::Any; @@ -52,8 +52,25 @@ pub trait ClientStateCommon: Convertible { root: &CommitmentRoot, ) -> Result<(), ClientError>; - // Verify_membership is a generic proof verification method which verifies a - // proof of the existence of a value at a given Path. + /// Serializes a given path object into a raw path bytes. + /// + /// This method provides essential information for IBC modules, enabling + /// them to understand how path serialization is performed on the chain this + /// light client represents it before passing the path bytes to either + /// `verify_membership_raw()` or `verify_non_membership_raw()`. + fn serialize_path(&self, path: Path) -> Result; + + /// Verifies a proof of the existence of a value at a given raw path bytes. + fn verify_membership_raw( + &self, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + path: PathBytes, + value: Vec, + ) -> Result<(), ClientError>; + + /// Verifies a proof of the existence of a value at a given path object. fn verify_membership( &self, prefix: &CommitmentPrefix, @@ -61,17 +78,31 @@ pub trait ClientStateCommon: Convertible { root: &CommitmentRoot, path: Path, value: Vec, + ) -> Result<(), ClientError> { + let path_bytes = self.serialize_path(path)?; + self.verify_membership_raw(prefix, proof, root, path_bytes, value) + } + + /// Verifies the absence of a given proof at a given raw path bytes. + fn verify_non_membership_raw( + &self, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + path: PathBytes, ) -> Result<(), ClientError>; - // Verify_non_membership is a generic proof verification method which - // verifies the absence of a given commitment. + /// Verifies the absence of a given proof at a given path object. fn verify_non_membership( &self, prefix: &CommitmentPrefix, proof: &CommitmentProofBytes, root: &CommitmentRoot, path: Path, - ) -> Result<(), ClientError>; + ) -> Result<(), ClientError> { + let path_bytes = self.serialize_path(path)?; + self.verify_non_membership_raw(prefix, proof, root, path_bytes) + } } /// `ClientState` methods which require access to the client's validation diff --git a/ibc-core/ics23-commitment/types/Cargo.toml b/ibc-core/ics23-commitment/types/Cargo.toml index 27ce743c6..c1ce47b36 100644 --- a/ibc-core/ics23-commitment/types/Cargo.toml +++ b/ibc-core/ics23-commitment/types/Cargo.toml @@ -28,9 +28,10 @@ serde = { workspace = true, optional = true } subtle-encoding = { workspace = true } # ibc dependencies -ibc-proto = { workspace = true } -ibc-primitives = { workspace = true } -ics23 = { version = "0.11", default-features = false, features = [ "host-functions" ] } +ibc-proto = { workspace = true } +ibc-primitives = { workspace = true } +ics23 = { version = "0.11", default-features = false, features = [ "host-functions" ] } +ibc-core-host-types = { workspace = true } # parity dependencies parity-scale-codec = { workspace = true, optional = true } @@ -46,12 +47,14 @@ std = [ "serde/std", "subtle-encoding/std", "ibc-primitives/std", + "ibc-core-host-types/std", "ibc-proto/std", "ics23/std", ] serde = [ "dep:serde", "ibc-primitives/serde", + "ibc-core-host-types/serde", "ibc-proto/serde", "ics23/serde", ] @@ -59,6 +62,7 @@ schema = [ "dep:schemars", "ibc-proto/json-schema", "ibc-primitives/schema", + "ibc-core-host-types/schema", "serde", "std", ] @@ -66,10 +70,12 @@ borsh = [ "dep:borsh", "ibc-proto/borsh", "ibc-primitives/borsh", + "ibc-core-host-types/borsh", ] parity-scale-codec = [ "dep:parity-scale-codec", "dep:scale-info", "ibc-primitives/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", "ibc-proto/parity-scale-codec", ] diff --git a/ibc-core/ics23-commitment/types/src/merkle.rs b/ibc-core/ics23-commitment/types/src/merkle.rs index cb36590ca..d597ef1c8 100644 --- a/ibc-core/ics23-commitment/types/src/merkle.rs +++ b/ibc-core/ics23-commitment/types/src/merkle.rs @@ -1,24 +1,59 @@ //! Merkle proof utilities +use ibc_core_host_types::path::PathBytes; use ibc_primitives::prelude::*; use ibc_primitives::proto::Protobuf; -use ibc_proto::ibc::core::commitment::v1::{MerklePath, MerkleProof as RawMerkleProof, MerkleRoot}; +use ibc_proto::ibc::core::commitment::v1::{ + MerklePath as RawMerklePath, MerkleProof as RawMerkleProof, MerkleRoot, +}; use ibc_proto::ics23::commitment_proof::Proof; use ibc_proto::ics23::{ calculate_existence_root, verify_membership, verify_non_membership, CommitmentProof, HostFunctionsProvider, NonExistenceProof, }; -use crate::commitment::{CommitmentPrefix, CommitmentRoot}; +use crate::commitment::CommitmentRoot; use crate::error::CommitmentError; use crate::specs::ProofSpecs; -pub fn apply_prefix(prefix: &CommitmentPrefix, mut path: Vec) -> MerklePath { - let mut key_path: Vec = vec![format!("{prefix:?}")]; - key_path.append(&mut path); - MerklePath { key_path } +/// A wrapper type representing a Merkle path, consisting of a sequence of path +/// bytes. +/// +/// This struct by definition is compatible with Cosmos SDK chains, but it is +/// also applicable to other blockchain implementations that follow similar path +/// structures. Note that while Cosmos SDK chains and some non-Cosmos chains +/// adhere to this definition, it may not be universally applicable to all +/// non-Cosmos chains. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, PartialEq)] +pub struct MerklePath { + pub key_path: Vec, +} + +impl MerklePath { + /// Constructs a new `MerklePath` from a given `Vec`. + pub fn new(key_path: Vec) -> Self { + Self { key_path } + } } +impl From for MerklePath { + fn from(path: RawMerklePath) -> Self { + Self { + key_path: path + .key_path + .into_iter() + .map(|p| p.into_bytes().into()) + .collect(), + } + } +} + +// The conversion from `MerklePath` to `RawMerklePath` is not provided, as we +// cannot assume how the key paths of `Vec` type should be serialized +// to the `Vec`. + impl From for MerkleRoot { fn from(root: CommitmentRoot) -> Self { Self { @@ -99,7 +134,7 @@ impl MerkleProof { subroot = calculate_existence_root::(existence_proof) .map_err(|_| CommitmentError::InvalidMerkleProof)?; - if !verify_membership::(proof, spec, &subroot, key.as_bytes(), &value) { + if !verify_membership::(proof, spec, &subroot, key.as_ref(), &value) { return Err(CommitmentError::VerificationFailure); } value.clone_from(&subroot); @@ -154,7 +189,7 @@ impl MerkleProof { Some(Proof::Nonexist(non_existence_proof)) => { let subroot = calculate_non_existence_root::(non_existence_proof)?; - if !verify_non_membership::(proof, spec, &subroot, key.as_bytes()) { + if !verify_non_membership::(proof, spec, &subroot, key.as_ref()) { return Err(CommitmentError::VerificationFailure); } diff --git a/ibc-core/ics24-host/types/src/path.rs b/ibc-core/ics24-host/types/src/path.rs index 43e99347e..c9e384989 100644 --- a/ibc-core/ics24-host/types/src/path.rs +++ b/ibc-core/ics24-host/types/src/path.rs @@ -42,6 +42,39 @@ pub const UPGRADED_CLIENT_STATE: &str = "upgradedClient"; /// - The key identifying the upgraded consensus state pub const UPGRADED_CLIENT_CONSENSUS_STATE: &str = "upgradedConsState"; +/// Represents a general-purpose path structure using the byte representation of +/// a path. This struct abstracts over different path types and can handle bytes +/// obtained from various serialization formats (e.g., Protobuf, Borsh). +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, From)] +pub struct PathBytes(Vec); + +impl PathBytes { + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn into_vec(self) -> Vec { + self.0 + } + + /// Flattens a list of path bytes into a single path. + pub fn flatten(paths: Vec) -> Self { + let mut bytes = Vec::new(); + paths.iter().for_each(|path| { + bytes.extend_from_slice(&path.0); + }); + Self(bytes) + } +} + +impl AsRef<[u8]> for PathBytes { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + /// The Path enum abstracts out the different sub-paths. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, From, Display)] pub enum Path { diff --git a/ibc-derive/src/client_state/traits/client_state_common.rs b/ibc-derive/src/client_state/traits/client_state_common.rs index bac320ff8..0184d9a23 100644 --- a/ibc-derive/src/client_state/traits/client_state_common.rs +++ b/ibc-derive/src/client_state/traits/client_state_common.rs @@ -41,12 +41,30 @@ pub(crate) fn impl_ClientStateCommon( quote! {verify_upgrade_client(cs, upgraded_client_state, upgraded_consensus_state, proof_upgrade_client, proof_upgrade_consensus_state, root)}, imports, ); + let serialize_path_impl = delegate_call_in_match( + client_state_enum_name, + enum_variants.iter(), + quote! {serialize_path(cs, path)}, + imports, + ); + let verify_membership_raw_impl = delegate_call_in_match( + client_state_enum_name, + enum_variants.iter(), + quote! {verify_membership_raw(cs, prefix, proof, root, path, value)}, + imports, + ); let verify_membership_impl = delegate_call_in_match( client_state_enum_name, enum_variants.iter(), quote! {verify_membership(cs, prefix, proof, root, path, value)}, imports, ); + let verify_non_membership_raw_impl = delegate_call_in_match( + client_state_enum_name, + enum_variants.iter(), + quote! {verify_non_membership_raw(cs, prefix, proof, root, path)}, + imports, + ); let verify_non_membership_impl = delegate_call_in_match( client_state_enum_name, enum_variants.iter(), @@ -65,6 +83,7 @@ pub(crate) fn impl_ClientStateCommon( let ClientError = imports.client_error(); let Height = imports.height(); let Path = imports.path(); + let PathBytes = imports.path_bytes(); quote! { impl #ClientStateCommon for #HostClientState { @@ -104,6 +123,25 @@ pub(crate) fn impl_ClientStateCommon( } } + fn serialize_path(&self, path: #Path) -> core::result::Result<#PathBytes, #ClientError> { + match self { + #(#serialize_path_impl),* + } + } + + fn verify_membership_raw( + &self, + prefix: &#CommitmentPrefix, + proof: &#CommitmentProofBytes, + root: &#CommitmentRoot, + path: #PathBytes, + value: Vec, + ) -> core::result::Result<(), #ClientError> { + match self { + #(#verify_membership_raw_impl),* + } + } + fn verify_membership( &self, prefix: &#CommitmentPrefix, @@ -117,6 +155,18 @@ pub(crate) fn impl_ClientStateCommon( } } + fn verify_non_membership_raw( + &self, + prefix: &#CommitmentPrefix, + proof: &#CommitmentProofBytes, + root: &#CommitmentRoot, + path: #PathBytes, + ) -> core::result::Result<(), #ClientError> { + match self { + #(#verify_non_membership_raw_impl),* + } + } + fn verify_non_membership( &self, prefix: &#CommitmentPrefix, diff --git a/ibc-derive/src/utils.rs b/ibc-derive/src/utils.rs index ab3986951..e028b677f 100644 --- a/ibc-derive/src/utils.rs +++ b/ibc-derive/src/utils.rs @@ -50,6 +50,11 @@ impl Imports { quote! {#Prefix::host::types::path::Path} } + pub fn path_bytes(&self) -> TokenStream { + let Prefix = self.prefix(); + quote! {#Prefix::host::types::path::PathBytes} + } + pub fn consensus_state(&self) -> TokenStream { let Prefix = self.prefix(); quote! {#Prefix::client::context::consensus_state::ConsensusState} diff --git a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs index 4352ac22f..ddcb0c684 100644 --- a/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs +++ b/ibc-testkit/src/testapp/ibc/clients/mock/client_state.rs @@ -9,7 +9,7 @@ use ibc::core::commitment_types::commitment::{ }; use ibc::core::handler::types::error::ContextError; use ibc::core::host::types::identifiers::{ClientId, ClientType}; -use ibc::core::host::types::path::{ClientConsensusStatePath, ClientStatePath, Path}; +use ibc::core::host::types::path::{ClientConsensusStatePath, ClientStatePath, Path, PathBytes}; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Timestamp; use ibc::primitives::proto::{Any, Protobuf}; @@ -184,6 +184,10 @@ impl ClientStateCommon for MockClientState { Ok(()) } + fn serialize_path(&self, path: Path) -> Result { + Ok(path.to_string().into_bytes().into()) + } + fn verify_upgrade_client( &self, upgraded_client_state: Any, @@ -203,23 +207,23 @@ impl ClientStateCommon for MockClientState { Ok(()) } - fn verify_membership( + fn verify_membership_raw( &self, _prefix: &CommitmentPrefix, _proof: &CommitmentProofBytes, _root: &CommitmentRoot, - _path: Path, + _path: PathBytes, _value: Vec, ) -> Result<(), ClientError> { Ok(()) } - fn verify_non_membership( + fn verify_non_membership_raw( &self, _prefix: &CommitmentPrefix, _proof: &CommitmentProofBytes, _root: &CommitmentRoot, - _path: Path, + _path: PathBytes, ) -> Result<(), ClientError> { Ok(()) }