From 9febcf04071116e1da36aa8a110b5b00ce9a5d04 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 11:02:15 +0300 Subject: [PATCH 01/11] contract from template + endpoints --- Cargo.lock | 17 +++ Cargo.toml | 2 + client/src/create_and_update_clients.rs | 2 - client/wasm/src/lib.rs | 7 +- connection/Cargo.toml | 18 +++ connection/meta/Cargo.toml | 12 ++ connection/meta/src/main.rs | 3 + connection/multiversx.json | 3 + connection/src/lib.rs | 12 ++ connection/wasm/Cargo.lock | 188 ++++++++++++++++++++++++ connection/wasm/Cargo.toml | 34 +++++ connection/wasm/src/lib.rs | 26 ++++ host/src/host_config.rs | 6 + host/wasm/src/lib.rs | 7 +- 14 files changed, 331 insertions(+), 6 deletions(-) create mode 100644 connection/Cargo.toml create mode 100644 connection/meta/Cargo.toml create mode 100644 connection/meta/src/main.rs create mode 100644 connection/multiversx.json create mode 100644 connection/src/lib.rs create mode 100644 connection/wasm/Cargo.lock create mode 100644 connection/wasm/Cargo.toml create mode 100644 connection/wasm/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index f6cfa2c..180966f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -225,6 +225,23 @@ dependencies = [ "multiversx-sc", ] +[[package]] +name = "connection" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-scenario", + "num-bigint", +] + +[[package]] +name = "connection-meta" +version = "0.0.0" +dependencies = [ + "connection", + "multiversx-sc-meta-lib", +] + [[package]] name = "const-oid" version = "0.9.6" diff --git a/Cargo.toml b/Cargo.toml index 76ebe85..3d0a448 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ members = [ "client-impls/mock/meta", "client-impls/qbft", "client-impls/qbft/meta", + "connection", + "connection/meta", "host", "host/meta" ] diff --git a/client/src/create_and_update_clients.rs b/client/src/create_and_update_clients.rs index aa869d4..949398c 100644 --- a/client/src/create_and_update_clients.rs +++ b/client/src/create_and_update_clients.rs @@ -68,8 +68,6 @@ pub trait CreateAndUpdateClientsModule: let client_impl_mapper = self.client_registry(&args.client_type); require!(!client_impl_mapper.is_empty(), "Client not registered"); - // TODO: Check register function - let client_impl = client_impl_mapper.get(); let client_id = self.generate_client_identifier(&args.client_type); self.client_info(&client_id).set(ClientInfo { diff --git a/client/wasm/src/lib.rs b/client/wasm/src/lib.rs index fe61c2a..f00ce96 100644 --- a/client/wasm/src/lib.rs +++ b/client/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 7 +// Endpoints: 10 // Async Callback (empty): 1 -// Total number of exported functions: 10 +// Total number of exported functions: 13 #![no_std] @@ -23,6 +23,9 @@ multiversx_sc_wasm_adapter::endpoints! { createClient => create_client updateClient => update_client updateClientCommitments => update_client_commitments + setExpectedTimePerBlock => set_expected_time_per_block + registerClient => register_client + bindPort => bind_port getHostTimestamp => get_host_timestamp getCommitmentPrefix => get_commitment_prefix checkAndGetClient => check_and_get_client diff --git a/connection/Cargo.toml b/connection/Cargo.toml new file mode 100644 index 0000000..98233b0 --- /dev/null +++ b/connection/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "connection" +version = "0.0.0" +publish = false +edition = "2021" +authors = ["you"] + +[lib] +path = "src/lib.rs" + +[dependencies.multiversx-sc] +version = "=0.53.0" + +[dev-dependencies] +num-bigint = "0.4" + +[dev-dependencies.multiversx-sc-scenario] +version = "=0.53.0" diff --git a/connection/meta/Cargo.toml b/connection/meta/Cargo.toml new file mode 100644 index 0000000..52fa9a5 --- /dev/null +++ b/connection/meta/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "connection-meta" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies.connection] +path = ".." + +[dependencies.multiversx-sc-meta-lib] +version = "=0.53.0" +default-features = false diff --git a/connection/meta/src/main.rs b/connection/meta/src/main.rs new file mode 100644 index 0000000..815f0f0 --- /dev/null +++ b/connection/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta_lib::cli_main::(); +} diff --git a/connection/multiversx.json b/connection/multiversx.json new file mode 100644 index 0000000..7365539 --- /dev/null +++ b/connection/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/connection/src/lib.rs b/connection/src/lib.rs new file mode 100644 index 0000000..e7b485c --- /dev/null +++ b/connection/src/lib.rs @@ -0,0 +1,12 @@ +#![no_std] + +multiversx_sc::imports!(); + +#[multiversx_sc::contract] +pub trait Connection { + #[init] + fn init(&self) {} + + #[upgrade] + fn upgrade(&self) {} +} diff --git a/connection/wasm/Cargo.lock b/connection/wasm/Cargo.lock new file mode 100644 index 0000000..d899ddb --- /dev/null +++ b/connection/wasm/Cargo.lock @@ -0,0 +1,188 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "connection" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "connection-wasm" +version = "0.0.0" +dependencies = [ + "connection", + "multiversx-sc-wasm-adapter", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "multiversx-sc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a86a27b04bb7cca97ad8971ee57e6b978619623dde4ba9acae1d4ecb436f062" +dependencies = [ + "bitflags", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d7a5a8534e5dc9128cb8f15a65a21dd378e135c6016c7cd1491cd012bc8cb" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", + "unwrap-infallible", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffba1dce273ed5b61ee1b90aeea5c8c744617d0f12624f620768c144d83e753" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a6ee275d6b1c2b86394369df0bc62a3f25018cbab12668a191b89d88fdcf71" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab5bb42b3ce827227a5e38f3c24fbe0fb23d475425b049043e193186e36c590" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unwrap-infallible" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151ac09978d3c2862c4e39b557f4eceee2cc72150bc4cb4f16abf061b6e381fb" diff --git a/connection/wasm/Cargo.toml b/connection/wasm/Cargo.toml new file mode 100644 index 0000000..c5e87b6 --- /dev/null +++ b/connection/wasm/Cargo.toml @@ -0,0 +1,34 @@ +# Code generated by the multiversx-sc build system. DO NOT EDIT. + +# ########################################## +# ############## AUTO-GENERATED ############# +# ########################################## + +[package] +name = "connection-wasm" +version = "0.0.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" +overflow-checks = false + +[profile.dev] +panic = "abort" + +[dependencies.connection] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "=0.53.0" + +[workspace] +members = ["."] diff --git a/connection/wasm/src/lib.rs b/connection/wasm/src/lib.rs new file mode 100644 index 0000000..f21f664 --- /dev/null +++ b/connection/wasm/src/lib.rs @@ -0,0 +1,26 @@ +// Code generated by the multiversx-sc build system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Upgrade: 1 +// Endpoints: 0 +// Async Callback (empty): 1 +// Total number of exported functions: 3 + +#![no_std] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + connection + ( + init => init + upgrade => upgrade + ) +} + +multiversx_sc_wasm_adapter::async_callback_empty! {} diff --git a/host/src/host_config.rs b/host/src/host_config.rs index 122b9d9..57c44d4 100644 --- a/host/src/host_config.rs +++ b/host/src/host_config.rs @@ -12,6 +12,8 @@ pub trait HostConfigModule: + common_modules::host_lib::HostLibModule + common_modules::utils::UtilsModule { + #[only_owner] + #[endpoint(setExpectedTimePerBlock)] fn set_expected_time_per_block(&self, exp_time_per_block: Timestamp) { let mapper = self.host_info(); if !mapper.is_empty() { @@ -27,6 +29,8 @@ pub trait HostConfigModule: mapper.set(default_host_value); } + #[only_owner] + #[endpoint(registerClient)] fn register_client(&self, client_type: &ClientType, client: &ManagedAddress) { require!(self.is_valid_client_type(client_type), "Invalid client ID"); @@ -37,6 +41,8 @@ pub trait HostConfigModule: mapper.set(client); } + #[only_owner] + #[endpoint(bindPort)] fn bind_port(&self, port_id: &PortId, module: &ManagedAddress) { require!(self.is_valid_port_id(port_id), "Invalid Port ID"); self.require_valid_address(module); diff --git a/host/wasm/src/lib.rs b/host/wasm/src/lib.rs index 7cd7dd6..ef5d1b2 100644 --- a/host/wasm/src/lib.rs +++ b/host/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 4 +// Endpoints: 7 // Async Callback (empty): 1 -// Total number of exported functions: 7 +// Total number of exported functions: 10 #![no_std] @@ -20,6 +20,9 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade + setExpectedTimePerBlock => set_expected_time_per_block + registerClient => register_client + bindPort => bind_port getHostTimestamp => get_host_timestamp getCommitmentPrefix => get_commitment_prefix checkAndGetClient => check_and_get_client From 42ff7a34c6ae05c4ec4b90527f59a684e3c5c227 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 12:16:08 +0300 Subject: [PATCH 02/11] connection lib --- Cargo.lock | 2 + common/common-types/src/connection_types.rs | 6 +- common/common-types/src/lib.rs | 7 + connection/Cargo.toml | 6 + connection/src/connection_lib.rs | 163 ++++++++++++++++++++ connection/src/lib.rs | 4 +- connection/wasm/Cargo.lock | 17 ++ 7 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 connection/src/connection_lib.rs diff --git a/Cargo.lock b/Cargo.lock index 180966f..f88f45f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,6 +229,8 @@ dependencies = [ name = "connection" version = "0.0.0" dependencies = [ + "common-modules", + "common-types", "multiversx-sc", "multiversx-sc-scenario", "num-bigint", diff --git a/common/common-types/src/connection_types.rs b/common/common-types/src/connection_types.rs index 847aa2f..d7af626 100644 --- a/common/common-types/src/connection_types.rs +++ b/common/common-types/src/connection_types.rs @@ -51,12 +51,14 @@ pub mod counterparty { } pub mod version { + use crate::{FeatureId, FeatureVec}; + multiversx_sc::imports!(); multiversx_sc::derive_imports!(); #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem)] pub struct Data { - pub identifier: ManagedBuffer, - pub features: ManagedVec>, + pub identifier: FeatureId, + pub features: FeatureVec, } } diff --git a/common/common-types/src/lib.rs b/common/common-types/src/lib.rs index 0c71951..2f305fe 100644 --- a/common/common-types/src/lib.rs +++ b/common/common-types/src/lib.rs @@ -1,5 +1,7 @@ #![no_std] +use connection_types::version; + multiversx_sc::imports!(); pub mod channel_types; @@ -16,5 +18,10 @@ pub type ClientId = ManagedBuffer; pub type ClientType = ManagedBuffer; pub type ConnectionId = ManagedBuffer; pub type ChannelId = ManagedBuffer; +pub type Feature = ManagedBuffer; +pub type FeatureId = ManagedBuffer; pub type PortId = ManagedBuffer; pub type Path = ManagedBuffer; + +pub type VersionVec = ManagedVec>; +pub type FeatureVec = ManagedVec>; diff --git a/connection/Cargo.toml b/connection/Cargo.toml index 98233b0..079aed1 100644 --- a/connection/Cargo.toml +++ b/connection/Cargo.toml @@ -11,6 +11,12 @@ path = "src/lib.rs" [dependencies.multiversx-sc] version = "=0.53.0" +[dependencies.common-types] +path = "../common/common-types" + +[dependencies.common-modules] +path = "../common/common-modules" + [dev-dependencies] num-bigint = "0.4" diff --git a/connection/src/connection_lib.rs b/connection/src/connection_lib.rs new file mode 100644 index 0000000..6e0f224 --- /dev/null +++ b/connection/src/connection_lib.rs @@ -0,0 +1,163 @@ +use common_types::{connection_types::version, Feature, FeatureVec, VersionVec}; + +multiversx_sc::imports!(); + +static IBC_VERSION_IDENTIFIER: &[u8] = b"1"; +static ORDER_ORDERED: &[u8] = b"ORDER_ORDERED"; +static ORDER_UNORDERED: &[u8] = b"ORDER_UNORDERED"; + +#[multiversx_sc::module] +pub trait ConnectionLibModule { + /// returns the latest supported version of IBC used in connection version negotiation + fn default_ibc_version(&self) -> version::Data { + let mut version = version::Data { + identifier: ManagedBuffer::from(IBC_VERSION_IDENTIFIER), + features: ManagedVec::new(), + }; + version.features.push(ManagedBuffer::from(ORDER_ORDERED)); + version.features.push(ManagedBuffer::from(ORDER_UNORDERED)); + + version + } + + /// sets the supported versions to a given array + fn set_supported_versions( + &self, + supported_versions: VersionVec, + dest: &mut VersionVec, + ) { + require!(dest.is_empty(), "Versions already set"); + + *dest = supported_versions; + } + + /// returns true if the proposed version has a matching version + fn is_supported_version( + &self, + supported_versions: &VersionVec, + version: &version::Data, + ) -> bool { + let opt_found = self.find_supported_version(supported_versions, version); + match opt_found { + Some(found_version) => self.verify_proposed_version(&found_version, version), + None => false, + } + } + + fn is_supported( + &self, + supported_versions: &VersionVec, + feature: &Feature, + ) -> bool { + for sup_version in supported_versions { + if self.verify_supported_feature(&sup_version, feature) { + return true; + } + } + + false + } + + /// Verifies that the entire feature set in the proposed version is supported by this chain. + /// + /// If the feature set is empty it verifies that this is allowed for the specified version identifier + fn verify_proposed_version( + &self, + supported_version: &version::Data, + proposed_version: &version::Data, + ) -> bool { + if supported_version.identifier != proposed_version.identifier { + return false; + } + if proposed_version.features.is_empty() { + return false; + } + + for feature in &proposed_version.features { + if !self.verify_supported_feature(supported_version, &feature) { + return false; + } + } + + true + } + + /// returns the version with a matching version identifier if it exists + fn find_supported_version( + &self, + supported_versions: &VersionVec, + version: &version::Data, + ) -> Option> { + for supp_version in supported_versions { + if supp_version.identifier == version.identifier { + Some(supp_version); + } + } + + None + } + + /// Iterates over the descending ordered set of compatible IBC versions + /// and selects the first version with a version identifier that is + /// supported by the counterparty. + /// + /// The returned version contains a feature set with the intersection + /// of the features supported by the source and counterparty chains. + /// + /// If the feature set intersection is nil and this is not allowed for the chosen version identifier + /// then the search for a compatible version continues. + /// + /// This function is called in the ConnOpenTry handshake procedure. + fn pick_version( + &self, + supported_versions: &VersionVec, + counterparty_versions: &VersionVec, + ) -> version::Data { + for supp_version in supported_versions { + let opt_counterparty_version = + self.find_supported_version(counterparty_versions, &supp_version); + if opt_counterparty_version.is_none() { + continue; + } + + let counterparty_version = unsafe { opt_counterparty_version.unwrap_unchecked() }; + let feature_set = self.get_feature_set_intersection( + &supp_version.features, + &counterparty_version.features, + ); + if !feature_set.is_empty() { + return version::Data { + identifier: supp_version.identifier, + features: feature_set, + }; + } + } + + sc_panic!("No matching versions found") + } + + /// takes in a version and feature string and returns true if the feature is supported by the version + #[inline(always)] + fn verify_supported_feature( + &self, + version: &version::Data, + feature: &Feature, + ) -> bool { + version.features.contains(feature) + } + + fn get_feature_set_intersection( + &self, + source_feature_set: &FeatureVec, + counterparty_feature_set: &FeatureVec, + ) -> FeatureVec { + let mut feature_set = FeatureVec::new(); + for src_feature in source_feature_set { + if counterparty_feature_set.contains(&src_feature) { + feature_set.push(src_feature); + } + } + + feature_set + } +} diff --git a/connection/src/lib.rs b/connection/src/lib.rs index e7b485c..193f1c0 100644 --- a/connection/src/lib.rs +++ b/connection/src/lib.rs @@ -2,8 +2,10 @@ multiversx_sc::imports!(); +pub mod connection_lib; + #[multiversx_sc::contract] -pub trait Connection { +pub trait Connection: connection_lib::ConnectionLibModule { #[init] fn init(&self) {} diff --git a/connection/wasm/Cargo.lock b/connection/wasm/Cargo.lock index d899ddb..ac1048d 100644 --- a/connection/wasm/Cargo.lock +++ b/connection/wasm/Cargo.lock @@ -20,10 +20,27 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "common-modules" +version = "0.0.0" +dependencies = [ + "common-types", + "multiversx-sc", +] + +[[package]] +name = "common-types" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "connection" version = "0.0.0" dependencies = [ + "common-modules", + "common-types", "multiversx-sc", ] From 45d08460cbd47ffc534fd6b8b2f890b46d66a7d5 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 12:18:03 +0300 Subject: [PATCH 03/11] clippy --- connection/src/connection_lib.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/connection/src/connection_lib.rs b/connection/src/connection_lib.rs index 6e0f224..d8a4883 100644 --- a/connection/src/connection_lib.rs +++ b/connection/src/connection_lib.rs @@ -88,13 +88,9 @@ pub trait ConnectionLibModule { supported_versions: &VersionVec, version: &version::Data, ) -> Option> { - for supp_version in supported_versions { - if supp_version.identifier == version.identifier { - Some(supp_version); - } - } - - None + supported_versions + .into_iter() + .find(|supp_version| supp_version.identifier == version.identifier) } /// Iterates over the descending ordered set of compatible IBC versions From 9f4e031c76da2a95580592baa95f802d942c02ba Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 12:36:57 +0300 Subject: [PATCH 04/11] connection types --- connection/src/connection_types.rs | 54 ++++++++++++++++++++++++++++++ connection/src/lib.rs | 1 + 2 files changed, 55 insertions(+) create mode 100644 connection/src/connection_types.rs diff --git a/connection/src/connection_types.rs b/connection/src/connection_types.rs new file mode 100644 index 0000000..dee3f9d --- /dev/null +++ b/connection/src/connection_types.rs @@ -0,0 +1,54 @@ +use common_types::{ + channel_types::height, + connection_types::{counterparty, version}, + ClientId, ConnectionId, Hash, Timestamp, +}; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[derive(TypeAbi, TopDecode)] +pub struct MsgConnectionOpenInit { + pub client_id: ClientId, + pub counterparty: counterparty::Data, + pub version: version::Data, + pub delay_period: Timestamp, +} + +#[derive(TypeAbi, TopDecode)] +pub struct MsgConnectionOpenTry { + pub counterparty: counterparty::Data, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier + pub delay_period: Timestamp, + pub client_id: ClientId, // clientID of chainA + // TODO: Might be able to deserialize this directly + pub client_state_bytes: ManagedBuffer, // clientState that chainA has for chainB + pub counterparty_versions: version::Data, // supported versions of chain A + pub proof_init: Hash, // proof that chainA stored connectionEnd in state (on ConnOpenInit) + pub proof_client: Hash, // proof that chainA stored a light client of chainB + pub proof_consensus: Hash, // proof that chainA stored chainB's consensus state at consensus height + pub proof_height: height::Data, // height at which relayer constructs proof of A storing connectionEnd in state + pub consensus_height: height::Data, // latest height of chain B which chain A has stored in its chain B client + pub host_consensus_state_proof: Hash, // optional proof data for host state machines that are unable to introspect their own consensus state +} + +#[derive(TypeAbi, TopDecode)] +pub struct MsgConnectionOpenAck { + pub connection_id: ConnectionId, + // TODO: Might be able to deserialize this directly + pub client_state_bytes: ManagedBuffer, // client state for chainA on chainB + pub version: version::Data, // version that ChainB chose in ConnOpenTry + pub counterparty_connection_id: ConnectionId, + pub proof_try: Hash, // proof that connectionEnd was added to ChainB state in ConnOpenTry + pub proof_client: Hash, // proof of client state on chainB for chainA + pub proof_consensus: Hash, // proof that chainB has stored ConsensusState of chainA on its client + pub proof_height: height::Data, // height that relayer constructed proofTry + pub consensus_height: height::Data, // latest height of chainA that chainB has stored on its chainA client + pub host_consensus_state_proof: Hash, // optional proof data for host state machines that are unable to introspect their own consensus state +} + +#[derive(TypeAbi, TopDecode)] +pub struct MsgConnectionOpenConfirm { + pub connection_id: ConnectionId, + pub proof_ack: Hash, + pub proof_height: height::Data, +} diff --git a/connection/src/lib.rs b/connection/src/lib.rs index 193f1c0..82b86dd 100644 --- a/connection/src/lib.rs +++ b/connection/src/lib.rs @@ -3,6 +3,7 @@ multiversx_sc::imports!(); pub mod connection_lib; +pub mod connection_types; #[multiversx_sc::contract] pub trait Connection: connection_lib::ConnectionLibModule { From d984df34ac01d1582219bf7dbd1ea8a4bb162b62 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 12:46:48 +0300 Subject: [PATCH 05/11] renames + new imports --- Cargo.lock | 1 + connection/Cargo.toml | 3 +++ connection/src/conn_endpoints.rs | 14 ++++++++++++++ .../src/{connection_lib.rs => conn_lib.rs} | 0 .../src/{connection_types.rs => conn_types.rs} | 0 connection/src/lib.rs | 18 +++++++++++++++--- connection/wasm/Cargo.lock | 10 ++++++++++ connection/wasm/src/lib.rs | 11 +++++++++-- 8 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 connection/src/conn_endpoints.rs rename connection/src/{connection_lib.rs => conn_lib.rs} (100%) rename connection/src/{connection_types.rs => conn_types.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index f88f45f..d714ce3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,6 +231,7 @@ version = "0.0.0" dependencies = [ "common-modules", "common-types", + "host", "multiversx-sc", "multiversx-sc-scenario", "num-bigint", diff --git a/connection/Cargo.toml b/connection/Cargo.toml index 079aed1..7459f8c 100644 --- a/connection/Cargo.toml +++ b/connection/Cargo.toml @@ -17,6 +17,9 @@ path = "../common/common-types" [dependencies.common-modules] path = "../common/common-modules" +[dependencies.host] +path = "../host" + [dev-dependencies] num-bigint = "0.4" diff --git a/connection/src/conn_endpoints.rs b/connection/src/conn_endpoints.rs new file mode 100644 index 0000000..42b2355 --- /dev/null +++ b/connection/src/conn_endpoints.rs @@ -0,0 +1,14 @@ +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait ConnectionEndpointsModule: + host::commitment::CommitmentModule + + host::host_config::HostConfigModule + + host::host_views::HostViewsModule + + host::module_manager::ModuleManagerModule + + host::storage::StorageModule + + common_modules::client_lib::ClientLibModule + + common_modules::host_lib::HostLibModule + + common_modules::utils::UtilsModule +{ +} diff --git a/connection/src/connection_lib.rs b/connection/src/conn_lib.rs similarity index 100% rename from connection/src/connection_lib.rs rename to connection/src/conn_lib.rs diff --git a/connection/src/connection_types.rs b/connection/src/conn_types.rs similarity index 100% rename from connection/src/connection_types.rs rename to connection/src/conn_types.rs diff --git a/connection/src/lib.rs b/connection/src/lib.rs index 82b86dd..115a822 100644 --- a/connection/src/lib.rs +++ b/connection/src/lib.rs @@ -2,11 +2,23 @@ multiversx_sc::imports!(); -pub mod connection_lib; -pub mod connection_types; +pub mod conn_endpoints; +pub mod conn_lib; +pub mod conn_types; #[multiversx_sc::contract] -pub trait Connection: connection_lib::ConnectionLibModule { +pub trait Connection: + conn_lib::ConnectionLibModule + + conn_endpoints::ConnectionEndpointsModule + + host::commitment::CommitmentModule + + host::host_config::HostConfigModule + + host::host_views::HostViewsModule + + host::module_manager::ModuleManagerModule + + host::storage::StorageModule + + common_modules::client_lib::ClientLibModule + + common_modules::host_lib::HostLibModule + + common_modules::utils::UtilsModule +{ #[init] fn init(&self) {} diff --git a/connection/wasm/Cargo.lock b/connection/wasm/Cargo.lock index ac1048d..404e6ce 100644 --- a/connection/wasm/Cargo.lock +++ b/connection/wasm/Cargo.lock @@ -41,6 +41,7 @@ version = "0.0.0" dependencies = [ "common-modules", "common-types", + "host", "multiversx-sc", ] @@ -70,6 +71,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "host" +version = "0.0.0" +dependencies = [ + "common-modules", + "common-types", + "multiversx-sc", +] + [[package]] name = "multiversx-sc" version = "0.53.0" diff --git a/connection/wasm/src/lib.rs b/connection/wasm/src/lib.rs index f21f664..ebc2ddc 100644 --- a/connection/wasm/src/lib.rs +++ b/connection/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 0 +// Endpoints: 7 // Async Callback (empty): 1 -// Total number of exported functions: 3 +// Total number of exported functions: 10 #![no_std] @@ -20,6 +20,13 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade + setExpectedTimePerBlock => set_expected_time_per_block + registerClient => register_client + bindPort => bind_port + getHostTimestamp => get_host_timestamp + getCommitmentPrefix => get_commitment_prefix + checkAndGetClient => check_and_get_client + getCommitment => get_commitment ) } From f0f065a3f7d06784ea1143fda18a2d0ab08aba31 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 13:30:19 +0300 Subject: [PATCH 06/11] open connection endpoint --- client/src/create_and_update_clients.rs | 7 +- common/common-types/src/connection_types.rs | 6 +- connection/src/conn_endpoints.rs | 88 ++++++++++++++++++++- connection/src/events.rs | 9 +++ connection/src/lib.rs | 2 + connection/wasm/src/lib.rs | 6 +- host/src/storage.rs | 27 +++++++ 7 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 connection/src/events.rs diff --git a/client/src/create_and_update_clients.rs b/client/src/create_and_update_clients.rs index 949398c..17da76e 100644 --- a/client/src/create_and_update_clients.rs +++ b/client/src/create_and_update_clients.rs @@ -121,12 +121,7 @@ pub trait CreateAndUpdateClientsModule: &self, client_type: &ClientType, ) -> ClientId { - let next_client_seq = self.host_info().update(|host_info| { - let returned_val = host_info.next_client_seq; - host_info.next_client_seq += 1; - - returned_val - }); + let next_client_seq = self.get_next_client_seq(); sc_format!("{}-{}", client_type, next_client_seq) } diff --git a/common/common-types/src/connection_types.rs b/common/common-types/src/connection_types.rs index d7af626..77b1cc0 100644 --- a/common/common-types/src/connection_types.rs +++ b/common/common-types/src/connection_types.rs @@ -9,7 +9,7 @@ pub mod merkle_prefix { } pub mod connection_end { - use crate::ClientId; + use crate::{ClientId, Timestamp}; use super::{counterparty, version}; @@ -30,7 +30,7 @@ pub mod connection_end { pub versions: ManagedVec>, pub state: State, pub counterparty: counterparty::Data, - pub delay_period: u64, // TODO: Probably a timestamp + pub delay_period: Timestamp, } } @@ -56,7 +56,7 @@ pub mod version { multiversx_sc::imports!(); multiversx_sc::derive_imports!(); - #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem)] + #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem, Clone)] pub struct Data { pub identifier: FeatureId, pub features: FeatureVec, diff --git a/connection/src/conn_endpoints.rs b/connection/src/conn_endpoints.rs index 42b2355..52865da 100644 --- a/connection/src/conn_endpoints.rs +++ b/connection/src/conn_endpoints.rs @@ -1,8 +1,17 @@ +use common_types::{ + connection_types::{connection_end, version}, + ConnectionId, VersionVec, +}; + +use crate::conn_types::MsgConnectionOpenInit; + multiversx_sc::imports!(); #[multiversx_sc::module] pub trait ConnectionEndpointsModule: - host::commitment::CommitmentModule + crate::conn_lib::ConnectionLibModule + + crate::events::EventsModule + + host::commitment::CommitmentModule + host::host_config::HostConfigModule + host::host_views::HostViewsModule + host::module_manager::ModuleManagerModule @@ -11,4 +20,81 @@ pub trait ConnectionEndpointsModule: + common_modules::host_lib::HostLibModule + common_modules::utils::UtilsModule { + /// Initialises a connection attempt on chain A. + /// + /// The generated connection identifier is returned. + #[endpoint(connectionOpenInit)] + fn connection_open_init( + &self, + args: MsgConnectionOpenInit, + ) -> ConnectionId { + let connection_id = self.generate_connection_id(); + let connection_mapper = self.connection_info(&connection_id); + require!(connection_mapper.is_empty(), "Connection already exists"); + + // ensure the client exists + let _ = self.check_and_get_client(&args.client_id); + require!( + !args.counterparty.connection_id.is_empty(), + "Invalid counterparty connection ID" + ); + + let mut connection_info = connection_end::Data { + client_id: args.client_id, + counterparty: args.counterparty, + delay_period: args.delay_period, + state: connection_end::State::StateInit, + versions: VersionVec::new(), + }; + + self.set_versions_after_init(args.version, &mut connection_info.versions); + self.update_connection_commitment(&connection_id, &connection_info); + connection_mapper.set(connection_info); + + self.generated_connection_id_event(&connection_id); + + connection_id + } + + #[view(getCompatibleVersions)] + fn get_compatible_versions(&self) -> VersionVec { + VersionVec::from_single_item(self.default_ibc_version()) + } + + fn set_versions_after_init( + &self, + args_version: version::Data, + output: &mut VersionVec, + ) { + let compatible_versions = self.get_compatible_versions(); + if !args_version.features.is_empty() { + require!( + self.is_supported_version(&compatible_versions, &args_version), + "Version not supported" + ); + + output.push(args_version); + } else { + self.set_supported_versions(compatible_versions, output); + } + } + + fn update_connection_commitment( + &self, + connection_id: &ConnectionId, + connection_info: &connection_end::Data, + ) { + let connection_key = self.get_connection_commitment_key(connection_id); + let mut encoded_connection = ManagedBuffer::new(); + let _ = connection_info.top_encode(&mut encoded_connection); + let hashed_connection = self.crypto().keccak256(encoded_connection); + + self.commitments(&connection_key).set(&hashed_connection); + } + + fn generate_connection_id(&self) -> ConnectionId { + let next_conn_seq = self.get_next_connection_seq(); + + sc_format!("connection-{}", next_conn_seq) + } } diff --git a/connection/src/events.rs b/connection/src/events.rs new file mode 100644 index 0000000..3dac1f8 --- /dev/null +++ b/connection/src/events.rs @@ -0,0 +1,9 @@ +use common_types::ConnectionId; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait EventsModule { + #[event("generatedConnectionIdentifier")] + fn generated_connection_id_event(&self, connection_id: &ConnectionId); +} diff --git a/connection/src/lib.rs b/connection/src/lib.rs index 115a822..e5d4f31 100644 --- a/connection/src/lib.rs +++ b/connection/src/lib.rs @@ -5,11 +5,13 @@ multiversx_sc::imports!(); pub mod conn_endpoints; pub mod conn_lib; pub mod conn_types; +pub mod events; #[multiversx_sc::contract] pub trait Connection: conn_lib::ConnectionLibModule + conn_endpoints::ConnectionEndpointsModule + + events::EventsModule + host::commitment::CommitmentModule + host::host_config::HostConfigModule + host::host_views::HostViewsModule diff --git a/connection/wasm/src/lib.rs b/connection/wasm/src/lib.rs index ebc2ddc..aa1c4a8 100644 --- a/connection/wasm/src/lib.rs +++ b/connection/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 7 +// Endpoints: 9 // Async Callback (empty): 1 -// Total number of exported functions: 10 +// Total number of exported functions: 12 #![no_std] @@ -20,6 +20,8 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade + connectionOpenInit => connection_open_init + getCompatibleVersions => get_compatible_versions setExpectedTimePerBlock => set_expected_time_per_block registerClient => register_client bindPort => bind_port diff --git a/host/src/storage.rs b/host/src/storage.rs index e0e51a5..47557fa 100644 --- a/host/src/storage.rs +++ b/host/src/storage.rs @@ -47,6 +47,33 @@ pub trait StorageModule { self.commitments(commitment_hash).get() } + fn get_next_client_seq(&self) -> Sequence { + self.host_info().update(|host_info| { + let ret_val = host_info.next_client_seq; + host_info.next_client_seq += 1; + + ret_val + }) + } + + fn get_next_connection_seq(&self) -> Sequence { + self.host_info().update(|host_info| { + let ret_val = host_info.next_connection_seq; + host_info.next_connection_seq += 1; + + ret_val + }) + } + + fn get_next_channel_seq(&self) -> Sequence { + self.host_info().update(|host_info| { + let ret_val = host_info.next_channel_seq; + host_info.next_channel_seq += 1; + + ret_val + }) + } + #[storage_mapper("commitments")] fn commitments(&self, commitment_hash: &Hash) -> SingleValueMapper>; From 60b3b02833faf859bdf891c960658b1df11231c1 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 14:55:03 +0300 Subject: [PATCH 07/11] connection open try + refactor --- Cargo.lock | 1 + client-impls/client-common/src/lib.rs | 29 +++- client-impls/local-host/src/views.rs | 47 ++---- client-impls/mock/src/views.rs | 52 +++--- common/common-types/src/channel_types.rs | 20 +-- common/common-types/src/connection_types.rs | 22 +-- connection/Cargo.toml | 3 + connection/src/{ => common}/conn_lib.rs | 0 connection/src/{ => common}/conn_types.rs | 8 +- connection/src/{ => common}/events.rs | 0 connection/src/common/mod.rs | 4 + connection/src/common/verify_states.rs | 70 ++++++++ connection/src/conn_endpoints.rs | 80 +++++---- connection/src/conn_internal.rs | 174 ++++++++++++++++++++ connection/src/lib.rs | 11 +- connection/wasm/Cargo.lock | 9 + connection/wasm/src/lib.rs | 7 +- 17 files changed, 394 insertions(+), 143 deletions(-) rename connection/src/{ => common}/conn_lib.rs (100%) rename connection/src/{ => common}/conn_types.rs (89%) rename connection/src/{ => common}/events.rs (100%) create mode 100644 connection/src/common/mod.rs create mode 100644 connection/src/common/verify_states.rs create mode 100644 connection/src/conn_internal.rs diff --git a/Cargo.lock b/Cargo.lock index d714ce3..d33f44c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,6 +229,7 @@ dependencies = [ name = "connection" version = "0.0.0" dependencies = [ + "client-common", "common-modules", "common-types", "host", diff --git a/client-impls/client-common/src/lib.rs b/client-impls/client-common/src/lib.rs index 18ddc5f..d0d6340 100644 --- a/client-impls/client-common/src/lib.rs +++ b/client-impls/client-common/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use common_types::{channel_types::height, Hash, Timestamp}; +use common_types::{channel_types::height, ClientId, Hash, Timestamp}; multiversx_sc::imports!(); multiversx_sc::derive_imports!(); @@ -10,7 +10,7 @@ pub struct ConsensusStateUpdate { pub height: height::Data, } -#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, PartialEq)] +#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, PartialEq)] pub enum ClientStatus { None, Active, @@ -18,13 +18,36 @@ pub enum ClientStatus { Frozen, } -#[derive(TypeAbi, TopEncode)] +#[derive(TypeAbi, TopEncode, TopDecode)] pub struct GetLatestInfoResultType { pub latest_height: height::Data, pub latest_timestamp: Timestamp, pub client_status: ClientStatus, } +#[derive(TypeAbi, TopEncode, TopDecode)] +pub struct VerifyMembershipArgs { + pub client_id: ClientId, + pub height: height::Data, + pub delay_time_period: Timestamp, + pub delay_block_period: u64, + pub proof: Hash, + pub prefix: ManagedBuffer, + pub path: ManagedBuffer, + pub value: ManagedBuffer, +} + +#[derive(TypeAbi, TopEncode, TopDecode)] +pub struct VerifyNonMembershipArgs { + pub client_id: ClientId, + pub height: height::Data, + pub delay_time_period: Timestamp, + pub delay_block_period: u64, + pub proof: Hash, + pub prefix: ManagedBuffer, + pub path: ManagedBuffer, +} + #[multiversx_sc::module] pub trait CommonClientLogicModule { fn set_ibc_handler(&self, ibc_handler: &ManagedAddress) { diff --git a/client-impls/local-host/src/views.rs b/client-impls/local-host/src/views.rs index c14514f..40a91e8 100644 --- a/client-impls/local-host/src/views.rs +++ b/client-impls/local-host/src/views.rs @@ -1,4 +1,6 @@ -use client_common::{ClientStatus, GetLatestInfoResultType}; +use client_common::{ + ClientStatus, GetLatestInfoResultType, VerifyMembershipArgs, VerifyNonMembershipArgs, +}; use common_types::{channel_types::height, ClientId, Hash, Timestamp}; use host::{host_views::ProxyTrait as _, storage::ProxyTrait as _}; @@ -74,60 +76,41 @@ pub trait ViewsModule: /// /// Proof uses "DEFAULT_PROOF_BYTES" #[view(verifyMembership)] - fn verify_membership( - &self, - client_id: ClientId, - height: height::Data, - _delay_time_period: Timestamp, - _delay_block_period: u64, - proof: Hash, - prefix: ManagedBuffer, - path: ManagedBuffer, - value: ManagedBuffer, - ) -> bool { - self.require_valid_client_id(&client_id); - let _ = self.get_timestamp_at_height(&client_id, &height); - self.require_ibc_prefix(&prefix); + fn verify_membership(&self, args: VerifyMembershipArgs) -> bool { + self.require_valid_client_id(&args.client_id); + let _ = self.get_timestamp_at_height(&args.client_id, &args.height); + self.require_ibc_prefix(&args.prefix); let default_proof = self .crypto() .keccak256(ManagedBuffer::from(DEFAULT_PROOF_BYTES)); - require!(proof == default_proof, "Invalid proof"); + require!(args.proof == default_proof, "Invalid proof"); let ibc_handler = self.ibc_handler().get(); - let hashed_path = self.crypto().keccak256(path); + let hashed_path = self.crypto().keccak256(args.path); let hash: Hash = self .host_proxy(ibc_handler) .get_commitment(&hashed_path) .execute_on_dest_context(); - hash == self.crypto().keccak256(value) + hash == self.crypto().keccak256(args.value) } /// A generic proof verification method which verifies the absence of a given CommitmentPath at a specified height /// /// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24) #[view(verifyNonMembership)] - fn verify_non_membership( - &self, - client_id: ClientId, - height: height::Data, - _delay_time_period: Timestamp, - _delay_block_period: u64, - proof: Hash, - prefix: ManagedBuffer, - path: ManagedBuffer, - ) -> bool { - let _ = self.get_timestamp_at_height(&client_id, &height); - self.require_ibc_prefix(&prefix); + fn verify_non_membership(&self, args: VerifyNonMembershipArgs) -> bool { + let _ = self.get_timestamp_at_height(&args.client_id, &args.height); + self.require_ibc_prefix(&args.prefix); let default_proof = self .crypto() .keccak256(ManagedBuffer::from(DEFAULT_PROOF_BYTES)); - require!(proof == default_proof, "Invalid proof"); + require!(args.proof == default_proof, "Invalid proof"); let ibc_handler = self.ibc_handler().get(); - let hashed_path = self.crypto().keccak256(path); + let hashed_path = self.crypto().keccak256(args.path); let hash: Hash = self .host_proxy(ibc_handler) .get_commitment(&hashed_path) diff --git a/client-impls/mock/src/views.rs b/client-impls/mock/src/views.rs index 8c3f3cf..b0be1c4 100644 --- a/client-impls/mock/src/views.rs +++ b/client-impls/mock/src/views.rs @@ -1,4 +1,6 @@ -use client_common::{ClientStatus, GetLatestInfoResultType}; +use client_common::{ + ClientStatus, GetLatestInfoResultType, VerifyMembershipArgs, VerifyNonMembershipArgs, +}; use common_types::{channel_types::height, ClientId, Hash, Timestamp}; use host::host_views::ProxyTrait as _; @@ -58,43 +60,29 @@ pub trait ViewsModule: /// /// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24) #[view(verifyMembership)] - fn verify_membership( - &self, - client_id: ClientId, - height: height::Data, - _delay_time_period: Timestamp, - _delay_block_period: u64, - proof: Hash, - prefix: ManagedBuffer, - path: ManagedBuffer, - value: ManagedBuffer, - ) -> bool { - let _ = self.get_timestamp_at_height(&client_id, &height); - self.require_ibc_prefix(&prefix); - - let local_proof = self.encode_and_hash(&height, &prefix, &path, &value); - local_proof == proof + fn verify_membership(&self, args: VerifyMembershipArgs) -> bool { + let _ = self.get_timestamp_at_height(&args.client_id, &args.height); + self.require_ibc_prefix(&args.prefix); + + let local_proof = self.encode_and_hash(&args.height, &args.prefix, &args.path, &args.value); + local_proof == args.proof } /// A generic proof verification method which verifies the absence of a given CommitmentPath at a specified height /// /// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24) #[view(verifyNonMembership)] - fn verify_non_membership( - &self, - client_id: ClientId, - height: height::Data, - _delay_time_period: Timestamp, - _delay_block_period: u64, - proof: Hash, - prefix: ManagedBuffer, - path: ManagedBuffer, - ) -> bool { - let _ = self.get_timestamp_at_height(&client_id, &height); - self.require_ibc_prefix(&prefix); - - let local_proof = self.encode_and_hash(&height, &prefix, &path, &ManagedBuffer::new()); - local_proof == proof + fn verify_non_membership(&self, args: VerifyNonMembershipArgs) -> bool { + let _ = self.get_timestamp_at_height(&args.client_id, &args.height); + self.require_ibc_prefix(&args.prefix); + + let local_proof = self.encode_and_hash( + &args.height, + &args.prefix, + &args.path, + &ManagedBuffer::new(), + ); + local_proof == args.proof } /// returns the clientState corresponding to `clientId` diff --git a/common/common-types/src/channel_types.rs b/common/common-types/src/channel_types.rs index fe66f0b..22c9432 100644 --- a/common/common-types/src/channel_types.rs +++ b/common/common-types/src/channel_types.rs @@ -6,20 +6,20 @@ pub mod channel { #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode)] pub enum State { - StateUninitializedUnspecified, - StateInit, - StateTryOpen, - StateOpen, - StateClosed, - StateFlushing, - StateFlushComplete, + UninitializedUnspecified, + Init, + TryOpen, + Open, + Closed, + Flushing, + FlushComplete, } #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode)] pub enum Order { - OrderNoneUnspecified, - OrderUnordered, - OrderOrdered, + NoneUnspecified, + Unordered, + Ordered, } #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode)] diff --git a/common/common-types/src/connection_types.rs b/common/common-types/src/connection_types.rs index 77b1cc0..63d4f0a 100644 --- a/common/common-types/src/connection_types.rs +++ b/common/common-types/src/connection_types.rs @@ -2,32 +2,32 @@ pub mod merkle_prefix { multiversx_sc::imports!(); multiversx_sc::derive_imports!(); - #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode)] + #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Clone)] pub struct Data { pub key_prefix: ManagedBuffer, } } pub mod connection_end { - use crate::{ClientId, Timestamp}; + use crate::{ClientId, Timestamp, VersionVec}; - use super::{counterparty, version}; + use super::counterparty; multiversx_sc::imports!(); multiversx_sc::derive_imports!(); - #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode)] + #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Clone, Copy)] pub enum State { - StateUninitializedUnspecified, - StateInit, - StateTryOpen, - StateOpen, + UninitializedUnspecified, + Init, + TryOpen, + Open, } - #[derive(TypeAbi, TopEncode, TopDecode)] + #[derive(TypeAbi, TopEncode, TopDecode, Clone)] pub struct Data { pub client_id: ClientId, - pub versions: ManagedVec>, + pub versions: VersionVec, pub state: State, pub counterparty: counterparty::Data, pub delay_period: Timestamp, @@ -42,7 +42,7 @@ pub mod counterparty { multiversx_sc::imports!(); multiversx_sc::derive_imports!(); - #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode)] + #[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Clone)] pub struct Data { pub client_id: ClientId, pub connection_id: ConnectionId, diff --git a/connection/Cargo.toml b/connection/Cargo.toml index 7459f8c..b9570a2 100644 --- a/connection/Cargo.toml +++ b/connection/Cargo.toml @@ -20,6 +20,9 @@ path = "../common/common-modules" [dependencies.host] path = "../host" +[dependencies.client-common] +path = "../client-impls/client-common" + [dev-dependencies] num-bigint = "0.4" diff --git a/connection/src/conn_lib.rs b/connection/src/common/conn_lib.rs similarity index 100% rename from connection/src/conn_lib.rs rename to connection/src/common/conn_lib.rs diff --git a/connection/src/conn_types.rs b/connection/src/common/conn_types.rs similarity index 89% rename from connection/src/conn_types.rs rename to connection/src/common/conn_types.rs index dee3f9d..3666e16 100644 --- a/connection/src/conn_types.rs +++ b/connection/src/common/conn_types.rs @@ -1,7 +1,7 @@ use common_types::{ channel_types::height, connection_types::{counterparty, version}, - ClientId, ConnectionId, Hash, Timestamp, + ClientId, ConnectionId, Hash, Timestamp, VersionVec, }; multiversx_sc::imports!(); @@ -19,10 +19,9 @@ pub struct MsgConnectionOpenInit { pub struct MsgConnectionOpenTry { pub counterparty: counterparty::Data, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier pub delay_period: Timestamp, - pub client_id: ClientId, // clientID of chainA - // TODO: Might be able to deserialize this directly + pub client_id: ClientId, // clientID of chainA pub client_state_bytes: ManagedBuffer, // clientState that chainA has for chainB - pub counterparty_versions: version::Data, // supported versions of chain A + pub counterparty_versions: VersionVec, // supported versions of chain A pub proof_init: Hash, // proof that chainA stored connectionEnd in state (on ConnOpenInit) pub proof_client: Hash, // proof that chainA stored a light client of chainB pub proof_consensus: Hash, // proof that chainA stored chainB's consensus state at consensus height @@ -34,7 +33,6 @@ pub struct MsgConnectionOpenTry { #[derive(TypeAbi, TopDecode)] pub struct MsgConnectionOpenAck { pub connection_id: ConnectionId, - // TODO: Might be able to deserialize this directly pub client_state_bytes: ManagedBuffer, // client state for chainA on chainB pub version: version::Data, // version that ChainB chose in ConnOpenTry pub counterparty_connection_id: ConnectionId, diff --git a/connection/src/events.rs b/connection/src/common/events.rs similarity index 100% rename from connection/src/events.rs rename to connection/src/common/events.rs diff --git a/connection/src/common/mod.rs b/connection/src/common/mod.rs new file mode 100644 index 0000000..bc6804b --- /dev/null +++ b/connection/src/common/mod.rs @@ -0,0 +1,4 @@ +pub mod conn_lib; +pub mod conn_types; +pub mod events; +pub mod verify_states; diff --git a/connection/src/common/verify_states.rs b/connection/src/common/verify_states.rs new file mode 100644 index 0000000..6e72724 --- /dev/null +++ b/connection/src/common/verify_states.rs @@ -0,0 +1,70 @@ +use common_types::{ + connection_types::{connection_end, counterparty, merkle_prefix}, + ConnectionId, Hash, +}; + +use crate::conn_internal::{ + VerifyClientStateArgs, VerifyConnectionStateArgs, VerifyConsensusStateArgs, +}; + +use super::conn_types::MsgConnectionOpenTry; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait VerifyStatesModule: + super::conn_lib::ConnectionLibModule + + crate::conn_internal::ConnectionInternalModule + + host::commitment::CommitmentModule + + host::host_config::HostConfigModule + + host::host_views::HostViewsModule + + host::module_manager::ModuleManagerModule + + host::storage::StorageModule + + common_modules::client_lib::ClientLibModule + + common_modules::host_lib::HostLibModule + + common_modules::utils::UtilsModule +{ + fn verify_all_states_open_try( + &self, + connection_info: connection_end::Data, + self_consensus_state: &Hash, + args: MsgConnectionOpenTry, + ) { + let expected_counterparty = counterparty::Data { + client_id: args.client_id, + connection_id: ConnectionId::new(), + prefix: merkle_prefix::Data { + key_prefix: self.get_commitment_prefix(), + }, + }; + let expected_connection = connection_end::Data { + client_id: args.counterparty.client_id, + counterparty: expected_counterparty, + state: connection_end::State::Init, + delay_period: args.delay_period, + versions: args.counterparty_versions, + }; + + self.verify_connection_state(VerifyConnectionStateArgs { + connection_info: connection_info.clone(), + height: args.proof_height, + proof: args.proof_init, + counterparty_connection_id: args.counterparty.connection_id, + counterparty_connection_info: expected_connection, + }); + self.verify_client_state(VerifyClientStateArgs { + connection_info: connection_info.clone(), + height: args.proof_height, + path: self.get_client_state_path(&connection_info.counterparty.client_id), + proof: args.proof_client, + client_state_bytes: args.client_state_bytes, + }); + self.verify_consensus_state(VerifyConsensusStateArgs { + connection_info, + height: args.proof_height, + consensus_height: args.consensus_height, + proof: args.proof_consensus, + consensus_state_bytes: self_consensus_state.as_managed_buffer().clone(), + }); + } +} diff --git a/connection/src/conn_endpoints.rs b/connection/src/conn_endpoints.rs index 52865da..95cfaf9 100644 --- a/connection/src/conn_endpoints.rs +++ b/connection/src/conn_endpoints.rs @@ -1,16 +1,15 @@ -use common_types::{ - connection_types::{connection_end, version}, - ConnectionId, VersionVec, -}; +use common_types::{connection_types::connection_end, ConnectionId, VersionVec}; -use crate::conn_types::MsgConnectionOpenInit; +use crate::common::conn_types::{MsgConnectionOpenInit, MsgConnectionOpenTry}; multiversx_sc::imports!(); #[multiversx_sc::module] pub trait ConnectionEndpointsModule: - crate::conn_lib::ConnectionLibModule - + crate::events::EventsModule + crate::common::conn_lib::ConnectionLibModule + + crate::common::verify_states::VerifyStatesModule + + crate::conn_internal::ConnectionInternalModule + + crate::common::events::EventsModule + host::commitment::CommitmentModule + host::host_config::HostConfigModule + host::host_views::HostViewsModule @@ -20,6 +19,8 @@ pub trait ConnectionEndpointsModule: + common_modules::host_lib::HostLibModule + common_modules::utils::UtilsModule { + // TODO: Check if those endpoints need special permissions + /// Initialises a connection attempt on chain A. /// /// The generated connection identifier is returned. @@ -43,7 +44,7 @@ pub trait ConnectionEndpointsModule: client_id: args.client_id, counterparty: args.counterparty, delay_period: args.delay_period, - state: connection_end::State::StateInit, + state: connection_end::State::Init, versions: VersionVec::new(), }; @@ -56,45 +57,40 @@ pub trait ConnectionEndpointsModule: connection_id } - #[view(getCompatibleVersions)] - fn get_compatible_versions(&self) -> VersionVec { - VersionVec::from_single_item(self.default_ibc_version()) - } - - fn set_versions_after_init( + /// relays notice of a connection attempt on chain A to chain B (this code is executed on chain B) + #[endpoint(connectionOpenTry)] + fn connection_open_try( &self, - args_version: version::Data, - output: &mut VersionVec, - ) { - let compatible_versions = self.get_compatible_versions(); - if !args_version.features.is_empty() { - require!( - self.is_supported_version(&compatible_versions, &args_version), - "Version not supported" - ); + args: MsgConnectionOpenTry, + ) -> ConnectionId { + require!( + !args.counterparty_versions.is_empty(), + "Empty counterparty versions" + ); - output.push(args_version); - } else { - self.set_supported_versions(compatible_versions, output); - } - } + let self_consensus_state = args.host_consensus_state_proof.clone(); + let connection_id = self.generate_connection_id(); + let connection_mapper = self.connection_info(&connection_id); + require!(connection_mapper.is_empty(), "Connection already exists"); - fn update_connection_commitment( - &self, - connection_id: &ConnectionId, - connection_info: &connection_end::Data, - ) { - let connection_key = self.get_connection_commitment_key(connection_id); - let mut encoded_connection = ManagedBuffer::new(); - let _ = connection_info.top_encode(&mut encoded_connection); - let hashed_connection = self.crypto().keccak256(encoded_connection); + // ensure the client exists + let _ = self.check_and_get_client(&args.client_id); - self.commitments(&connection_key).set(&hashed_connection); - } + let compatible_versions = self.get_compatible_versions(); + let picked_version = self.pick_version(&compatible_versions, &args.counterparty_versions); + let connection_info = connection_end::Data { + client_id: args.client_id.clone(), + counterparty: args.counterparty.clone(), + delay_period: args.delay_period, + state: connection_end::State::TryOpen, + versions: ManagedVec::from_single_item(picked_version), + }; + connection_mapper.set(&connection_info); - fn generate_connection_id(&self) -> ConnectionId { - let next_conn_seq = self.get_next_connection_seq(); + self.verify_all_states_open_try(connection_info.clone(), &self_consensus_state, args); + self.update_connection_commitment(&connection_id, &connection_info); + self.generated_connection_id_event(&connection_id); - sc_format!("connection-{}", next_conn_seq) + connection_id } } diff --git a/connection/src/conn_internal.rs b/connection/src/conn_internal.rs new file mode 100644 index 0000000..4ebc0f5 --- /dev/null +++ b/connection/src/conn_internal.rs @@ -0,0 +1,174 @@ +use client_common::VerifyMembershipArgs; +use common_types::{ + channel_types::height, + connection_types::{connection_end, version}, + ConnectionId, Hash, VersionVec, +}; + +multiversx_sc::imports!(); + +pub struct VerifyClientStateArgs { + pub connection_info: connection_end::Data, + pub height: height::Data, + pub path: ManagedBuffer, + pub proof: Hash, + pub client_state_bytes: ManagedBuffer, +} + +pub struct VerifyConsensusStateArgs { + pub connection_info: connection_end::Data, + pub height: height::Data, + pub consensus_height: height::Data, + pub proof: Hash, + pub consensus_state_bytes: ManagedBuffer, +} + +pub struct VerifyConnectionStateArgs { + pub connection_info: connection_end::Data, + pub height: height::Data, + pub proof: Hash, + pub counterparty_connection_id: ConnectionId, + pub counterparty_connection_info: connection_end::Data, +} + +mod client_proxy { + use client_common::{VerifyMembershipArgs, VerifyNonMembershipArgs}; + + multiversx_sc::imports!(); + + #[multiversx_sc::proxy] + pub trait ClientProxy { + #[view(verifyMembership)] + fn verify_membership(&self, args: VerifyMembershipArgs) -> bool; + + #[view(verifyNonMembership)] + fn verify_non_membership(&self, args: VerifyNonMembershipArgs) -> bool; + } +} + +#[multiversx_sc::module] +pub trait ConnectionInternalModule: + crate::common::conn_lib::ConnectionLibModule + + host::commitment::CommitmentModule + + host::host_config::HostConfigModule + + host::host_views::HostViewsModule + + host::module_manager::ModuleManagerModule + + host::storage::StorageModule + + common_modules::client_lib::ClientLibModule + + common_modules::host_lib::HostLibModule + + common_modules::utils::UtilsModule +{ + #[view(getCompatibleVersions)] + fn get_compatible_versions(&self) -> VersionVec { + VersionVec::from_single_item(self.default_ibc_version()) + } + + fn set_versions_after_init( + &self, + args_version: version::Data, + output: &mut VersionVec, + ) { + let compatible_versions = self.get_compatible_versions(); + if !args_version.features.is_empty() { + require!( + self.is_supported_version(&compatible_versions, &args_version), + "Version not supported" + ); + + output.push(args_version); + } else { + self.set_supported_versions(compatible_versions, output); + } + } + + fn update_connection_commitment( + &self, + connection_id: &ConnectionId, + connection_info: &connection_end::Data, + ) { + let connection_key = self.get_connection_commitment_key(connection_id); + let mut encoded_connection = ManagedBuffer::new(); + let _ = connection_info.top_encode(&mut encoded_connection); + let hashed_connection = self.crypto().keccak256(encoded_connection); + + self.commitments(&connection_key).set(&hashed_connection); + } + + fn generate_connection_id(&self) -> ConnectionId { + let next_conn_seq = self.get_next_connection_seq(); + + sc_format!("connection-{}", next_conn_seq) + } + + fn verify_client_state(&self, args: VerifyClientStateArgs) { + let client = self.check_and_get_client(&args.connection_info.client_id); + let args = VerifyMembershipArgs { + client_id: args.connection_info.client_id, + height: args.height, + delay_time_period: 0, + delay_block_period: 0, + proof: args.proof, + prefix: args.connection_info.counterparty.prefix.key_prefix, + path: args.path, + value: args.client_state_bytes, + }; + let membership_result: bool = self + .client_proxy_impl(client) + .verify_membership(args) + .execute_on_dest_context(); + require!(membership_result, "Failed to verify client state"); + } + + fn verify_consensus_state(&self, args: VerifyConsensusStateArgs) { + let client = self.check_and_get_client(&args.connection_info.client_id); + let consensus_state_path = self.get_consensus_state_path( + &args.connection_info.counterparty.client_id, + args.consensus_height.revision_number, + args.consensus_height.revision_height, + ); + let args = VerifyMembershipArgs { + client_id: args.connection_info.client_id, + height: args.height, + delay_time_period: 0, + delay_block_period: 0, + proof: args.proof, + prefix: args.connection_info.counterparty.prefix.key_prefix, + path: consensus_state_path, + value: args.consensus_state_bytes, + }; + let membership_result: bool = self + .client_proxy_impl(client) + .verify_membership(args) + .execute_on_dest_context(); + require!(membership_result, "Failed to verify consensus state"); + } + + fn verify_connection_state(&self, args: VerifyConnectionStateArgs) { + let client = self.check_and_get_client(&args.connection_info.client_id); + let connection_path = self.get_connection_path(&args.counterparty_connection_id); + let mut encoded_connection = ManagedBuffer::new(); + let _ = args + .counterparty_connection_info + .top_encode(&mut encoded_connection); + + let args = VerifyMembershipArgs { + client_id: args.connection_info.client_id, + height: args.height, + delay_time_period: 0, + delay_block_period: 0, + proof: args.proof, + prefix: args.connection_info.counterparty.prefix.key_prefix, + path: connection_path, + value: encoded_connection, + }; + let membership_result: bool = self + .client_proxy_impl(client) + .verify_membership(args) + .execute_on_dest_context(); + require!(membership_result, "Failed to verify connection state"); + } + + #[proxy] + fn client_proxy_impl(&self, sc_address: ManagedAddress) + -> client_proxy::ClientProxy; +} diff --git a/connection/src/lib.rs b/connection/src/lib.rs index e5d4f31..53c3593 100644 --- a/connection/src/lib.rs +++ b/connection/src/lib.rs @@ -2,16 +2,17 @@ multiversx_sc::imports!(); +pub mod common; pub mod conn_endpoints; -pub mod conn_lib; -pub mod conn_types; -pub mod events; +pub mod conn_internal; #[multiversx_sc::contract] pub trait Connection: - conn_lib::ConnectionLibModule + common::conn_lib::ConnectionLibModule + + common::verify_states::VerifyStatesModule + + conn_internal::ConnectionInternalModule + conn_endpoints::ConnectionEndpointsModule - + events::EventsModule + + common::events::EventsModule + host::commitment::CommitmentModule + host::host_config::HostConfigModule + host::host_views::HostViewsModule diff --git a/connection/wasm/Cargo.lock b/connection/wasm/Cargo.lock index 404e6ce..2222e00 100644 --- a/connection/wasm/Cargo.lock +++ b/connection/wasm/Cargo.lock @@ -20,6 +20,14 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "client-common" +version = "0.0.0" +dependencies = [ + "common-types", + "multiversx-sc", +] + [[package]] name = "common-modules" version = "0.0.0" @@ -39,6 +47,7 @@ dependencies = [ name = "connection" version = "0.0.0" dependencies = [ + "client-common", "common-modules", "common-types", "host", diff --git a/connection/wasm/src/lib.rs b/connection/wasm/src/lib.rs index aa1c4a8..9a755e8 100644 --- a/connection/wasm/src/lib.rs +++ b/connection/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 9 +// Endpoints: 10 // Async Callback (empty): 1 -// Total number of exported functions: 12 +// Total number of exported functions: 13 #![no_std] @@ -20,8 +20,9 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade - connectionOpenInit => connection_open_init getCompatibleVersions => get_compatible_versions + connectionOpenInit => connection_open_init + connectionOpenTry => connection_open_try setExpectedTimePerBlock => set_expected_time_per_block registerClient => register_client bindPort => bind_port From 7754fb5f41c08e31f43374b1916c2f853b4d549f Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 14:59:06 +0300 Subject: [PATCH 08/11] move conn_internal to common --- connection/src/{ => common}/conn_internal.rs | 0 connection/src/common/mod.rs | 1 + connection/src/common/verify_states.rs | 4 ++-- connection/src/conn_endpoints.rs | 2 +- connection/src/lib.rs | 3 +-- 5 files changed, 5 insertions(+), 5 deletions(-) rename connection/src/{ => common}/conn_internal.rs (100%) diff --git a/connection/src/conn_internal.rs b/connection/src/common/conn_internal.rs similarity index 100% rename from connection/src/conn_internal.rs rename to connection/src/common/conn_internal.rs diff --git a/connection/src/common/mod.rs b/connection/src/common/mod.rs index bc6804b..fcbceeb 100644 --- a/connection/src/common/mod.rs +++ b/connection/src/common/mod.rs @@ -1,3 +1,4 @@ +pub mod conn_internal; pub mod conn_lib; pub mod conn_types; pub mod events; diff --git a/connection/src/common/verify_states.rs b/connection/src/common/verify_states.rs index 6e72724..4a5b958 100644 --- a/connection/src/common/verify_states.rs +++ b/connection/src/common/verify_states.rs @@ -3,7 +3,7 @@ use common_types::{ ConnectionId, Hash, }; -use crate::conn_internal::{ +use super::conn_internal::{ VerifyClientStateArgs, VerifyConnectionStateArgs, VerifyConsensusStateArgs, }; @@ -14,7 +14,7 @@ multiversx_sc::imports!(); #[multiversx_sc::module] pub trait VerifyStatesModule: super::conn_lib::ConnectionLibModule - + crate::conn_internal::ConnectionInternalModule + + super::conn_internal::ConnectionInternalModule + host::commitment::CommitmentModule + host::host_config::HostConfigModule + host::host_views::HostViewsModule diff --git a/connection/src/conn_endpoints.rs b/connection/src/conn_endpoints.rs index 95cfaf9..04597e7 100644 --- a/connection/src/conn_endpoints.rs +++ b/connection/src/conn_endpoints.rs @@ -8,7 +8,7 @@ multiversx_sc::imports!(); pub trait ConnectionEndpointsModule: crate::common::conn_lib::ConnectionLibModule + crate::common::verify_states::VerifyStatesModule - + crate::conn_internal::ConnectionInternalModule + + crate::common::conn_internal::ConnectionInternalModule + crate::common::events::EventsModule + host::commitment::CommitmentModule + host::host_config::HostConfigModule diff --git a/connection/src/lib.rs b/connection/src/lib.rs index 53c3593..b5f223e 100644 --- a/connection/src/lib.rs +++ b/connection/src/lib.rs @@ -4,13 +4,12 @@ multiversx_sc::imports!(); pub mod common; pub mod conn_endpoints; -pub mod conn_internal; #[multiversx_sc::contract] pub trait Connection: common::conn_lib::ConnectionLibModule + common::verify_states::VerifyStatesModule - + conn_internal::ConnectionInternalModule + + common::conn_internal::ConnectionInternalModule + conn_endpoints::ConnectionEndpointsModule + common::events::EventsModule + host::commitment::CommitmentModule From f1468b87d1796ba71dadf3a7d49a91818a72e1a7 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 15:24:38 +0300 Subject: [PATCH 09/11] connection open ack --- connection/src/common/conn_types.rs | 2 +- connection/src/common/verify_states.rs | 49 ++++++++++++++++++++++++-- connection/src/conn_endpoints.rs | 31 +++++++++++++++- connection/wasm/src/lib.rs | 5 +-- 4 files changed, 81 insertions(+), 6 deletions(-) diff --git a/connection/src/common/conn_types.rs b/connection/src/common/conn_types.rs index 3666e16..c2b7e00 100644 --- a/connection/src/common/conn_types.rs +++ b/connection/src/common/conn_types.rs @@ -30,7 +30,7 @@ pub struct MsgConnectionOpenTry { pub host_consensus_state_proof: Hash, // optional proof data for host state machines that are unable to introspect their own consensus state } -#[derive(TypeAbi, TopDecode)] +#[derive(TypeAbi, TopDecode, Clone)] pub struct MsgConnectionOpenAck { pub connection_id: ConnectionId, pub client_state_bytes: ManagedBuffer, // client state for chainA on chainB diff --git a/connection/src/common/verify_states.rs b/connection/src/common/verify_states.rs index 4a5b958..8c79437 100644 --- a/connection/src/common/verify_states.rs +++ b/connection/src/common/verify_states.rs @@ -3,8 +3,9 @@ use common_types::{ ConnectionId, Hash, }; -use super::conn_internal::{ - VerifyClientStateArgs, VerifyConnectionStateArgs, VerifyConsensusStateArgs, +use super::{ + conn_internal::{VerifyClientStateArgs, VerifyConnectionStateArgs, VerifyConsensusStateArgs}, + conn_types::MsgConnectionOpenAck, }; use super::conn_types::MsgConnectionOpenTry; @@ -67,4 +68,48 @@ pub trait VerifyStatesModule: consensus_state_bytes: self_consensus_state.as_managed_buffer().clone(), }); } + + fn verify_all_states_open_ack( + &self, + connection_info: connection_end::Data, + self_consensus_state: &Hash, + args: MsgConnectionOpenAck, + ) { + let expected_counterparty = counterparty::Data { + client_id: connection_info.client_id.clone(), + connection_id: args.connection_id, + prefix: merkle_prefix::Data { + key_prefix: self.get_commitment_prefix(), + }, + }; + let expected_connection = connection_end::Data { + client_id: connection_info.counterparty.client_id.clone(), + counterparty: expected_counterparty, + state: connection_end::State::TryOpen, + delay_period: connection_info.delay_period, + versions: ManagedVec::from_single_item(args.version), + }; + + self.verify_connection_state(VerifyConnectionStateArgs { + connection_info: connection_info.clone(), + height: args.proof_height, + proof: args.proof_try, + counterparty_connection_id: args.counterparty_connection_id, + counterparty_connection_info: expected_connection, + }); + self.verify_client_state(VerifyClientStateArgs { + connection_info: connection_info.clone(), + height: args.proof_height, + path: self.get_client_state_path(&connection_info.counterparty.client_id), + proof: args.proof_client, + client_state_bytes: args.client_state_bytes, + }); + self.verify_consensus_state(VerifyConsensusStateArgs { + connection_info, + height: args.proof_height, + consensus_height: args.consensus_height, + proof: args.proof_consensus, + consensus_state_bytes: self_consensus_state.as_managed_buffer().clone(), + }); + } } diff --git a/connection/src/conn_endpoints.rs b/connection/src/conn_endpoints.rs index 04597e7..7f3222b 100644 --- a/connection/src/conn_endpoints.rs +++ b/connection/src/conn_endpoints.rs @@ -1,6 +1,8 @@ use common_types::{connection_types::connection_end, ConnectionId, VersionVec}; -use crate::common::conn_types::{MsgConnectionOpenInit, MsgConnectionOpenTry}; +use crate::common::conn_types::{ + MsgConnectionOpenAck, MsgConnectionOpenInit, MsgConnectionOpenTry, +}; multiversx_sc::imports!(); @@ -93,4 +95,31 @@ pub trait ConnectionEndpointsModule: connection_id } + + /// relays acceptance of a connection open attempt from chain B back to chain A (this code is executed on chain A) + #[endpoint(connectionOpenAck)] + fn connection_open_ack(&self, args: MsgConnectionOpenAck) { + let connection_mapper = self.connection_info(&args.connection_id); + require!(!connection_mapper.is_empty(), "Connection does not exist"); + + let mut connection_info = connection_mapper.get(); + require!( + matches!(connection_info.state, connection_end::State::Init), + "Invalid connection state" + ); + + let self_consensus_state = args.host_consensus_state_proof.clone(); + self.verify_all_states_open_ack( + connection_info.clone(), + &self_consensus_state, + args.clone(), + ); + + connection_info.state = connection_end::State::Open; + connection_info.counterparty.connection_id = args.counterparty_connection_id; + connection_info.versions = ManagedVec::from_single_item(args.version); + + connection_mapper.set(&connection_info); + self.update_connection_commitment(&args.connection_id, &connection_info); + } } diff --git a/connection/wasm/src/lib.rs b/connection/wasm/src/lib.rs index 9a755e8..b5d1650 100644 --- a/connection/wasm/src/lib.rs +++ b/connection/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 10 +// Endpoints: 11 // Async Callback (empty): 1 -// Total number of exported functions: 13 +// Total number of exported functions: 14 #![no_std] @@ -23,6 +23,7 @@ multiversx_sc_wasm_adapter::endpoints! { getCompatibleVersions => get_compatible_versions connectionOpenInit => connection_open_init connectionOpenTry => connection_open_try + connectionOpenAck => connection_open_ack setExpectedTimePerBlock => set_expected_time_per_block registerClient => register_client bindPort => bind_port From f02d98439946413b2d45454a9622632c8fb393d4 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 23 Sep 2024 15:36:48 +0300 Subject: [PATCH 10/11] connection open confirm --- connection/src/common/verify_states.rs | 31 ++++++++++++++++- connection/src/conn_endpoints.rs | 46 +++++++++++++++++++++++--- connection/wasm/src/lib.rs | 5 +-- 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/connection/src/common/verify_states.rs b/connection/src/common/verify_states.rs index 8c79437..41c687b 100644 --- a/connection/src/common/verify_states.rs +++ b/connection/src/common/verify_states.rs @@ -5,7 +5,7 @@ use common_types::{ use super::{ conn_internal::{VerifyClientStateArgs, VerifyConnectionStateArgs, VerifyConsensusStateArgs}, - conn_types::MsgConnectionOpenAck, + conn_types::{MsgConnectionOpenAck, MsgConnectionOpenConfirm}, }; use super::conn_types::MsgConnectionOpenTry; @@ -112,4 +112,33 @@ pub trait VerifyStatesModule: consensus_state_bytes: self_consensus_state.as_managed_buffer().clone(), }); } + + fn verify_all_states_open_confirm( + &self, + connection_info: connection_end::Data, + args: MsgConnectionOpenConfirm, + ) { + let expected_counterparty = counterparty::Data { + client_id: connection_info.client_id.clone(), + connection_id: args.connection_id, + prefix: merkle_prefix::Data { + key_prefix: self.get_commitment_prefix(), + }, + }; + let expected_connection = connection_end::Data { + client_id: connection_info.counterparty.client_id.clone(), + counterparty: expected_counterparty, + state: connection_end::State::Open, + delay_period: connection_info.delay_period, + versions: connection_info.versions.clone(), + }; + + self.verify_connection_state(VerifyConnectionStateArgs { + counterparty_connection_id: connection_info.counterparty.connection_id.clone(), + counterparty_connection_info: expected_connection, + connection_info, + height: args.proof_height, + proof: args.proof_ack, + }); + } } diff --git a/connection/src/conn_endpoints.rs b/connection/src/conn_endpoints.rs index 7f3222b..d6dc1c8 100644 --- a/connection/src/conn_endpoints.rs +++ b/connection/src/conn_endpoints.rs @@ -1,11 +1,15 @@ use common_types::{connection_types::connection_end, ConnectionId, VersionVec}; use crate::common::conn_types::{ - MsgConnectionOpenAck, MsgConnectionOpenInit, MsgConnectionOpenTry, + MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenInit, MsgConnectionOpenTry, }; multiversx_sc::imports!(); +static CONNECTION_ALREADY_EXISTS_ERR_MSG: &[u8] = b"Connection already exists"; +static CONNECTION_DOES_NOT_EXIST_ERR_MSG: &[u8] = b"Connection does not exist"; +static INVALID_CONNECTION_STATE_ERR_MSG: &[u8] = b"Invalid connection state"; + #[multiversx_sc::module] pub trait ConnectionEndpointsModule: crate::common::conn_lib::ConnectionLibModule @@ -33,7 +37,10 @@ pub trait ConnectionEndpointsModule: ) -> ConnectionId { let connection_id = self.generate_connection_id(); let connection_mapper = self.connection_info(&connection_id); - require!(connection_mapper.is_empty(), "Connection already exists"); + require!( + connection_mapper.is_empty(), + CONNECTION_ALREADY_EXISTS_ERR_MSG + ); // ensure the client exists let _ = self.check_and_get_client(&args.client_id); @@ -73,7 +80,10 @@ pub trait ConnectionEndpointsModule: let self_consensus_state = args.host_consensus_state_proof.clone(); let connection_id = self.generate_connection_id(); let connection_mapper = self.connection_info(&connection_id); - require!(connection_mapper.is_empty(), "Connection already exists"); + require!( + connection_mapper.is_empty(), + CONNECTION_ALREADY_EXISTS_ERR_MSG + ); // ensure the client exists let _ = self.check_and_get_client(&args.client_id); @@ -100,12 +110,15 @@ pub trait ConnectionEndpointsModule: #[endpoint(connectionOpenAck)] fn connection_open_ack(&self, args: MsgConnectionOpenAck) { let connection_mapper = self.connection_info(&args.connection_id); - require!(!connection_mapper.is_empty(), "Connection does not exist"); + require!( + !connection_mapper.is_empty(), + CONNECTION_DOES_NOT_EXIST_ERR_MSG + ); let mut connection_info = connection_mapper.get(); require!( matches!(connection_info.state, connection_end::State::Init), - "Invalid connection state" + INVALID_CONNECTION_STATE_ERR_MSG ); let self_consensus_state = args.host_consensus_state_proof.clone(); @@ -122,4 +135,27 @@ pub trait ConnectionEndpointsModule: connection_mapper.set(&connection_info); self.update_connection_commitment(&args.connection_id, &connection_info); } + + /// confirms opening of a connection on chain A to chain B, after which the connection is open on both chains (this code is executed on chain B) + #[endpoint(connectionOpenConfirm)] + fn connection_open_confirm(&self, args: MsgConnectionOpenConfirm) { + let connection_mapper = self.connection_info(&args.connection_id); + require!( + !connection_mapper.is_empty(), + CONNECTION_DOES_NOT_EXIST_ERR_MSG + ); + + let mut connection_info = connection_mapper.get(); + require!( + matches!(connection_info.state, connection_end::State::TryOpen), + INVALID_CONNECTION_STATE_ERR_MSG + ); + + let connection_id = args.connection_id.clone(); + self.verify_all_states_open_confirm(connection_info.clone(), args); + + connection_info.state = connection_end::State::Open; + connection_mapper.set(&connection_info); + self.update_connection_commitment(&connection_id, &connection_info); + } } diff --git a/connection/wasm/src/lib.rs b/connection/wasm/src/lib.rs index b5d1650..ffd420e 100644 --- a/connection/wasm/src/lib.rs +++ b/connection/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 11 +// Endpoints: 12 // Async Callback (empty): 1 -// Total number of exported functions: 14 +// Total number of exported functions: 15 #![no_std] @@ -24,6 +24,7 @@ multiversx_sc_wasm_adapter::endpoints! { connectionOpenInit => connection_open_init connectionOpenTry => connection_open_try connectionOpenAck => connection_open_ack + connectionOpenConfirm => connection_open_confirm setExpectedTimePerBlock => set_expected_time_per_block registerClient => register_client bindPort => bind_port From 3a7efdfa124d714c6fdc63cbd3804dd1274ce788 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Tue, 24 Sep 2024 08:08:09 +0300 Subject: [PATCH 11/11] common encode function --- common/common-modules/src/utils.rs | 7 +++++++ connection/src/common/conn_internal.rs | 8 ++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/common/common-modules/src/utils.rs b/common/common-modules/src/utils.rs index e8b625f..6d1d669 100644 --- a/common/common-modules/src/utils.rs +++ b/common/common-modules/src/utils.rs @@ -20,4 +20,11 @@ pub trait UtilsModule { None => sc_panic!("Overlow!!!"), } } + + fn encode_to_buffer(&self, value: &T) -> ManagedBuffer { + let mut encoded_value = ManagedBuffer::new(); + let _ = value.top_encode(&mut encoded_value); + + encoded_value + } } diff --git a/connection/src/common/conn_internal.rs b/connection/src/common/conn_internal.rs index 4ebc0f5..29a455e 100644 --- a/connection/src/common/conn_internal.rs +++ b/connection/src/common/conn_internal.rs @@ -87,8 +87,7 @@ pub trait ConnectionInternalModule: connection_info: &connection_end::Data, ) { let connection_key = self.get_connection_commitment_key(connection_id); - let mut encoded_connection = ManagedBuffer::new(); - let _ = connection_info.top_encode(&mut encoded_connection); + let encoded_connection = self.encode_to_buffer(&connection_info); let hashed_connection = self.crypto().keccak256(encoded_connection); self.commitments(&connection_key).set(&hashed_connection); @@ -146,10 +145,7 @@ pub trait ConnectionInternalModule: fn verify_connection_state(&self, args: VerifyConnectionStateArgs) { let client = self.check_and_get_client(&args.connection_info.client_id); let connection_path = self.get_connection_path(&args.counterparty_connection_id); - let mut encoded_connection = ManagedBuffer::new(); - let _ = args - .counterparty_connection_info - .top_encode(&mut encoded_connection); + let encoded_connection = self.encode_to_buffer(&args.counterparty_connection_info); let args = VerifyMembershipArgs { client_id: args.connection_info.client_id,