From 68b4ca6900335724d25a4892650fee78dba6bc7c Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Fri, 17 Nov 2023 07:26:39 -0800 Subject: [PATCH 01/13] feat: migrate `applications` module under the `ibc` crate into `ibc-apps` (#967) * feat: restructure and split off applications codebase into ibc-apps dir * imp: rename transfer dir to ics20_transfer * feat: add ibc-apps crate * fix: remove redundant dep + fix cargo doc * docs: add README and descriptions * docs: update main README page * nit: docstrings * nit: docstrings * imp: rename folder to ics20-transfer * chore: move serializers into ics20-transfer/types * fix: apply reviewer comments * imp: add docstring for cosmos_adr028_escrow_address * fix: add missing features + use workspace deps for ibc crates * imp: place re-exports under mod * nit: apply suggestions from code review Co-authored-by: Sean Chen Signed-off-by: Farhad Shabani * fix: cargo fmt --------- Signed-off-by: Farhad Shabani Co-authored-by: Sean Chen --- Cargo.toml | 9 +- README.md | 1 + clippy.toml | 9 + crates/ibc-apps/Cargo.toml | 37 ++++ crates/ibc-apps/README.md | 48 ++++ crates/ibc-apps/ics20-transfer/Cargo.toml | 57 +++++ crates/ibc-apps/ics20-transfer/src/context.rs | 136 ++++++++++++ .../ics20-transfer/src/handler/mod.rs} | 16 +- .../src/handler}/on_recv_packet.rs | 17 +- .../src/handler}/send_transfer.rs | 27 +-- crates/ibc-apps/ics20-transfer/src/lib.rs | 32 +++ .../ics20-transfer/src/module.rs} | 207 ++++++------------ .../ibc-apps/ics20-transfer/types/Cargo.toml | 55 +++++ .../ics20-transfer/types/src}/amount.rs | 9 +- .../ics20-transfer/types/src}/coin.rs | 3 +- .../ics20-transfer/types/src}/denom.rs | 10 +- .../ics20-transfer/types/src}/error.rs | 12 +- .../ics20-transfer/types/src}/events.rs | 30 ++- .../ibc-apps/ics20-transfer/types/src/lib.rs | 69 ++++++ .../ics20-transfer/types/src}/memo.rs | 2 +- .../ics20-transfer/types/src/msgs/mod.rs} | 1 - .../types/src}/msgs/transfer.rs | 17 +- .../ics20-transfer/types/src}/packet.rs | 8 +- .../ics20-transfer/types/src/serializers.rs | 27 +++ crates/ibc-apps/src/lib.rs | 20 ++ crates/ibc-testkit/Cargo.toml | 4 +- .../ibc/applications/transfer/context.rs | 10 +- .../src/testapp/ibc/core/router/types.rs | 2 +- .../utils/dummies/applications/transfer.rs | 6 +- .../tests/applications/transfer.rs | 11 +- .../tests/core/ics04_channel/chan_open_ack.rs | 2 +- crates/ibc-testkit/tests/core/router.rs | 7 +- crates/ibc/Cargo.toml | 5 +- crates/ibc/src/applications/mod.rs | 4 - crates/ibc/src/applications/transfer/mod.rs | 41 ---- .../src/core/ics04_channel/acknowledgement.rs | 68 ------ crates/ibc/src/core/ics04_channel/handler.rs | 22 +- crates/ibc/src/core/ics04_channel/mod.rs | 2 +- crates/ibc/src/lib.rs | 5 - crates/ibc/src/serializers.rs | 29 --- 40 files changed, 674 insertions(+), 403 deletions(-) create mode 100644 clippy.toml create mode 100644 crates/ibc-apps/Cargo.toml create mode 100644 crates/ibc-apps/README.md create mode 100644 crates/ibc-apps/ics20-transfer/Cargo.toml create mode 100644 crates/ibc-apps/ics20-transfer/src/context.rs rename crates/{ibc/src/applications/transfer/relay.rs => ibc-apps/ics20-transfer/src/handler/mod.rs} (84%) rename crates/{ibc/src/applications/transfer/relay => ibc-apps/ics20-transfer/src/handler}/on_recv_packet.rs (90%) rename crates/{ibc/src/applications/transfer/relay => ibc-apps/ics20-transfer/src/handler}/send_transfer.rs (88%) create mode 100644 crates/ibc-apps/ics20-transfer/src/lib.rs rename crates/{ibc/src/applications/transfer/context.rs => ibc-apps/ics20-transfer/src/module.rs} (62%) create mode 100644 crates/ibc-apps/ics20-transfer/types/Cargo.toml rename crates/{ibc/src/applications/transfer => ibc-apps/ics20-transfer/types/src}/amount.rs (95%) rename crates/{ibc/src/applications/transfer => ibc-apps/ics20-transfer/types/src}/coin.rs (99%) rename crates/{ibc/src/applications/transfer => ibc-apps/ics20-transfer/types/src}/denom.rs (98%) rename crates/{ibc/src/applications/transfer => ibc-apps/ics20-transfer/types/src}/error.rs (93%) rename crates/{ibc/src/applications/transfer => ibc-apps/ics20-transfer/types/src}/events.rs (83%) create mode 100644 crates/ibc-apps/ics20-transfer/types/src/lib.rs rename crates/{ibc/src/applications/transfer => ibc-apps/ics20-transfer/types/src}/memo.rs (98%) rename crates/{ibc/src/applications/transfer/msgs.rs => ibc-apps/ics20-transfer/types/src/msgs/mod.rs} (98%) rename crates/{ibc/src/applications/transfer => ibc-apps/ics20-transfer/types/src}/msgs/transfer.rs (91%) rename crates/{ibc/src/applications/transfer => ibc-apps/ics20-transfer/types/src}/packet.rs (95%) create mode 100644 crates/ibc-apps/ics20-transfer/types/src/serializers.rs create mode 100644 crates/ibc-apps/src/lib.rs delete mode 100644 crates/ibc/src/applications/mod.rs delete mode 100644 crates/ibc/src/applications/transfer/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 7f65e463b..a2ac8e33a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,9 @@ resolver = "2" members = [ "crates/ibc", + "crates/ibc-apps", + "crates/ibc-apps/ics20-transfer", + "crates/ibc-apps/ics20-transfer/types", "crates/ibc-derive", "crates/ibc-testkit", "crates/ibc-query", @@ -45,7 +48,11 @@ tracing-subscriber = { version = "0.3.17", features = ["fmt", "env-filter", "jso typed-builder = { version = "0.18.0"} # ibc dependencies -ibc-derive = { version = "0.3.0", path = "../ibc-derive" } +ibc = { version = "0.47.0", path = "./crates/ibc", default-features = false } +ibc-testkit = { version = "0.47.0", path = "./crates/ibc-testkit", default-features = false} +ibc-app-transfer = { version = "0.47.0", path = "./crates/ibc-apps/ics20-transfer", default-features = false } +ibc-app-transfer-types = { version = "0.47.0", path = "./crates/ibc-apps/ics20-transfer/types", default-features = false } +ibc-derive = { version = "0.3.0", path = "./crates/ibc-derive" } ibc-proto = { version = "0.38.0", default-features = false } ics23 = { version = "0.11", default-features = false } diff --git a/README.md b/README.md index 6bcd01fe8..2c5c8a8a5 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ the `ibc` rust crate which defines the main data structures and on-chain logic f ## Libraries - [ibc](crates/ibc/README.md) - Data structures and on-chain logic for the IBC protocol. +- [ibc-apps](crates/ibc-apps/README.md) - Contains implementations of various IBC applications. - [ibc-derive](crates/ibc-derive/README.md) - Derive macros for `ClientState` and `ConsensusState` traits, reducing boilerplate. - [ibc-testkit](crates/ibc-testkit/README.md) - Testing toolkit to aid `ibc-rs` and host chains in writing integration tests. diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 000000000..87ee0dae3 --- /dev/null +++ b/clippy.toml @@ -0,0 +1,9 @@ +disallowed-types = [ + # { path = "usize", reason = "variable size" }, # cannot on now, because mocks use it and serde, even if there is no usize in type + { path = "f64", reason = "not supported in CosmWasm" }, + { path = "f32", reason = "not supported in CosmWasm" }, +] + +disallowed-methods = [ + "std::time::Duration::as_secs_f64", +] diff --git a/crates/ibc-apps/Cargo.toml b/crates/ibc-apps/Cargo.toml new file mode 100644 index 000000000..f0c4420cf --- /dev/null +++ b/crates/ibc-apps/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "ibc-apps" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "applications"] +readme = "README.md" +description = """ + `ibc-apps` provides a comprehensive set of libraries for IBC applications, + facilitating seamless integration of IBC business logic into any blockchain system. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +ibc-app-transfer = { workspace = true } + +[features] +default = ["std"] +std = [ + "ibc-app-transfer/std", +] +serde = [ + "ibc-app-transfer/serde", +] +schema = [ + "ibc-app-transfer/schema", + "serde", + "std", +] +borsh = [ + "ibc-app-transfer/borsh", +] diff --git a/crates/ibc-apps/README.md b/crates/ibc-apps/README.md new file mode 100644 index 000000000..d74d4ad46 --- /dev/null +++ b/crates/ibc-apps/README.md @@ -0,0 +1,48 @@ +# `ibc-apps` + +This crate is a top-level library that re-exports Inter-Blockchain +Communication (IBC) applications implemented in Rust. It serves as a centralized hub, +simplifying the process of importing and integrating various IBC applications +into your blockchain. IBC is a distributed protocol that enables communication +between distinct sovereign blockchains. IBC applications abstract away the core +transport and authentication layers, letter blockchain app developers +focus solely on business logic implementation. + +The structure within the `ibc-apps` crate is designed to provide flexibility for +external users. It allows users to either utilize the entire `ibc-apps` crate, +or selectively import specific sub-crates, whether you need a certain IBC +application (e.g. `ibc-app-transfer` crate) or only their associated data +structures (e.g. `ibc-app-transfer-types`). This versatility empowers hosts, +including chain integrators, relayers, or any IBC tooling projects, to build +their solutions on top of the layers that best suit their requirements. + +## Libraries + +Currently, the `ibc-apps` crate contains the implementation of the following IBC +applications: + +### ICS-20: Fungible Token Transfer Application + +- [ibc-app-transfer](crates/ibc-apps/ics20-transfer) +- [ibc-app-transfer-types](crates/ibc-apps/ics20-transfer/types) + +## Contributing + +IBC is specified in English in the [cosmos/ibc repo][ibc]. Any +protocol changes or clarifications should be contributed there. + +If you're interested in contributing, please comment on an issue or open a new +one! + +See also [CONTRIBUTING.md](./../../CONTRIBUTING.md). + +## Resources + +- [IBC Website][ibc-homepage] +- [IBC Specification][ibc] +- [IBC Go implementation][ibc-go] + +[//]: # (general links) +[ibc]: https://github.com/cosmos/ibc +[ibc-go]: https://github.com/cosmos/ibc-go +[ibc-homepage]: https://cosmos.network/ibc diff --git a/crates/ibc-apps/ics20-transfer/Cargo.toml b/crates/ibc-apps/ics20-transfer/Cargo.toml new file mode 100644 index 000000000..821e3381b --- /dev/null +++ b/crates/ibc-apps/ics20-transfer/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "ibc-app-transfer" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "transfer", "ics20"] +readme = "./../README.md" +description = """ + Contains the core implementation of the ICS-20 token transfer application logic + along with re-exporting the data structures from `ibc-app-transfer-types` crate. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +serde_json = { workspace = true, optional = true } +sha2 = { workspace = true } + +# ibc dependencies +ibc = { workspace = true } +ibc-app-transfer-types = { workspace = true } + +[dev-dependencies] +subtle-encoding = { workspace = true } + +[features] +default = ["std"] +std = [ + "ibc-app-transfer-types/std", + "ibc/std", + "serde_json/std", + "sha2/std", +] +serde = [ + "ibc-app-transfer-types/serde", + "ibc/serde", + "serde_json" +] +schema = [ + "ibc-app-transfer-types/schema", + "ibc/schema", + "serde", + "std", +] +borsh = [ + "ibc-app-transfer-types/borsh", + "ibc/borsh", +] +parity-scale-codec = [ + "ibc-app-transfer-types/parity-scale-codec", + "ibc/parity-scale-codec", +] diff --git a/crates/ibc-apps/ics20-transfer/src/context.rs b/crates/ibc-apps/ics20-transfer/src/context.rs new file mode 100644 index 000000000..80899b12b --- /dev/null +++ b/crates/ibc-apps/ics20-transfer/src/context.rs @@ -0,0 +1,136 @@ +//! Defines the main context traits and IBC module callbacks + +use ibc::core::ics24_host::identifier::{ChannelId, PortId}; +use ibc::prelude::*; +use ibc::Signer; +use ibc_app_transfer_types::error::TokenTransferError; +use ibc_app_transfer_types::{PrefixedCoin, PrefixedDenom, VERSION}; +use sha2::{Digest, Sha256}; + +/// Methods required in token transfer validation, to be implemented by the host +pub trait TokenTransferValidationContext { + type AccountId: TryFrom; + + /// get_port returns the portID for the transfer module. + fn get_port(&self) -> Result; + + /// Returns the escrow account id for a port and channel combination + fn get_escrow_account( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result; + + /// Returns Ok() if the host chain supports sending coins. + fn can_send_coins(&self) -> Result<(), TokenTransferError>; + + /// Returns Ok() if the host chain supports receiving coins. + fn can_receive_coins(&self) -> Result<(), TokenTransferError>; + + /// Validates the sender and receiver accounts and the coin inputs + fn send_coins_validate( + &self, + from_account: &Self::AccountId, + to_account: &Self::AccountId, + coin: &PrefixedCoin, + ) -> Result<(), TokenTransferError>; + + /// Validates the receiver account and the coin input + fn mint_coins_validate( + &self, + account: &Self::AccountId, + coin: &PrefixedCoin, + ) -> Result<(), TokenTransferError>; + + /// Validates the sender account and the coin input + fn burn_coins_validate( + &self, + account: &Self::AccountId, + coin: &PrefixedCoin, + ) -> Result<(), TokenTransferError>; + + /// Returns a hash of the prefixed denom. + /// Implement only if the host chain supports hashed denominations. + fn denom_hash_string(&self, _denom: &PrefixedDenom) -> Option { + None + } +} + +/// Methods required in token transfer execution, to be implemented by the host +pub trait TokenTransferExecutionContext: TokenTransferValidationContext { + /// This function should enable sending ibc fungible tokens from one account to another + fn send_coins_execute( + &mut self, + from_account: &Self::AccountId, + to_account: &Self::AccountId, + coin: &PrefixedCoin, + ) -> Result<(), TokenTransferError>; + + /// This function to enable minting ibc tokens to a user account + fn mint_coins_execute( + &mut self, + account: &Self::AccountId, + coin: &PrefixedCoin, + ) -> Result<(), TokenTransferError>; + + /// This function should enable burning of minted tokens in a user account + fn burn_coins_execute( + &mut self, + account: &Self::AccountId, + coin: &PrefixedCoin, + ) -> Result<(), TokenTransferError>; +} + +/// Helper function to generate an escrow address for a given port and channel +/// ids according to the format specified in the Cosmos SDK +/// [`ADR-028`](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-028-public-key-addresses.md) +pub fn cosmos_adr028_escrow_address(port_id: &PortId, channel_id: &ChannelId) -> Vec { + let contents = format!("{port_id}/{channel_id}"); + + let mut hasher = Sha256::new(); + hasher.update(VERSION.as_bytes()); + hasher.update([0]); + hasher.update(contents.as_bytes()); + + let mut hash = hasher.finalize().to_vec(); + hash.truncate(20); + hash +} + +#[cfg(test)] +mod tests { + use subtle_encoding::bech32; + + use super::*; + use crate::context::cosmos_adr028_escrow_address; + + #[test] + fn test_cosmos_escrow_address() { + fn assert_eq_escrow_address(port_id: &str, channel_id: &str, address: &str) { + let port_id = port_id.parse().unwrap(); + let channel_id = channel_id.parse().unwrap(); + let gen_address = { + let addr = cosmos_adr028_escrow_address(&port_id, &channel_id); + bech32::encode("cosmos", addr) + }; + assert_eq!(gen_address, address.to_owned()) + } + + // addresses obtained using `gaiad query ibc-transfer escrow-address [port-id] [channel-id]` + assert_eq_escrow_address( + "transfer", + "channel-141", + "cosmos1x54ltnyg88k0ejmk8ytwrhd3ltm84xehrnlslf", + ); + assert_eq_escrow_address( + "transfer", + "channel-207", + "cosmos1ju6tlfclulxumtt2kglvnxduj5d93a64r5czge", + ); + assert_eq_escrow_address( + "transfer", + "channel-187", + "cosmos177x69sver58mcfs74x6dg0tv6ls4s3xmmcaw53", + ); + } +} diff --git a/crates/ibc/src/applications/transfer/relay.rs b/crates/ibc-apps/ics20-transfer/src/handler/mod.rs similarity index 84% rename from crates/ibc/src/applications/transfer/relay.rs rename to crates/ibc-apps/ics20-transfer/src/handler/mod.rs index 227ac8243..730017f6d 100644 --- a/crates/ibc/src/applications/transfer/relay.rs +++ b/crates/ibc-apps/ics20-transfer/src/handler/mod.rs @@ -1,15 +1,15 @@ //! Implements the processing logic for ICS20 (token transfer) message. - -use super::context::{TokenTransferExecutionContext, TokenTransferValidationContext}; -use crate::applications::transfer::error::TokenTransferError; -use crate::applications::transfer::is_sender_chain_source; -use crate::applications::transfer::packet::PacketData; -use crate::core::ics04_channel::packet::Packet; -use crate::prelude::*; - pub mod on_recv_packet; pub mod send_transfer; +use ibc::core::ics04_channel::packet::Packet; +use ibc::prelude::*; +use ibc_app_transfer_types::error::TokenTransferError; +use ibc_app_transfer_types::is_sender_chain_source; +use ibc_app_transfer_types::packet::PacketData; + +use crate::context::{TokenTransferExecutionContext, TokenTransferValidationContext}; + pub fn refund_packet_token_execute( ctx_a: &mut impl TokenTransferExecutionContext, packet: &Packet, diff --git a/crates/ibc/src/applications/transfer/relay/on_recv_packet.rs b/crates/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs similarity index 90% rename from crates/ibc/src/applications/transfer/relay/on_recv_packet.rs rename to crates/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs index 9e9e70c2d..d150d8399 100644 --- a/crates/ibc/src/applications/transfer/relay/on_recv_packet.rs +++ b/crates/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs @@ -1,11 +1,12 @@ -use crate::applications::transfer::context::TokenTransferExecutionContext; -use crate::applications::transfer::error::TokenTransferError; -use crate::applications::transfer::events::DenomTraceEvent; -use crate::applications::transfer::packet::PacketData; -use crate::applications::transfer::{is_receiver_chain_source, TracePrefix}; -use crate::core::ics04_channel::packet::Packet; -use crate::core::router::ModuleExtras; -use crate::prelude::*; +use ibc::core::ics04_channel::packet::Packet; +use ibc::core::router::ModuleExtras; +use ibc::prelude::*; +use ibc_app_transfer_types::error::TokenTransferError; +use ibc_app_transfer_types::events::DenomTraceEvent; +use ibc_app_transfer_types::packet::PacketData; +use ibc_app_transfer_types::{is_receiver_chain_source, TracePrefix}; + +use crate::context::TokenTransferExecutionContext; /// This function handles the transfer receiving logic. /// diff --git a/crates/ibc/src/applications/transfer/relay/send_transfer.rs b/crates/ibc-apps/ics20-transfer/src/handler/send_transfer.rs similarity index 88% rename from crates/ibc/src/applications/transfer/relay/send_transfer.rs rename to crates/ibc-apps/ics20-transfer/src/handler/send_transfer.rs index 112462cd0..9fe2662b5 100644 --- a/crates/ibc/src/applications/transfer/relay/send_transfer.rs +++ b/crates/ibc-apps/ics20-transfer/src/handler/send_transfer.rs @@ -1,18 +1,15 @@ -use crate::applications::transfer::context::{ - TokenTransferExecutionContext, TokenTransferValidationContext, -}; -use crate::applications::transfer::error::TokenTransferError; -use crate::applications::transfer::events::TransferEvent; -use crate::applications::transfer::msgs::transfer::MsgTransfer; -use crate::applications::transfer::{is_sender_chain_source, MODULE_ID_STR}; -use crate::core::events::{MessageEvent, ModuleEvent}; -use crate::core::ics04_channel::context::{ - SendPacketExecutionContext, SendPacketValidationContext, -}; -use crate::core::ics04_channel::handler::send_packet::{send_packet_execute, send_packet_validate}; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics24_host::path::{ChannelEndPath, SeqSendPath}; -use crate::prelude::*; +use ibc::core::events::{MessageEvent, ModuleEvent}; +use ibc::core::ics04_channel::context::{SendPacketExecutionContext, SendPacketValidationContext}; +use ibc::core::ics04_channel::handler::send_packet::{send_packet_execute, send_packet_validate}; +use ibc::core::ics04_channel::packet::Packet; +use ibc::core::ics24_host::path::{ChannelEndPath, SeqSendPath}; +use ibc::prelude::*; +use ibc_app_transfer_types::error::TokenTransferError; +use ibc_app_transfer_types::events::TransferEvent; +use ibc_app_transfer_types::msgs::transfer::MsgTransfer; +use ibc_app_transfer_types::{is_sender_chain_source, MODULE_ID_STR}; + +use crate::context::{TokenTransferExecutionContext, TokenTransferValidationContext}; /// Initiate a token transfer. Equivalent to calling [`send_transfer_validate`], followed by [`send_transfer_execute`]. pub fn send_transfer( diff --git a/crates/ibc-apps/ics20-transfer/src/lib.rs b/crates/ibc-apps/ics20-transfer/src/lib.rs new file mode 100644 index 000000000..8c2c31d9c --- /dev/null +++ b/crates/ibc-apps/ics20-transfer/src/lib.rs @@ -0,0 +1,32 @@ +//! Implementation of the IBC [fungible token transfer](https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md) (ICS-20) application logic. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types))] +#![deny( + warnings, + trivial_casts, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] +#![allow(clippy::result_large_err)] + +#[cfg(any(test, feature = "std"))] +extern crate std; + +/// Re-exports the implementation of the IBC [fungible token +/// transfer](https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md) +/// (ICS-20) data structures. +pub mod types { + #[doc(inline)] + pub use ibc_app_transfer_types::*; +} + +#[cfg(feature = "serde")] +pub mod context; +#[cfg(feature = "serde")] +pub mod handler; +#[cfg(feature = "serde")] +pub mod module; diff --git a/crates/ibc/src/applications/transfer/context.rs b/crates/ibc-apps/ics20-transfer/src/module.rs similarity index 62% rename from crates/ibc/src/applications/transfer/context.rs rename to crates/ibc-apps/ics20-transfer/src/module.rs index 33d080f30..1c86d139e 100644 --- a/crates/ibc/src/applications/transfer/context.rs +++ b/crates/ibc-apps/ics20-transfer/src/module.rs @@ -1,112 +1,20 @@ -//! Defines the main context traits and IBC module callbacks -use sha2::{Digest, Sha256}; - -use super::ack_success_b64; -use super::error::TokenTransferError; -use crate::applications::transfer::events::{AckEvent, AckStatusEvent, RecvEvent, TimeoutEvent}; -use crate::applications::transfer::packet::PacketData; -use crate::applications::transfer::relay::on_recv_packet::process_recv_packet_execute; -use crate::applications::transfer::relay::{ - refund_packet_token_execute, refund_packet_token_validate, -}; -use crate::applications::transfer::{PrefixedCoin, PrefixedDenom, VERSION}; -use crate::core::ics04_channel::acknowledgement::{Acknowledgement, AcknowledgementStatus}; -use crate::core::ics04_channel::channel::{Counterparty, Order}; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::core::router::ModuleExtras; -use crate::core::ContextError; -use crate::prelude::*; -use crate::signer::Signer; - -/// Methods required in token transfer validation, to be implemented by the host -pub trait TokenTransferValidationContext { - type AccountId: TryFrom; - - /// get_port returns the portID for the transfer module. - fn get_port(&self) -> Result; - - /// Returns the escrow account id for a port and channel combination - fn get_escrow_account( - &self, - port_id: &PortId, - channel_id: &ChannelId, - ) -> Result; - - /// Returns Ok() if the host chain supports sending coins. - fn can_send_coins(&self) -> Result<(), TokenTransferError>; - - /// Returns Ok() if the host chain supports receiving coins. - fn can_receive_coins(&self) -> Result<(), TokenTransferError>; - - /// Validates the sender and receiver accounts and the coin inputs - fn send_coins_validate( - &self, - from_account: &Self::AccountId, - to_account: &Self::AccountId, - coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; - - /// Validates the receiver account and the coin input - fn mint_coins_validate( - &self, - account: &Self::AccountId, - coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; - - /// Validates the sender account and the coin input - fn burn_coins_validate( - &self, - account: &Self::AccountId, - coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; - - /// Returns a hash of the prefixed denom. - /// Implement only if the host chain supports hashed denominations. - fn denom_hash_string(&self, _denom: &PrefixedDenom) -> Option { - None - } -} - -/// Methods required in token transfer execution, to be implemented by the host -pub trait TokenTransferExecutionContext: TokenTransferValidationContext { - /// This function should enable sending ibc fungible tokens from one account to another - fn send_coins_execute( - &mut self, - from_account: &Self::AccountId, - to_account: &Self::AccountId, - coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; - - /// This function to enable minting ibc tokens to a user account - fn mint_coins_execute( - &mut self, - account: &Self::AccountId, - coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; - - /// This function should enable burning of minted tokens in a user account - fn burn_coins_execute( - &mut self, - account: &Self::AccountId, - coin: &PrefixedCoin, - ) -> Result<(), TokenTransferError>; -} - -// https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-028-public-key-addresses.md -pub fn cosmos_adr028_escrow_address(port_id: &PortId, channel_id: &ChannelId) -> Vec { - let contents = format!("{port_id}/{channel_id}"); - - let mut hasher = Sha256::new(); - hasher.update(VERSION.as_bytes()); - hasher.update([0]); - hasher.update(contents.as_bytes()); - - let mut hash = hasher.finalize().to_vec(); - hash.truncate(20); - hash -} +use ibc::core::ics04_channel::acknowledgement::{Acknowledgement, AcknowledgementStatus}; +use ibc::core::ics04_channel::channel::{Counterparty, Order}; +use ibc::core::ics04_channel::packet::Packet; +use ibc::core::ics04_channel::Version; +use ibc::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; +use ibc::core::router::ModuleExtras; +use ibc::core::ContextError; +use ibc::prelude::*; +use ibc::Signer; +use ibc_app_transfer_types::error::TokenTransferError; +use ibc_app_transfer_types::events::{AckEvent, AckStatusEvent, RecvEvent, TimeoutEvent}; +use ibc_app_transfer_types::packet::PacketData; +use ibc_app_transfer_types::{ack_success_b64, VERSION}; + +use crate::context::{TokenTransferExecutionContext, TokenTransferValidationContext}; +use crate::handler::on_recv_packet::process_recv_packet_execute; +use crate::handler::{refund_packet_token_execute, refund_packet_token_validate}; pub fn on_chan_open_init_validate( ctx: &impl TokenTransferValidationContext, @@ -411,39 +319,70 @@ pub fn on_timeout_packet_execute( } #[cfg(test)] -mod tests { - use subtle_encoding::bech32; +mod test { + use ibc_app_transfer_types::ack_success_b64; + use ibc_app_transfer_types::error::TokenTransferError; use super::*; - use crate::applications::transfer::context::cosmos_adr028_escrow_address; #[test] - fn test_cosmos_escrow_address() { - fn assert_eq_escrow_address(port_id: &str, channel_id: &str, address: &str) { - let port_id = port_id.parse().unwrap(); - let channel_id = channel_id.parse().unwrap(); - let gen_address = { - let addr = cosmos_adr028_escrow_address(&port_id, &channel_id); - bech32::encode("cosmos", addr) - }; - assert_eq!(gen_address, address.to_owned()) + fn test_ack_ser() { + fn ser_json_assert_eq(ack: AcknowledgementStatus, json_str: &str) { + let ser = serde_json::to_string(&ack).unwrap(); + assert_eq!(ser, json_str) } - // addresses obtained using `gaiad query ibc-transfer escrow-address [port-id] [channel-id]` - assert_eq_escrow_address( - "transfer", - "channel-141", - "cosmos1x54ltnyg88k0ejmk8ytwrhd3ltm84xehrnlslf", + ser_json_assert_eq( + AcknowledgementStatus::success(ack_success_b64()), + r#"{"result":"AQ=="}"#, ); - assert_eq_escrow_address( - "transfer", - "channel-207", - "cosmos1ju6tlfclulxumtt2kglvnxduj5d93a64r5czge", + ser_json_assert_eq( + AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()), + r#"{"error":"failed to deserialize packet data"}"#, ); - assert_eq_escrow_address( - "transfer", - "channel-187", - "cosmos177x69sver58mcfs74x6dg0tv6ls4s3xmmcaw53", + } + + #[test] + fn test_ack_success_to_vec() { + let ack_success: Vec = AcknowledgementStatus::success(ack_success_b64()).into(); + + // Check that it's the same output as ibc-go + // Note: this also implicitly checks that the ack bytes are non-empty, + // which would make the conversion to `Acknowledgement` panic + assert_eq!(ack_success, r#"{"result":"AQ=="}"#.as_bytes()); + } + + #[test] + fn test_ack_error_to_vec() { + let ack_error: Vec = + AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()) + .into(); + + // Check that it's the same output as ibc-go + // Note: this also implicitly checks that the ack bytes are non-empty, + // which would make the conversion to `Acknowledgement` panic + assert_eq!( + ack_error, + r#"{"error":"failed to deserialize packet data"}"#.as_bytes() ); } + + #[test] + fn test_ack_de() { + fn de_json_assert_eq(json_str: &str, ack: AcknowledgementStatus) { + let de = serde_json::from_str::(json_str).unwrap(); + assert_eq!(de, ack) + } + + de_json_assert_eq( + r#"{"result":"AQ=="}"#, + AcknowledgementStatus::success(ack_success_b64()), + ); + de_json_assert_eq( + r#"{"error":"failed to deserialize packet data"}"#, + AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()), + ); + + assert!(serde_json::from_str::(r#"{"success":"AQ=="}"#).is_err()); + } } diff --git a/crates/ibc-apps/ics20-transfer/types/Cargo.toml b/crates/ibc-apps/ics20-transfer/types/Cargo.toml new file mode 100644 index 000000000..495a77de5 --- /dev/null +++ b/crates/ibc-apps/ics20-transfer/types/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "ibc-app-transfer-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "transfer", "ics20"] +readme = "./../../README.md" +description = """ + Contains the universal data structures of the ICS-20 fungible token transfer application + that can be used across various IBC implementations +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } +primitive-types = { workspace = true } +schemars = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +serde_json = { workspace = true, optional = true} +uint = { version = "0.9", default-features = false } + +# ibc dependencies +ibc = { workspace = true } +ibc-proto = { workspace = true } + +## parity dependencies +parity-scale-codec = { workspace = true , optional = true } +scale-info = { workspace = true , optional = true } + +[dev-dependencies] +ibc-testkit = { workspace = true } +rstest = { workspace = true } + +[features] +default = ["std"] +std = [ + "ibc-proto/std", + "serde/std", + "serde_json/std", + "displaydoc/std", + "uint/std", + "primitive-types/std", +] +borsh = ["dep:borsh", "ibc/borsh", "ibc-proto/borsh"] +serde = ["dep:serde", "serde_json", "ibc/serde", "ibc-proto/serde"] +schema = ["dep:schemars", "ibc/schema", "ibc-proto/json-schema", "serde", "std"] +parity-scale-codec = ["dep:parity-scale-codec", "dep:scale-info", "ibc/parity-scale-codec", "ibc-proto/parity-scale-codec"] \ No newline at end of file diff --git a/crates/ibc/src/applications/transfer/amount.rs b/crates/ibc-apps/ics20-transfer/types/src/amount.rs similarity index 95% rename from crates/ibc/src/applications/transfer/amount.rs rename to crates/ibc-apps/ics20-transfer/types/src/amount.rs index b14a1797a..cc793200b 100644 --- a/crates/ibc/src/applications/transfer/amount.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/amount.rs @@ -1,17 +1,12 @@ //! Contains the `Amount` type, which represents amounts of tokens transferred. - use core::ops::Deref; use core::str::FromStr; use derive_more::{Display, From, Into}; +use ibc::prelude::*; use primitive_types::U256; use super::error::TokenTransferError; -#[cfg(feature = "schema")] -use crate::alloc::borrow::ToOwned; -#[cfg(feature = "schema")] -use crate::alloc::string::String; -use crate::prelude::*; /// A type for representing token transfer amounts. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -19,7 +14,7 @@ use crate::prelude::*; #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Display, From, Into)] pub struct Amount( #[cfg_attr(feature = "schema", schemars(with = "String"))] - #[serde(serialize_with = "crate::serializers::serde_string::serialize")] + #[serde(serialize_with = "crate::serializers::serialize")] #[serde(deserialize_with = "deserialize")] U256, ); diff --git a/crates/ibc/src/applications/transfer/coin.rs b/crates/ibc-apps/ics20-transfer/types/src/coin.rs similarity index 99% rename from crates/ibc/src/applications/transfer/coin.rs rename to crates/ibc-apps/ics20-transfer/types/src/coin.rs index be7a41172..70f3d832b 100644 --- a/crates/ibc/src/applications/transfer/coin.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/coin.rs @@ -1,14 +1,13 @@ //! Defines coin types; the objects that are being transferred. - use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; +use ibc::prelude::*; use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; use super::amount::Amount; use super::denom::{BaseDenom, PrefixedDenom}; use super::error::TokenTransferError; -use crate::prelude::*; /// A `Coin` type with fully qualified `PrefixedDenom`. pub type PrefixedCoin = Coin; diff --git a/crates/ibc/src/applications/transfer/denom.rs b/crates/ibc-apps/ics20-transfer/types/src/denom.rs similarity index 98% rename from crates/ibc/src/applications/transfer/denom.rs rename to crates/ibc-apps/ics20-transfer/types/src/denom.rs index 855b542ae..42847ceba 100644 --- a/crates/ibc/src/applications/transfer/denom.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/denom.rs @@ -1,16 +1,14 @@ //! Defines types to represent "denominations" [as defined in ICS-20](https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md#data-structures) - use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; use derive_more::{Display, From}; +use ibc::core::ics24_host::identifier::{ChannelId, PortId}; +use ibc::prelude::*; use ibc_proto::ibc::applications::transfer::v1::DenomTrace as RawDenomTrace; use super::error::TokenTransferError; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::prelude::*; -#[cfg(feature = "serde")] -use crate::serializers::serde_string; +use crate::serializers; /// The "base" of a denomination. /// @@ -218,7 +216,7 @@ impl Display for TracePath { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct PrefixedDenom { /// A series of `{port-id}/{channel-id}`s for tracing the source of the token. - #[cfg_attr(feature = "serde", serde(with = "serde_string"))] + #[cfg_attr(feature = "serde", serde(with = "serializers"))] #[cfg_attr(feature = "schema", schemars(with = "String"))] pub trace_path: TracePath, /// Base denomination of the relayed fungible token. diff --git a/crates/ibc/src/applications/transfer/error.rs b/crates/ibc-apps/ics20-transfer/types/src/error.rs similarity index 93% rename from crates/ibc/src/applications/transfer/error.rs rename to crates/ibc-apps/ics20-transfer/types/src/error.rs index d47decc33..8372f8aa5 100644 --- a/crates/ibc/src/applications/transfer/error.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/error.rs @@ -1,17 +1,15 @@ //! Defines the token transfer error type - use core::convert::Infallible; use core::str::Utf8Error; use displaydoc::Display; +use ibc::core::ics04_channel::acknowledgement::StatusValue; +use ibc::core::ics04_channel::channel::Order; +use ibc::core::ics24_host::identifier::{ChannelId, IdentifierError, PortId}; +use ibc::core::ContextError; +use ibc::prelude::*; use uint::FromDecStrErr; -use crate::core::ics04_channel::acknowledgement::StatusValue; -use crate::core::ics04_channel::channel::Order; -use crate::core::ics24_host::identifier::{ChannelId, IdentifierError, PortId}; -use crate::core::ContextError; -use crate::prelude::*; - #[derive(Display, Debug)] pub enum TokenTransferError { /// context error: `{0}` diff --git a/crates/ibc/src/applications/transfer/events.rs b/crates/ibc-apps/ics20-transfer/types/src/events.rs similarity index 83% rename from crates/ibc/src/applications/transfer/events.rs rename to crates/ibc-apps/ics20-transfer/types/src/events.rs index 45eff108a..bee96cf72 100644 --- a/crates/ibc/src/applications/transfer/events.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/events.rs @@ -1,11 +1,11 @@ //! Defines all token transfer event types +use ibc::core::events::ModuleEvent; +use ibc::core::ics04_channel::acknowledgement::AcknowledgementStatus; +use ibc::prelude::*; +use ibc::Signer; use super::Memo; -use crate::applications::transfer::{Amount, PrefixedDenom, MODULE_ID_STR}; -use crate::core::events::ModuleEvent; -use crate::core::ics04_channel::acknowledgement::AcknowledgementStatus; -use crate::prelude::*; -use crate::signer::Signer; +use crate::{Amount, PrefixedDenom, MODULE_ID_STR}; const EVENT_TYPE_PACKET: &str = "fungible_token_packet"; const EVENT_TYPE_TIMEOUT: &str = "timeout"; @@ -22,8 +22,8 @@ pub enum Event { Transfer(TransferEvent), } -/// Event emitted in the [`onRecvPacket`][super::context::on_recv_packet_execute] -/// module callback to indicate the that the `RecvPacket` message was processed +/// Event emitted in the `onRecvPacket` module callback to indicate that the +/// `RecvPacket` message was processed pub struct RecvEvent { pub sender: Signer, pub receiver: Signer, @@ -58,8 +58,7 @@ impl From for ModuleEvent { } } -/// Event emitted in the [`onAcknowledgePacket`][super::context::on_acknowledgement_packet_execute] -/// module callback +/// Event emitted by the `onAcknowledgePacket` module callback pub struct AckEvent { pub sender: Signer, pub receiver: Signer, @@ -94,8 +93,8 @@ impl From for ModuleEvent { } } -/// Event emitted in the [`onAcknowledgePacket`][super::context::on_acknowledgement_packet_execute] -/// module callback to indicate whether the acknowledgement is a success or a failure +/// Event emitted by the `onAcknowledgePacket` module callback to indicate +/// whether the acknowledgement is a success or a failure pub struct AckStatusEvent { pub acknowledgement: AcknowledgementStatus, } @@ -115,8 +114,7 @@ impl From for ModuleEvent { } } -/// Event emitted in the [`onTimeoutPacket`][super::context::on_timeout_packet_execute] -/// module callback +/// Event emitted by the `onTimeoutPacket` module callback pub struct TimeoutEvent { pub refund_receiver: Signer, pub refund_denom: PrefixedDenom, @@ -145,8 +143,7 @@ impl From for ModuleEvent { } } -/// Event emitted in the [`onRecvPacket`][super::context::on_recv_packet_execute] -/// module callback when new tokens are minted +/// Event emitted by the `onRecvPacket` module callback when new tokens are minted pub struct DenomTraceEvent { pub trace_hash: Option, pub denom: PrefixedDenom, @@ -166,8 +163,7 @@ impl From for ModuleEvent { } } -/// Event emitted in [`sendTransfer`][super::send_transfer] after a successful -/// transfer +/// Event emitted after a successful `sendTransfer` pub struct TransferEvent { pub sender: Signer, pub receiver: Signer, diff --git a/crates/ibc-apps/ics20-transfer/types/src/lib.rs b/crates/ibc-apps/ics20-transfer/types/src/lib.rs new file mode 100644 index 000000000..723a146d3 --- /dev/null +++ b/crates/ibc-apps/ics20-transfer/types/src/lib.rs @@ -0,0 +1,69 @@ +//! Implementation of the IBC [fungible token transfer](https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md) (ICS-20) data structures. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types))] +#![deny( + warnings, + trivial_casts, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(any(test, feature = "std"))] +extern crate std; + +#[cfg(feature = "serde")] +mod amount; +#[cfg(feature = "serde")] +pub use amount::*; +#[cfg(feature = "serde")] +mod coin; +#[cfg(feature = "serde")] +pub use coin::*; +#[cfg(feature = "serde")] +mod denom; +#[cfg(feature = "serde")] +pub use denom::*; +#[cfg(feature = "serde")] +pub mod events; +#[cfg(feature = "serde")] +pub mod msgs; +#[cfg(feature = "serde")] +pub mod packet; + +#[cfg(feature = "serde")] +pub(crate) mod serializers; + +pub mod error; +mod memo; +pub use memo::*; + +/// Re-exports ICS-20 token transfer proto types from the `ibc-proto-rs` crate +/// for added convenience +pub mod proto { + pub use ibc_proto::ibc::apps::transfer; +} + +/// Module identifier for the ICS20 application. +pub const MODULE_ID_STR: &str = "transfer"; + +/// The port identifier that the ICS20 applications +/// typically bind with. +pub const PORT_ID_STR: &str = "transfer"; + +/// ICS20 application current version. +pub const VERSION: &str = "ics20-1"; + +/// The successful string used for creating an acknowledgement status, +/// equivalent to `base64::encode(0x01)`. +pub const ACK_SUCCESS_B64: &str = "AQ=="; + +use ibc::core::ics04_channel::acknowledgement::StatusValue; + +/// Returns a successful acknowledgement status for the token transfer application. +pub fn ack_success_b64() -> StatusValue { + StatusValue::new(ACK_SUCCESS_B64).expect("ack status value is never supposed to be empty") +} diff --git a/crates/ibc/src/applications/transfer/memo.rs b/crates/ibc-apps/ics20-transfer/types/src/memo.rs similarity index 98% rename from crates/ibc/src/applications/transfer/memo.rs rename to crates/ibc-apps/ics20-transfer/types/src/memo.rs index 3d31f206e..de7368fa6 100644 --- a/crates/ibc/src/applications/transfer/memo.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/memo.rs @@ -7,7 +7,7 @@ use core::fmt::{ }; use core::str::FromStr; -use crate::prelude::*; +use ibc::prelude::*; /// Represents the token transfer memo #[cfg_attr( diff --git a/crates/ibc/src/applications/transfer/msgs.rs b/crates/ibc-apps/ics20-transfer/types/src/msgs/mod.rs similarity index 98% rename from crates/ibc/src/applications/transfer/msgs.rs rename to crates/ibc-apps/ics20-transfer/types/src/msgs/mod.rs index c019a3120..9c6780741 100644 --- a/crates/ibc/src/applications/transfer/msgs.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/msgs/mod.rs @@ -1,3 +1,2 @@ //! Defines the token transfer message type - pub mod transfer; diff --git a/crates/ibc/src/applications/transfer/msgs/transfer.rs b/crates/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs similarity index 91% rename from crates/ibc/src/applications/transfer/msgs/transfer.rs rename to crates/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs index 5ea2d66d7..eb061d9a2 100644 --- a/crates/ibc/src/applications/transfer/msgs/transfer.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs @@ -1,17 +1,16 @@ //! Defines the token transfer message type - +use ibc::core::ics04_channel::error::PacketError; +use ibc::core::ics04_channel::timeout::TimeoutHeight; +use ibc::core::ics24_host::identifier::{ChannelId, PortId}; +use ibc::core::timestamp::Timestamp; +use ibc::core::{ContextError, Msg}; +use ibc::prelude::*; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::transfer::v1::MsgTransfer as RawMsgTransfer; use ibc_proto::Protobuf; -use crate::applications::transfer::error::TokenTransferError; -use crate::applications::transfer::packet::PacketData; -use crate::core::ics04_channel::error::PacketError; -use crate::core::ics04_channel::timeout::TimeoutHeight; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::core::timestamp::Timestamp; -use crate::core::{ContextError, Msg}; -use crate::prelude::*; +use crate::error::TokenTransferError; +use crate::packet::PacketData; pub(crate) const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer"; diff --git a/crates/ibc/src/applications/transfer/packet.rs b/crates/ibc-apps/ics20-transfer/types/src/packet.rs similarity index 95% rename from crates/ibc/src/applications/transfer/packet.rs rename to crates/ibc-apps/ics20-transfer/types/src/packet.rs index 63058b2ed..bb556af34 100644 --- a/crates/ibc/src/applications/transfer/packet.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/packet.rs @@ -1,16 +1,14 @@ //! Contains the `PacketData` type that defines the structure of token transfers' packet bytes -use alloc::string::ToString; use core::convert::TryFrom; use core::str::FromStr; +use ibc::prelude::*; +use ibc::Signer; use ibc_proto::ibc::applications::transfer::v2::FungibleTokenPacketData as RawPacketData; use super::error::TokenTransferError; use super::{Amount, Memo, PrefixedCoin, PrefixedDenom}; -#[cfg(feature = "schema")] -use crate::alloc::borrow::ToOwned; -use crate::signer::Signer; /// Defines the structure of token transfers' packet bytes #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -69,7 +67,7 @@ mod tests { use primitive_types::U256; use super::*; - use crate::applications::transfer::BaseCoin; + use crate::BaseCoin; impl PacketData { pub fn new_dummy() -> Self { diff --git a/crates/ibc-apps/ics20-transfer/types/src/serializers.rs b/crates/ibc-apps/ics20-transfer/types/src/serializers.rs new file mode 100644 index 000000000..57f6e20d3 --- /dev/null +++ b/crates/ibc-apps/ics20-transfer/types/src/serializers.rs @@ -0,0 +1,27 @@ +use core::fmt::Display; +use core::str::FromStr; + +use ibc::prelude::*; +use serde::{de, Deserialize, Deserializer, Serializer}; + +// Note: This method serializes to a String instead of a str +// in order to avoid a wasm compilation issue. Specifically, +// str (de)serialization hits some kind of f64/f32 case +// when compiled into wasm, but this fails validation on +// f32/f64 wasm runtimes. +pub fn serialize(value: &T, serializer: S) -> Result +where + T: Display, + S: Serializer, +{ + serializer.serialize_str(value.to_string().as_ref()) +} + +pub fn deserialize<'de, T, D>(deserializer: D) -> Result +where + T: FromStr, + T::Err: Display, + D: Deserializer<'de>, +{ + T::from_str(::deserialize(deserializer)?.as_str()).map_err(de::Error::custom) +} diff --git a/crates/ibc-apps/src/lib.rs b/crates/ibc-apps/src/lib.rs new file mode 100644 index 000000000..3693d65d4 --- /dev/null +++ b/crates/ibc-apps/src/lib.rs @@ -0,0 +1,20 @@ +//! Re-exports implementations and data structures of different IBC applications. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +/// Re-exports the implementation of the IBC [fungible token +/// transfer](https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md) +/// (ICS-20) application logic. +pub mod transfer { + #[doc(inline)] + pub use ibc_app_transfer::*; +} diff --git a/crates/ibc-testkit/Cargo.toml b/crates/ibc-testkit/Cargo.toml index 8a8c9137d..57b1e061b 100644 --- a/crates/ibc-testkit/Cargo.toml +++ b/crates/ibc-testkit/Cargo.toml @@ -30,7 +30,8 @@ tracing = { workspace = true } typed-builder = { workspace = true } # ibc dependencies -ibc = { version = "0.47.0" , path = "../ibc" } # NOTE: since `ibc-testkit` does not well support `no_std` yet, we keep `ibc` default features enabled +ibc = { version = "0.47.0", path = "../ibc" } # NOTE: since `ibc-testkit` does not well support `no_std` yet, we keep `ibc` default features enabled +ibc-app-transfer = { version = "0.47.0", path = "../ibc-apps/ics20-transfer", default-features = false, features = ["serde"] } # cosmos dependencies tendermint = { workspace = true } @@ -46,6 +47,7 @@ test-log = { workspace = true } default = ["std"] std = [ "ibc/std", + "ibc-app-transfer/std", "tracing/std", "prost/std", "serde/std", diff --git a/crates/ibc-testkit/src/testapp/ibc/applications/transfer/context.rs b/crates/ibc-testkit/src/testapp/ibc/applications/transfer/context.rs index f8ec4ae88..1e31a3254 100644 --- a/crates/ibc-testkit/src/testapp/ibc/applications/transfer/context.rs +++ b/crates/ibc-testkit/src/testapp/ibc/applications/transfer/context.rs @@ -1,11 +1,11 @@ -use ibc::applications::transfer::context::{ - cosmos_adr028_escrow_address, TokenTransferExecutionContext, TokenTransferValidationContext, -}; -use ibc::applications::transfer::error::TokenTransferError; -use ibc::applications::transfer::PrefixedCoin; use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::prelude::*; use ibc::Signer; +use ibc_app_transfer::context::{ + cosmos_adr028_escrow_address, TokenTransferExecutionContext, TokenTransferValidationContext, +}; +use ibc_app_transfer::types::error::TokenTransferError; +use ibc_app_transfer::types::PrefixedCoin; use subtle_encoding::bech32; use super::types::DummyTransferModule; diff --git a/crates/ibc-testkit/src/testapp/ibc/core/router/types.rs b/crates/ibc-testkit/src/testapp/ibc/core/router/types.rs index b0aaaae1b..2874f43cd 100644 --- a/crates/ibc-testkit/src/testapp/ibc/core/router/types.rs +++ b/crates/ibc-testkit/src/testapp/ibc/core/router/types.rs @@ -1,10 +1,10 @@ use alloc::collections::BTreeMap; use alloc::sync::Arc; -use ibc::applications::transfer::MODULE_ID_STR; use ibc::core::ics24_host::identifier::PortId; use ibc::core::router::{Module, ModuleId}; use ibc::prelude::*; +use ibc_app_transfer::types::MODULE_ID_STR; use crate::testapp::ibc::applications::transfer::types::DummyTransferModule; diff --git a/crates/ibc-testkit/src/utils/dummies/applications/transfer.rs b/crates/ibc-testkit/src/utils/dummies/applications/transfer.rs index 0bf50c99b..49581488a 100644 --- a/crates/ibc-testkit/src/utils/dummies/applications/transfer.rs +++ b/crates/ibc-testkit/src/utils/dummies/applications/transfer.rs @@ -1,13 +1,13 @@ use alloc::string::ToString; -use ibc::applications::transfer::msgs::transfer::MsgTransfer; -use ibc::applications::transfer::packet::PacketData; -use ibc::applications::transfer::{Memo, PrefixedCoin}; use ibc::core::ics04_channel::packet::{Packet, Sequence}; use ibc::core::ics04_channel::timeout::TimeoutHeight; use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::core::timestamp::Timestamp; use ibc::Signer; +use ibc_app_transfer::types::msgs::transfer::MsgTransfer; +use ibc_app_transfer::types::packet::PacketData; +use ibc_app_transfer::types::{Memo, PrefixedCoin}; use typed_builder::TypedBuilder; use crate::utils::dummies::core::signer::dummy_account_id; diff --git a/crates/ibc-testkit/tests/applications/transfer.rs b/crates/ibc-testkit/tests/applications/transfer.rs index 64d56b8c2..9ae6f664f 100644 --- a/crates/ibc-testkit/tests/applications/transfer.rs +++ b/crates/ibc-testkit/tests/applications/transfer.rs @@ -1,12 +1,13 @@ -use ibc::applications::transfer::context::{ - cosmos_adr028_escrow_address, on_chan_open_init_execute, on_chan_open_init_validate, - on_chan_open_try_execute, on_chan_open_try_validate, -}; -use ibc::applications::transfer::VERSION; use ibc::core::ics04_channel::channel::{Counterparty, Order}; use ibc::core::ics04_channel::Version; use ibc::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; use ibc::prelude::*; +use ibc_app_transfer::context::cosmos_adr028_escrow_address; +use ibc_app_transfer::module::{ + on_chan_open_init_execute, on_chan_open_init_validate, on_chan_open_try_execute, + on_chan_open_try_validate, +}; +use ibc_app_transfer::types::VERSION; use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; use subtle_encoding::bech32; diff --git a/crates/ibc-testkit/tests/core/ics04_channel/chan_open_ack.rs b/crates/ibc-testkit/tests/core/ics04_channel/chan_open_ack.rs index 25a7d36c5..14778bc25 100644 --- a/crates/ibc-testkit/tests/core/ics04_channel/chan_open_ack.rs +++ b/crates/ibc-testkit/tests/core/ics04_channel/chan_open_ack.rs @@ -1,4 +1,3 @@ -use ibc::applications::transfer::MODULE_ID_STR; use ibc::core::events::{IbcEvent, MessageEvent}; use ibc::core::ics03_connection::connection::{ ConnectionEnd, Counterparty as ConnectionCounterparty, State as ConnectionState, @@ -13,6 +12,7 @@ use ibc::core::timestamp::ZERO_DURATION; use ibc::core::{execute, validate, MsgEnvelope}; use ibc::prelude::*; use ibc::Height; +use ibc_app_transfer::types::MODULE_ID_STR; use ibc_testkit::testapp::ibc::clients::mock::client_state::client_type as mock_client_type; use ibc_testkit::testapp::ibc::core::router::MockRouter; use ibc_testkit::testapp::ibc::core::types::MockContext; diff --git a/crates/ibc-testkit/tests/core/router.rs b/crates/ibc-testkit/tests/core/router.rs index 94a5a0c2a..e27739858 100644 --- a/crates/ibc-testkit/tests/core/router.rs +++ b/crates/ibc-testkit/tests/core/router.rs @@ -1,6 +1,3 @@ -use ibc::applications::transfer::error::TokenTransferError; -use ibc::applications::transfer::msgs::transfer::MsgTransfer; -use ibc::applications::transfer::{send_transfer, BaseCoin}; use ibc::core::events::{IbcEvent, MessageEvent}; use ibc::core::ics02_client::msgs::create_client::MsgCreateClient; use ibc::core::ics02_client::msgs::update_client::MsgUpdateClient; @@ -23,6 +20,10 @@ use ibc::core::timestamp::Timestamp; use ibc::core::{dispatch, MsgEnvelope, RouterError, ValidationContext}; use ibc::prelude::*; use ibc::Height; +use ibc_app_transfer::handler::send_transfer::send_transfer; +use ibc_app_transfer::types::error::TokenTransferError; +use ibc_app_transfer::types::msgs::transfer::MsgTransfer; +use ibc_app_transfer::types::BaseCoin; use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; use ibc_testkit::testapp::ibc::clients::mock::consensus_state::MockConsensusState; diff --git a/crates/ibc/Cargo.toml b/crates/ibc/Cargo.toml index 8bd87b26f..9a9cc1805 100644 --- a/crates/ibc/Cargo.toml +++ b/crates/ibc/Cargo.toml @@ -22,7 +22,6 @@ borsh = { workspace = true, optional = true } bytes = { workspace = true } derive_more = { workspace = true } displaydoc = { workspace = true } -primitive-types = { workspace = true } prost = { workspace = true } serde_derive = { workspace = true, optional = true } serde = { workspace = true, optional = true } @@ -32,9 +31,9 @@ sha2 = { workspace = true, default-features = false } time = { workspace = true, default-features = false } schemars = { workspace = true, optional = true } typed-builder = { workspace = true, optional = true } -uint = { version = "0.9", default-features = false } # ibc dependencies +# ibc-apps = { version = "0.47.0", path = "../ibc-apps" } ibc-derive = { version = "0.3.0", path = "../ibc-derive" } ibc-proto = { workspace = true } ics23 = { workspace = true, features = ["host-functions"] } @@ -70,8 +69,6 @@ std = [ "serde_json/std", "sha2/std", "displaydoc/std", - "uint/std", - "primitive-types/std", "tendermint/clock", "tendermint/std", ] diff --git a/crates/ibc/src/applications/mod.rs b/crates/ibc/src/applications/mod.rs deleted file mode 100644 index bfbfd10f6..000000000 --- a/crates/ibc/src/applications/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Implementation of IBC applications - -#[cfg(feature = "serde")] -pub mod transfer; diff --git a/crates/ibc/src/applications/transfer/mod.rs b/crates/ibc/src/applications/transfer/mod.rs deleted file mode 100644 index 198a9f82e..000000000 --- a/crates/ibc/src/applications/transfer/mod.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Implementation of the [fungible token transfer module](https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md) (ICS-20) - -pub mod amount; -pub mod coin; -pub mod context; -pub mod denom; -pub mod error; -pub mod events; -pub mod memo; -pub mod msgs; -pub mod packet; - -pub use amount::*; -pub use coin::*; -pub use denom::*; -pub use memo::*; - -mod relay; - -pub use relay::send_transfer::{send_transfer, send_transfer_execute, send_transfer_validate}; - -/// Module identifier for the ICS20 application. -pub const MODULE_ID_STR: &str = "transfer"; - -/// The port identifier that the ICS20 applications -/// typically bind with. -pub const PORT_ID_STR: &str = "transfer"; - -/// ICS20 application current version. -pub const VERSION: &str = "ics20-1"; - -/// The successful string used for creating an acknowledgement status, -/// equivalent to `base64::encode(0x01)`. -pub const ACK_SUCCESS_B64: &str = "AQ=="; - -use crate::core::ics04_channel::acknowledgement::StatusValue; - -/// Returns a successful acknowledgement status for the token transfer application. -pub fn ack_success_b64() -> StatusValue { - StatusValue::new(ACK_SUCCESS_B64).expect("ack status value is never supposed to be empty") -} diff --git a/crates/ibc/src/core/ics04_channel/acknowledgement.rs b/crates/ibc/src/core/ics04_channel/acknowledgement.rs index c7a91c754..732234103 100644 --- a/crates/ibc/src/core/ics04_channel/acknowledgement.rs +++ b/crates/ibc/src/core/ics04_channel/acknowledgement.rs @@ -140,71 +140,3 @@ impl From for Acknowledgement { .expect("token transfer internal error: ack is never supposed to be empty") } } - -#[cfg(test)] -mod test { - use super::*; - use crate::applications::transfer::ack_success_b64; - use crate::applications::transfer::error::TokenTransferError; - - #[test] - fn test_ack_ser() { - fn ser_json_assert_eq(ack: AcknowledgementStatus, json_str: &str) { - let ser = serde_json::to_string(&ack).unwrap(); - assert_eq!(ser, json_str) - } - - ser_json_assert_eq( - AcknowledgementStatus::success(ack_success_b64()), - r#"{"result":"AQ=="}"#, - ); - ser_json_assert_eq( - AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()), - r#"{"error":"failed to deserialize packet data"}"#, - ); - } - - #[test] - fn test_ack_success_to_vec() { - let ack_success: Vec = AcknowledgementStatus::success(ack_success_b64()).into(); - - // Check that it's the same output as ibc-go - // Note: this also implicitly checks that the ack bytes are non-empty, - // which would make the conversion to `Acknowledgement` panic - assert_eq!(ack_success, r#"{"result":"AQ=="}"#.as_bytes()); - } - - #[test] - fn test_ack_error_to_vec() { - let ack_error: Vec = - AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()) - .into(); - - // Check that it's the same output as ibc-go - // Note: this also implicitly checks that the ack bytes are non-empty, - // which would make the conversion to `Acknowledgement` panic - assert_eq!( - ack_error, - r#"{"error":"failed to deserialize packet data"}"#.as_bytes() - ); - } - - #[test] - fn test_ack_de() { - fn de_json_assert_eq(json_str: &str, ack: AcknowledgementStatus) { - let de = serde_json::from_str::(json_str).unwrap(); - assert_eq!(de, ack) - } - - de_json_assert_eq( - r#"{"result":"AQ=="}"#, - AcknowledgementStatus::success(ack_success_b64()), - ); - de_json_assert_eq( - r#"{"error":"failed to deserialize packet data"}"#, - AcknowledgementStatus::error(TokenTransferError::PacketDataDeserialization.into()), - ); - - assert!(serde_json::from_str::(r#"{"success":"AQ=="}"#).is_err()); - } -} diff --git a/crates/ibc/src/core/ics04_channel/handler.rs b/crates/ibc/src/core/ics04_channel/handler.rs index 0950dc923..ab39f168a 100644 --- a/crates/ibc/src/core/ics04_channel/handler.rs +++ b/crates/ibc/src/core/ics04_channel/handler.rs @@ -1,13 +1,13 @@ //! This module implements the processing logic for ICS4 (channel) messages. -pub(crate) mod acknowledgement; -pub(crate) mod chan_close_confirm; -pub(crate) mod chan_close_init; -pub(crate) mod chan_open_ack; -pub(crate) mod chan_open_confirm; -pub(crate) mod chan_open_init; -pub(crate) mod chan_open_try; -pub(crate) mod recv_packet; -pub(crate) mod send_packet; -pub(crate) mod timeout; -pub(crate) mod timeout_on_close; +pub mod acknowledgement; +pub mod chan_close_confirm; +pub mod chan_close_init; +pub mod chan_open_ack; +pub mod chan_open_confirm; +pub mod chan_open_init; +pub mod chan_open_try; +pub mod recv_packet; +pub mod send_packet; +pub mod timeout; +pub mod timeout_on_close; diff --git a/crates/ibc/src/core/ics04_channel/mod.rs b/crates/ibc/src/core/ics04_channel/mod.rs index 40e6538cf..a969a9cde 100644 --- a/crates/ibc/src/core/ics04_channel/mod.rs +++ b/crates/ibc/src/core/ics04_channel/mod.rs @@ -6,7 +6,7 @@ pub mod context; pub mod error; pub mod events; -pub(crate) mod handler; +pub mod handler; pub mod msgs; pub mod packet; pub mod timeout; diff --git a/crates/ibc/src/lib.rs b/crates/ibc/src/lib.rs index 16318bdfb..868b36c42 100644 --- a/crates/ibc/src/lib.rs +++ b/crates/ibc/src/lib.rs @@ -24,9 +24,6 @@ //! client interface that is defined in `Core`) for specific consensus algorithms. A chain uses these //! verification algorithms to verify the state of remote chains. //! -//! + [Applications](applications) consists of implementations of some IBC applications. This is the part of -//! the protocol that abstracts away the core protocol and focuses solely on business logic. -//! //! When processing a given message `M`, if any method in this library returns an error, the runtime //! is expected to rollback all state modifications made to the context //! (e.g. [`ExecutionContext`](core::ExecutionContext)) while processing `M`. If a transaction on your @@ -50,7 +47,6 @@ pub use signer::Signer; /// Represents a block height pub use crate::core::ics02_client::height::Height; -pub mod applications; pub mod clients; pub mod core; pub mod hosts; @@ -65,7 +61,6 @@ mod serializers; /// Re-exports pertinent ibc proto types from the `ibc-proto-rs` crate for added convenience pub mod proto { pub use ibc_proto::google::protobuf::Any; - pub use ibc_proto::ibc::apps::transfer; pub use ibc_proto::ibc::lightclients::tendermint; pub use ibc_proto::ibc::{core, mock}; pub use ibc_proto::{ics23, Protobuf}; diff --git a/crates/ibc/src/serializers.rs b/crates/ibc/src/serializers.rs index a4b56473b..081cd05fe 100644 --- a/crates/ibc/src/serializers.rs +++ b/crates/ibc/src/serializers.rs @@ -12,35 +12,6 @@ where hex.serialize(serializer) } -pub mod serde_string { - use core::fmt::Display; - use core::str::FromStr; - - use serde::{de, Deserialize, Deserializer, Serializer}; - - use crate::prelude::*; - - // Note: used String version (slower + heap) instead of str, - // because both str ser/de hit some kind of f64/f32 case when compiled into wasm - // and fails to be validated f32/f64 wasm runtimes - pub fn serialize(value: &T, serializer: S) -> Result - where - T: Display, - S: Serializer, - { - serializer.serialize_str(value.to_string().as_ref()) - } - - pub fn deserialize<'de, T, D>(deserializer: D) -> Result - where - T: FromStr, - T::Err: Display, - D: Deserializer<'de>, - { - T::from_str(::deserialize(deserializer)?.as_str()).map_err(de::Error::custom) - } -} - /// Test that a struct `T` can be: /// /// - parsed out of the provided JSON data From 55038aabfb5e3899e94e70bc08e6a1d1f6e892be Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Tue, 21 Nov 2023 09:57:24 -0800 Subject: [PATCH 02/13] docs: ADR-008 to restructure the `ibc` crate (#966) * docs: write ADR for ibc crate restructure * fix: mistaken adr007 file naming * chore: markdown adjustment * fix: apply suggestions from code review Co-authored-by: Sean Chen Signed-off-by: Farhad Shabani * docs: explanation for *-types interaction with ibc-proto --------- Signed-off-by: Farhad Shabani Co-authored-by: Sean Chen --- .../adr-008-restructure-ibc-crate.md | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 docs/architecture/adr-008-restructure-ibc-crate.md diff --git a/docs/architecture/adr-008-restructure-ibc-crate.md b/docs/architecture/adr-008-restructure-ibc-crate.md new file mode 100644 index 000000000..45c7be6e8 --- /dev/null +++ b/docs/architecture/adr-008-restructure-ibc-crate.md @@ -0,0 +1,190 @@ +# ADR 008: RESTRUCTURE `ibc` CRATE + +## Context + +The current state of the **`ibc`** crate exhibits a mix of different +implementation layers. From a module-based perspective, it encompasses essential +elements like ibc core, clients, applications, along with testing facilities. +However, an architectural view reveals a fusion of diverse layers of type +definitions, interfaces (APIs), and handler functions, resulting in a mix of +dependencies and features that may lead to potential conflicts or unnecessary +imports for users. + +As of [this pull request](https://github.com/cosmos/ibc-rs/pull/954), we've +separated our mock testing kit into the standalone **`ibc-testkit`** library. +This decoupling from the main **`ibc`** crate sets the stage for the objectives +of this ADR. + +The primary goals here are twofold: firstly, to reduce interdependence within +the codebase among various components such as ibc core, clients, and +applications, and secondly, to improve the overall usability of the `ibc-rs` +implementation. The overarching aim is to empower users to selectively import +specific IBC layers, mitigating potential conflicts related to dependencies or +features that may arise in the context of a monolithic library and letting +`ibc-rs` be used in the following scenarios: + +1. **Selective Module Import** + - Users cannot import only the necessary components/modules for their + projects. For instance, importing only the **`ics07_tendermint`** + implementation is impractical. +2. **Selective Types Import** + - Relayers, like Hermes, or any off-chain consumers cannot import their + desired layer of implementation like ibc types without pulling in + unnecessary dependencies into their project. +3. **Smoother IBC Core Integration with Hosts** + - Integrating ibc core with host chains without introducing light client or + app dependencies is currently not straightforward, impeding smooth + integration. +4. **Easier Development of CosmWasm Contracts** + - For developing a CosmWasm tendermint light client, we ideally should only + be dependent on implementation under the **`ics07_tendermint`** and also + be importing relevant parts from the **`ibc-core-client`** layer without + pulling in all the ibc codebase and dependencies. + +This ADR aims to enhance both the usability and practicality of `ibc-rs` by +restructuring the codebase and organizing it under multiple sub-libraries, as +stated in the [decision](#decision) section. This will make different parts of +`ibc-rs` accessible to users, positioning it as a more comprehensive, one-stop +solution catering to diverse user groups, whether for on-chain or off-chain use +cases. + +## Decision + +For the library organization, the first stage of separation is to split the +codebase so that each IBC application, client, and core implementation is +decoupled from one another. The top-level libraries and the naming schema would +look as follows: + +```markdown +. +├── ibc -> Primarily re-exports sub-libraries +├── ibc-core +│ ├── ibc-core-client (contains the implementation + Re-exports types) +│ ├── ibc-core-connection +│ ├── ibc-core-channel +│ ├── ibc-core-commitment +│ └── ibc-core-host +│ └── . +├── ibc-clients +│ ├── ibc-client-tendermint +│ ├── ibc-client-tendermint-cw +│ └── . +├── ibc-apps +│ ├── ibc-app-transfer +│ ├── ibc-app-ica +│ │ └── . +│ └── . +├── ibc-primitives +├── ibc-testkit (previously mock module + `test-utils` feature) +├── ibc-query +└── ibc-derive +``` + +With this restructure, the main `ibc` crate primarily re-exports types, +interfaces, and implementations of all the sub-libraries. Therefore, if someone +only wants to depend on the `ibc` crate without caring about this granularity, +they can do so. + +Afterward, we split off data structure (domain types) of each IBC layer into a +separate sub-library under a `types` folder, still maintained under the +directory of that relevant component/module. As an example, the +`ibc-core-client` crate’s tree and the naming schema would look like this: + +```markdown +ibc-core +└── ibc-core-client (dir: ibc-core/ics02-client) + └── ibc-core-client-types (dir: ibc-core/ics02-client/types) + ├── msgs + ├── events + └── . +``` + +This way, the main crate of each IBC module contains all the necessary APIs and +implementations to integrate with host chains, along with re-exporting the +sub-library types. This allows projects to selectively import types (e.g. +`ibc-core-client-types`), often required by off-chain users such as relayers. Or +to pick the library containing the entire implementation of that particular +module (e.g. `ibc-core-client`), typically more convenient for host chains or +smart contract developers to integrate with on their end. + +Once the restructuring is complete, the **directory tree** of the repo would +look as follows: + +```markdown +ibc +ibc-core +├── ics02-client +| ├── src +| ├── types +| | ├── src +| | └── Cargo.toml +| └── Cargo.toml +├── ics03-connection +| └── . +├── ics04-channel +| └── . +├── ics23-commitment +| └── . +├── ics24-host +| └── . +├── src +├── Cargo.toml +└── README.md +ibc-clients +├── ics07-tendermint +├── ics08-wasm +└── . +ibc-apps +├── ics20-transfer +├── ics27-ica +└── . +ibc-primitives +ibc-testkit +ibc-query +ibc-derive +``` + +In the refactored codebase, there will be several `*-types` crates that rely on +the `ibc-proto` library. This library acts as an upstream crate, facilitating +the conversion to and from proto types. Each `*-types` crate also re-exports +crucial proto types for added user convenience. This approach ensures a seamless +experience for users downstream, sparing them the necessity of directly +including the `ibc-proto` dependency in their projects. Consequently, the +`*-types` crates serve as comprehensive, battery-included libraries. + +To implement this ADR efficiently and for more organization, we use the +workspace inheritance feature and will add a top-level README for main library +groups like `ibc-core`, `ibc-clients`, etc serving as a guide for users to +understand the purpose and structure of their sub libraries. + +Later, it is crucial to come up with a Github action to automate and simplify +the release process as well. + +## **Status** + +Proposed + +## **Consequences** + +We should acknowledge this restructuring, while a significant step forward, will +not completely address all existing design couplings. Subsequent improvements in +implementation logic will be necessary to completely decouple ibc core, clients, +and applications from each other and make the entire logic as chain-agnostic as +possible. For instance, currently, our `IbcEvent` type depends on the Tendermint +events in their conversion, which can only be addressed once this restructuring +is complete. There may be other mix-ups as well, but the new repository +structure significantly simplifies their handling and ensures `ibc-rs` evolves +into a more adaptable, modular, and composable implementation that can serve +various use cases. + +### **Positive** + +- Opens up a range of new use cases for `ibc-rs` +- Facilitates moving toward more chain-agnostic and flexible design and interfaces +- Simplifies development on top of each layer of `ibc-rs` implementation + +### **Negative** + +- Multiple libraries are more challenging to maintain +- Enforces current users to update a large number of their import paths from + `ibc` crates From 3cc9753268c05229f70379214301ddc964a69050 Mon Sep 17 00:00:00 2001 From: Farhad Shabani Date: Tue, 21 Nov 2023 09:58:57 -0800 Subject: [PATCH 03/13] feat: migrate `core`, `clients` modules into `ibc-core`, `ibc-clients` crates (#969) * feat: migrate `core` module under the `ibc` crate into `ibc-core` feat: migrate `core` module under the `ibc` crate into `ibc-core` feat: migrate `applications` module under the `ibc` crate into `ibc-apps` (#967) * feat: restructure and split off applications codebase into ibc-apps dir * imp: rename transfer dir to ics20_transfer * feat: add ibc-apps crate * fix: remove redundant dep + fix cargo doc * docs: add README and descriptions * docs: update main README page * nit: docstrings * nit: docstrings * imp: rename folder to ics20-transfer * chore: move serializers into ics20-transfer/types * fix: apply reviewer comments * imp: add docstring for cosmos_adr028_escrow_address * fix: add missing features + use workspace deps for ibc crates * imp: place re-exports under mod * nit: apply suggestions from code review Co-authored-by: Sean Chen Signed-off-by: Farhad Shabani * fix: cargo fmt --------- Signed-off-by: Farhad Shabani Co-authored-by: Sean Chen feat: restructure and split off applications codebase into ibc-apps dir refactor: nits from nightly clippy (#962) * use enum tuple variants directly * use first() over get(0) * use infallible conversion * rm redundant export * cargo fmt ci: spell check on GitHub workflows (#964) * typos github action * cutom config for typos * fix spelling to counterparty * fix spelling to transfer imp: rename transfer dir to ics20_transfer feat: add ibc-apps crate fix: remove redundant dep + fix cargo doc docs: add README and descriptions docs: update main README page nit: docstrings nit: docstrings imp: rename folder to ics20-transfer chore: move serializers into ics20-transfer/types fix: apply reviewer comments imp: add docstring for cosmos_adr028_escrow_address fix: add missing features + use workspace deps for ibc crates imp: place re-exports under mod feat: ibc core codebase overhaul (part-1) feat: ibc core codebase overhaul (part-2) chore: comment out ibc-query & ibc-testkit fix: add missing features nit * fix: re-export ibc_apps in the ibc crate * chore: adjust features + add description for crates * fix: CI catches * fix: no_std * imp: define ics25-handler + move tendermint-specific impls into ibc-core-host-tendermint * fix: cargo doc * docs: add and edit READMEs * fix: cargo hack catches * fix: cargo udeps catches * chore: ajdust README tables * docs: further README adjustments * fix: typo * chore: another review of comments & READMEs * imp: move Any and Protobuf to ibc-primitives * fix: missing std features * Split out ibc-clients crate (#971) * Migrate crates/ibc-clients * Fix dependencies in types directory * Fix dependencies in ibc-clients crate * Delete ibc/ics07_tendermint directory * Resolve dependencies in ibc crate * Resolve dependencies in ibc-clients crate * Wrap ClientState type in a newtype wrapper * Address all compilation errors * Migrate crates/ibc-clients * Fix dependencies in types directory * Fix dependencies in ibc-clients crate * Delete ibc/ics07_tendermint directory * Resolve dependencies in ibc crate * Resolve dependencies in ibc-clients crate * Wrap ClientState type in a newtype wrapper * Address all compilation errors * Add default feature `std` for ibc-clients crate * Change cfg derivation * Fixing import paths * Fix import paths for ibc-client-tendermint crate * Fix merge conflicts * Fix merge conflicts * Fix merge conflicts * Fix remaining compilation errors in ics07-tendermint crate * chore: adjust import paths, features and READMEs * fix: CI catches * fix: add serde dep for ibc-client-tendermint * fix: serde_tests * imp: rename ClientState to ClientStateWrapper --------- Co-authored-by: Farhad Shabani * docs: improve crates descriptions * fix: apply reviewer comments * Delete some unused modules and add some documentation * Add TODO to use u64::dev_ceil * Formatting of ibc-primitives README * fix: ibc-primitives serde feature --------- Co-authored-by: Sean Chen --- Cargo.toml | 114 +++- README.md | 55 +- ci/no-std-check/Cargo.lock | 320 ++++++++- crates/ibc-apps/Cargo.toml | 9 +- crates/ibc-apps/README.md | 51 +- crates/ibc-apps/ics20-transfer/Cargo.toml | 17 +- crates/ibc-apps/ics20-transfer/src/context.rs | 6 +- .../ics20-transfer/src/handler/mod.rs | 3 +- .../src/handler/on_recv_packet.rs | 6 +- .../src/handler/send_transfer.rs | 13 +- crates/ibc-apps/ics20-transfer/src/module.rs | 18 +- .../ibc-apps/ics20-transfer/types/Cargo.toml | 37 +- .../ics20-transfer/types/src/amount.rs | 2 +- .../ibc-apps/ics20-transfer/types/src/coin.rs | 2 +- .../ics20-transfer/types/src/denom.rs | 4 +- .../ics20-transfer/types/src/error.rs | 11 +- .../ics20-transfer/types/src/events.rs | 18 +- .../ibc-apps/ics20-transfer/types/src/lib.rs | 4 +- .../ibc-apps/ics20-transfer/types/src/memo.rs | 2 +- .../ics20-transfer/types/src/msgs/transfer.rs | 13 +- .../ics20-transfer/types/src/packet.rs | 4 +- .../ics20-transfer/types/src/serializers.rs | 2 +- crates/ibc-clients/Cargo.toml | 29 + crates/ibc-clients/README.md | 46 ++ .../ibc-clients/ics07-tendermint/Cargo.toml | 78 +++ .../ics07-tendermint/src/client_state.rs | 571 ++++++++++++++++ .../src}/client_state/misbehaviour.rs | 55 +- .../src}/client_state/update_client.rs | 71 +- .../ics07-tendermint/src}/context.rs | 16 +- .../ibc-clients/ics07-tendermint/src/lib.rs | 30 + .../ics07-tendermint/types/Cargo.toml | 106 +++ .../ics07-tendermint/types/README.md | 0 .../types/src}/client_state.rs | 568 ++-------------- .../types/src}/consensus_state.rs | 57 +- .../ics07-tendermint/types/src}/error.rs | 12 +- .../ics07-tendermint/types/src}/header.rs | 21 +- .../ics07-tendermint/types/src/lib.rs | 63 ++ .../types/src}/misbehaviour.rs | 10 +- .../types/src}/trust_threshold.rs | 3 +- crates/ibc-clients/src/lib.rs | 18 + crates/ibc-core/Cargo.toml | 75 +++ crates/ibc-core/README.md | 124 ++++ crates/ibc-core/ics02-client/Cargo.toml | 76 +++ .../ibc-core/ics02-client/context/Cargo.toml | 81 +++ .../ics02-client/context/src}/client_state.rs | 66 +- .../context/src}/consensus_state.rs | 7 +- .../ics02-client/context/src}/context.rs | 15 +- .../ibc-core/ics02-client/context/src/lib.rs | 30 + .../src}/handler/create_client.rs | 24 +- .../ics02-client/src/handler/mod.rs} | 0 .../src}/handler/update_client.rs | 26 +- .../src}/handler/upgrade_client.rs | 33 +- crates/ibc-core/ics02-client/src/lib.rs | 31 + crates/ibc-core/ics02-client/types/Cargo.toml | 88 +++ .../ics02-client/types/src}/error.rs | 29 +- .../ics02-client/types/src}/events.rs | 9 +- .../ics02-client/types/src}/height.rs | 4 +- crates/ibc-core/ics02-client/types/src/lib.rs | 29 + .../types/src}/msgs/create_client.rs | 14 +- .../types/src}/msgs/misbehaviour.rs | 13 +- .../ics02-client/types/src/msgs/mod.rs} | 30 +- .../types/src}/msgs/update_client.rs | 16 +- .../types/src}/msgs/upgrade_client.rs | 19 +- .../ibc-core/ics02-client/types/src/status.rs | 47 ++ crates/ibc-core/ics03-connection/Cargo.toml | 66 ++ .../ics03-connection/src}/delay.rs | 11 +- .../src}/handler/conn_open_ack.rs | 50 +- .../src}/handler/conn_open_confirm.rs | 45 +- .../src}/handler/conn_open_init.rs | 26 +- .../src}/handler/conn_open_try.rs | 53 +- .../ics03-connection/src/handler/mod.rs | 4 + crates/ibc-core/ics03-connection/src/lib.rs | 26 + .../ics03-connection/types/Cargo.toml | 92 +++ .../ics03-connection/types/src}/connection.rs | 14 +- .../ics03-connection/types/src}/error.rs | 13 +- .../ics03-connection/types/src}/events.rs | 9 +- .../ics03-connection/types/src/lib.rs | 29 + .../types/src}/msgs/conn_open_ack.rs | 24 +- .../types/src}/msgs/conn_open_confirm.rs | 22 +- .../types/src}/msgs/conn_open_init.rs | 20 +- .../types/src}/msgs/conn_open_try.rs | 26 +- .../ics03-connection/types/src/msgs/mod.rs} | 19 +- .../ics03-connection/types/src}/version.rs | 19 +- crates/ibc-core/ics04-channel/Cargo.toml | 84 +++ .../ics04-channel/src}/context.rs | 70 +- .../src}/handler/acknowledgement.rs | 42 +- .../src}/handler/chan_close_confirm.rs | 43 +- .../src}/handler/chan_close_init.rs | 31 +- .../src}/handler/chan_open_ack.rs | 44 +- .../src}/handler/chan_open_confirm.rs | 43 +- .../src}/handler/chan_open_init.rs | 29 +- .../src}/handler/chan_open_try.rs | 45 +- .../ibc-core/ics04-channel/src/handler/mod.rs | 24 + .../ics04-channel/src}/handler/recv_packet.rs | 50 +- .../ics04-channel/src}/handler/send_packet.rs | 38 +- .../ics04-channel/src}/handler/timeout.rs | 49 +- .../src}/handler/timeout_on_close.rs | 35 +- crates/ibc-core/ics04-channel/src/lib.rs | 26 + .../ibc-core/ics04-channel/types/Cargo.toml | 101 +++ .../types/src}/acknowledgement.rs | 2 +- .../ics04-channel/types/src}/channel.rs | 17 +- .../ics04-channel/types/src}/commitment.rs | 9 +- .../ics04-channel/types/src}/error.rs | 17 +- .../ics04-channel/types/src}/events.rs | 11 +- .../types/src}/events/channel_attributes.rs | 4 +- .../types/src}/events/packet_attributes.rs | 15 +- .../ibc-core/ics04-channel/types/src/lib.rs | 35 + .../types/src}/msgs/acknowledgement.rs | 26 +- .../types/src}/msgs/chan_close_confirm.rs | 21 +- .../types/src}/msgs/chan_close_init.rs | 18 +- .../types/src}/msgs/chan_open_ack.rs | 24 +- .../types/src}/msgs/chan_open_confirm.rs | 22 +- .../types/src}/msgs/chan_open_init.rs | 26 +- .../types/src}/msgs/chan_open_try.rs | 30 +- .../ics04-channel/types/src/msgs/mod.rs} | 50 +- .../types/src}/msgs/recv_packet.rs | 24 +- .../ics04-channel/types/src}/msgs/timeout.rs | 25 +- .../types/src}/msgs/timeout_on_close.rs | 23 +- .../ics04-channel/types/src}/packet.rs | 93 +-- .../ics04-channel/types/src}/timeout.rs | 9 +- .../ics04-channel/types/src}/version.rs | 3 +- .../ics23-commitment/types/Cargo.toml | 74 +++ .../ics23-commitment/types/src}/commitment.rs | 8 +- .../ics23-commitment/types/src}/error.rs | 3 +- .../ics23-commitment/types/src/lib.rs | 31 + .../ics23-commitment/types/src}/merkle.rs | 8 +- .../ics23-commitment/types/src/serializer.rs | 14 + .../ics23-commitment/types/src}/specs.rs | 3 +- crates/ibc-core/ics24-host/Cargo.toml | 90 +++ .../ics24-host/src}/context.rs | 110 +-- crates/ibc-core/ics24-host/src/lib.rs | 29 + crates/ibc-core/ics24-host/src/utils.rs | 47 ++ .../ibc-core/ics24-host/tendermint/Cargo.toml | 100 +++ .../ibc-core/ics24-host/tendermint/src/lib.rs | 28 + .../src}/upgrade_proposal/context.rs | 11 +- .../src}/upgrade_proposal/events.rs | 5 +- .../src}/upgrade_proposal/handler.rs | 13 +- .../tendermint/src}/upgrade_proposal/mod.rs | 0 .../tendermint/src}/upgrade_proposal/plan.rs | 9 +- .../src}/upgrade_proposal/proposal.rs | 5 +- .../tendermint/src}/validate_self_client.rs | 56 +- crates/ibc-core/ics24-host/types/Cargo.toml | 62 ++ crates/ibc-core/ics24-host/types/src/error.rs | 31 + .../types/src/identifiers/chain_id.rs | 272 ++++++++ .../types/src/identifiers/channel_id.rs | 100 +++ .../types/src/identifiers/client_id.rs | 94 +++ .../types/src/identifiers}/client_type.rs | 7 +- .../types/src/identifiers/connection_id.rs | 93 +++ .../ics24-host/types/src/identifiers/mod.rs | 17 + .../types/src/identifiers/port_id.rs | 72 ++ .../types/src/identifiers/sequence.rs | 65 ++ crates/ibc-core/ics24-host/types/src/lib.rs | 21 + .../ics24-host/types/src}/path.rs | 44 +- .../ics24-host/types/src}/validate.rs | 7 +- crates/ibc-core/ics25-handler/Cargo.toml | 76 +++ .../ics25-handler/src/entrypoint.rs} | 70 +- crates/ibc-core/ics25-handler/src/lib.rs | 26 + .../ibc-core/ics25-handler/types/Cargo.toml | 115 ++++ .../ibc-core/ics25-handler/types/src/error.rs | 48 ++ .../ics25-handler/types/src}/events.rs | 108 +-- .../ibc-core/ics25-handler/types/src/lib.rs | 21 + .../ibc-core/ics25-handler/types/src/msgs.rs | 206 ++++++ crates/ibc-core/ics26-routing/Cargo.toml | 66 ++ crates/ibc-core/ics26-routing/src/lib.rs | 24 + .../ics26-routing/src/module.rs} | 107 +-- crates/ibc-core/ics26-routing/src/router.rs | 18 + .../ibc-core/ics26-routing/types/Cargo.toml | 84 +++ .../ibc-core/ics26-routing/types/src/error.rs | 19 + .../ibc-core/ics26-routing/types/src/event.rs | 67 ++ .../ibc-core/ics26-routing/types/src/lib.rs | 24 + .../ics26-routing/types/src/module.rs | 74 +++ crates/ibc-core/src/lib.rs | 67 ++ crates/ibc-data-types/Cargo.toml | 83 +++ crates/ibc-data-types/README.md | 50 ++ crates/ibc-data-types/src/lib.rs | 77 +++ crates/ibc-derive/Cargo.toml | 2 +- crates/ibc-derive/README.md | 88 +-- crates/ibc-derive/src/utils.rs | 32 +- crates/ibc-primitives/Cargo.toml | 68 ++ crates/ibc-primitives/README.md | 5 + crates/ibc-primitives/src/lib.rs | 32 + crates/{ibc => ibc-primitives}/src/prelude.rs | 0 crates/ibc-primitives/src/traits/mod.rs | 3 + crates/ibc-primitives/src/traits/msg.rs | 23 + crates/ibc-primitives/src/types/mod.rs | 5 + .../src/types}/signer.rs | 0 .../src/types}/timestamp.rs | 7 +- .../src/utils/macros.rs | 6 +- crates/ibc-primitives/src/utils/mod.rs | 5 + .../src/utils/pretty.rs | 3 + crates/ibc-query/Cargo.toml | 5 +- crates/ibc-query/README.md | 6 +- crates/ibc-query/src/core/channel/query.rs | 15 +- crates/ibc-query/src/core/channel/service.rs | 4 +- crates/ibc-query/src/core/client/query.rs | 27 +- crates/ibc-query/src/core/client/service.rs | 6 +- crates/ibc-query/src/core/connection/query.rs | 14 +- .../ibc-query/src/core/connection/service.rs | 4 +- crates/ibc-query/src/core/context.rs | 17 +- crates/ibc-query/src/error.rs | 6 +- crates/ibc-query/src/lib.rs | 10 +- crates/ibc-testkit/Cargo.toml | 52 +- crates/ibc-testkit/README.md | 7 +- crates/ibc-testkit/src/hosts/block.rs | 19 +- crates/ibc-testkit/src/relayer/context.rs | 28 +- crates/ibc-testkit/src/relayer/error.rs | 11 +- .../ibc/applications/transfer/context.rs | 5 +- .../ibc/applications/transfer/module.rs | 19 +- .../testapp/ibc/clients/mock/client_state.rs | 68 +- .../ibc/clients/mock/consensus_state.rs | 19 +- .../testapp/ibc/clients/mock/header copy.rs | 136 ---- .../src/testapp/ibc/clients/mock/header.rs | 11 +- .../testapp/ibc/clients/mock/misbehaviour.rs | 10 +- .../src/testapp/ibc/clients/mock/mod.rs | 5 + .../src/testapp/ibc/clients/mod.rs | 25 +- .../src/testapp/ibc/core/client_ctx.rs | 31 +- .../src/testapp/ibc/core/core_ctx.rs | 44 +- .../src/testapp/ibc/core/router/context.rs | 6 +- .../src/testapp/ibc/core/router/types.rs | 7 +- .../ibc-testkit/src/testapp/ibc/core/types.rs | 51 +- .../utils/dummies/applications/transfer.rs | 9 +- .../src/utils/dummies/clients/mock.rs | 3 +- .../src/utils/dummies/clients/tendermint.rs | 45 +- .../dummies/core/channel/acknowledgement.rs | 4 +- .../core/channel/chan_close_confirm.rs | 8 +- .../dummies/core/channel/chan_close_init.rs | 6 +- .../dummies/core/channel/chan_open_ack.rs | 8 +- .../dummies/core/channel/chan_open_confirm.rs | 8 +- .../dummies/core/channel/chan_open_init.rs | 6 +- .../dummies/core/channel/chan_open_try.rs | 8 +- .../src/utils/dummies/core/channel/mod.rs | 8 +- .../src/utils/dummies/core/channel/packet.rs | 14 +- .../utils/dummies/core/channel/recv_packet.rs | 14 +- .../src/utils/dummies/core/channel/timeout.rs | 4 +- .../dummies/core/channel/timeout_on_close.rs | 4 +- .../dummies/core/client/msg_create_client.rs | 6 +- .../dummies/core/client/msg_update_client.rs | 4 +- .../dummies/core/client/msg_upgrade_client.rs | 8 +- .../src/utils/dummies/core/commitment.rs | 8 +- .../dummies/core/connection/conn_open_ack.rs | 14 +- .../core/connection/conn_open_confirm.rs | 6 +- .../dummies/core/connection/conn_open_init.rs | 12 +- .../dummies/core/connection/conn_open_try.rs | 14 +- .../src/utils/dummies/core/connection/mod.rs | 8 +- .../src/utils/dummies/core/context.rs | 8 +- .../src/utils/dummies/core/signer.rs | 4 +- crates/ibc-testkit/src/utils/fixture.rs | 9 +- .../tests/applications/transfer.rs | 8 +- .../tests/core/ics02_client/create_client.rs | 18 +- .../tests/core/ics02_client/update_client.rs | 53 +- .../tests/core/ics02_client/upgrade_client.rs | 33 +- .../core/ics03_connection/conn_open_ack.rs | 37 +- .../ics03_connection/conn_open_confirm.rs | 20 +- .../core/ics03_connection/conn_open_init.rs | 17 +- .../core/ics03_connection/conn_open_try.rs | 16 +- .../core/ics04_channel/acknowledgement.rs | 28 +- .../core/ics04_channel/chan_close_confirm.rs | 21 +- .../core/ics04_channel/chan_close_init.rs | 21 +- .../tests/core/ics04_channel/chan_open_ack.rs | 23 +- .../core/ics04_channel/chan_open_confirm.rs | 23 +- .../core/ics04_channel/chan_open_init.rs | 20 +- .../tests/core/ics04_channel/chan_open_try.rs | 20 +- .../tests/core/ics04_channel/recv_packet.rs | 28 +- .../tests/core/ics04_channel/send_packet.rs | 21 +- .../tests/core/ics04_channel/timeout.rs | 28 +- .../core/ics04_channel/timeout_on_close.rs | 26 +- crates/ibc-testkit/tests/core/router.rs | 42 +- crates/ibc/Cargo.toml | 68 +- crates/ibc/README.md | 73 +- crates/ibc/clippy.toml | 9 - .../ibc/src/clients/ics07_tendermint/mod.rs | 34 - crates/ibc/src/clients/mod.rs | 16 - crates/ibc/src/core/ics02_client/mod.rs | 13 - .../ibc/src/core/ics03_connection/handler.rs | 7 - crates/ibc/src/core/ics03_connection/mod.rs | 11 - crates/ibc/src/core/ics04_channel/handler.rs | 13 - crates/ibc/src/core/ics04_channel/mod.rs | 17 - crates/ibc/src/core/ics23_commitment/mod.rs | 7 - crates/ibc/src/core/ics24_host/identifier.rs | 629 ------------------ crates/ibc/src/core/ics24_host/mod.rs | 5 - crates/ibc/src/core/mod.rs | 44 -- crates/ibc/src/core/msgs.rs | 203 ------ crates/ibc/src/hosts/mod.rs | 2 - crates/ibc/src/hosts/tendermint/mod.rs | 12 - crates/ibc/src/lib.rs | 83 +-- crates/ibc/src/serializers.rs | 45 -- crates/ibc/src/utils/mod.rs | 3 - 287 files changed, 7005 insertions(+), 4125 deletions(-) create mode 100644 crates/ibc-clients/Cargo.toml create mode 100644 crates/ibc-clients/README.md create mode 100644 crates/ibc-clients/ics07-tendermint/Cargo.toml create mode 100644 crates/ibc-clients/ics07-tendermint/src/client_state.rs rename crates/{ibc/src/clients/ics07_tendermint => ibc-clients/ics07-tendermint/src}/client_state/misbehaviour.rs (75%) rename crates/{ibc/src/clients/ics07_tendermint => ibc-clients/ics07-tendermint/src}/client_state/update_client.rs (77%) rename crates/{ibc/src/clients/ics07_tendermint => ibc-clients/ics07-tendermint/src}/context.rs (83%) create mode 100644 crates/ibc-clients/ics07-tendermint/src/lib.rs create mode 100644 crates/ibc-clients/ics07-tendermint/types/Cargo.toml create mode 100644 crates/ibc-clients/ics07-tendermint/types/README.md rename crates/{ibc/src/clients/ics07_tendermint => ibc-clients/ics07-tendermint/types/src}/client_state.rs (55%) rename crates/{ibc/src/clients/ics07_tendermint => ibc-clients/ics07-tendermint/types/src}/consensus_state.rs (88%) rename crates/{ibc/src/clients/ics07_tendermint => ibc-clients/ics07-tendermint/types/src}/error.rs (95%) rename crates/{ibc/src/clients/ics07_tendermint => ibc-clients/ics07-tendermint/types/src}/header.rs (94%) create mode 100644 crates/ibc-clients/ics07-tendermint/types/src/lib.rs rename crates/{ibc/src/clients/ics07_tendermint => ibc-clients/ics07-tendermint/types/src}/misbehaviour.rs (94%) rename crates/{ibc/src/clients/ics07_tendermint => ibc-clients/ics07-tendermint/types/src}/trust_threshold.rs (98%) create mode 100644 crates/ibc-clients/src/lib.rs create mode 100644 crates/ibc-core/Cargo.toml create mode 100644 crates/ibc-core/README.md create mode 100644 crates/ibc-core/ics02-client/Cargo.toml create mode 100644 crates/ibc-core/ics02-client/context/Cargo.toml rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/context/src}/client_state.rs (80%) rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/context/src}/consensus_state.rs (88%) rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/context/src}/context.rs (90%) create mode 100644 crates/ibc-core/ics02-client/context/src/lib.rs rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/src}/handler/create_client.rs (75%) rename crates/{ibc/src/core/ics02_client/handler.rs => ibc-core/ics02-client/src/handler/mod.rs} (100%) rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/src}/handler/update_client.rs (83%) rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/src}/handler/upgrade_client.rs (68%) create mode 100644 crates/ibc-core/ics02-client/src/lib.rs create mode 100644 crates/ibc-core/ics02-client/types/Cargo.toml rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/types/src}/error.rs (90%) rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/types/src}/events.rs (98%) rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/types/src}/height.rs (98%) create mode 100644 crates/ibc-core/ics02-client/types/src/lib.rs rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/types/src}/msgs/create_client.rs (88%) rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/types/src}/msgs/misbehaviour.rs (86%) rename crates/{ibc/src/core/ics02_client/msgs.rs => ibc-core/ics02-client/types/src/msgs/mod.rs} (65%) rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/types/src}/msgs/update_client.rs (86%) rename crates/{ibc/src/core/ics02_client => ibc-core/ics02-client/types/src}/msgs/upgrade_client.rs (88%) create mode 100644 crates/ibc-core/ics02-client/types/src/status.rs create mode 100644 crates/ibc-core/ics03-connection/Cargo.toml rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/src}/delay.rs (87%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/src}/handler/conn_open_ack.rs (79%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/src}/handler/conn_open_confirm.rs (77%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/src}/handler/conn_open_init.rs (72%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/src}/handler/conn_open_try.rs (80%) create mode 100644 crates/ibc-core/ics03-connection/src/handler/mod.rs create mode 100644 crates/ibc-core/ics03-connection/src/lib.rs create mode 100644 crates/ibc-core/ics03-connection/types/Cargo.toml rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/types/src}/connection.rs (97%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/types/src}/error.rs (92%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/types/src}/events.rs (98%) create mode 100644 crates/ibc-core/ics03-connection/types/src/lib.rs rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/types/src}/msgs/conn_open_ack.rs (93%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/types/src}/msgs/conn_open_confirm.rs (89%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/types/src}/msgs/conn_open_init.rs (94%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/types/src}/msgs/conn_open_try.rs (96%) rename crates/{ibc/src/core/ics03_connection/msgs.rs => ibc-core/ics03-connection/types/src/msgs/mod.rs} (75%) rename crates/{ibc/src/core/ics03_connection => ibc-core/ics03-connection/types/src}/version.rs (95%) create mode 100644 crates/ibc-core/ics04-channel/Cargo.toml rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/context.rs (67%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/acknowledgement.rs (84%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/chan_close_confirm.rs (81%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/chan_close_init.rs (82%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/chan_open_ack.rs (80%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/chan_open_confirm.rs (81%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/chan_open_init.rs (83%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/chan_open_try.rs (82%) create mode 100644 crates/ibc-core/ics04-channel/src/handler/mod.rs rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/recv_packet.rs (86%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/send_packet.rs (81%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/timeout.rs (87%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/src}/handler/timeout_on_close.rs (86%) create mode 100644 crates/ibc-core/ics04-channel/src/lib.rs create mode 100644 crates/ibc-core/ics04-channel/types/Cargo.toml rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/acknowledgement.rs (99%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/channel.rs (98%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/commitment.rs (95%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/error.rs (94%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/events.rs (99%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/events/channel_attributes.rs (97%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/events/packet_attributes.rs (95%) create mode 100644 crates/ibc-core/ics04-channel/types/src/lib.rs rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/acknowledgement.rs (87%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/chan_close_confirm.rs (92%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/chan_close_init.rs (92%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/chan_open_ack.rs (93%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/chan_open_confirm.rs (92%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/chan_open_init.rs (89%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/chan_open_try.rs (91%) rename crates/{ibc/src/core/ics04_channel/msgs.rs => ibc-core/ics04-channel/types/src/msgs/mod.rs} (66%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/recv_packet.rs (88%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/timeout.rs (90%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/msgs/timeout_on_close.rs (90%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/packet.rs (88%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/timeout.rs (97%) rename crates/{ibc/src/core/ics04_channel => ibc-core/ics04-channel/types/src}/version.rs (98%) create mode 100644 crates/ibc-core/ics23-commitment/types/Cargo.toml rename crates/{ibc/src/core/ics23_commitment => ibc-core/ics23-commitment/types/src}/commitment.rs (96%) rename crates/{ibc/src/core/ics23_commitment => ibc-core/ics23-commitment/types/src}/error.rs (97%) create mode 100644 crates/ibc-core/ics23-commitment/types/src/lib.rs rename crates/{ibc/src/core/ics23_commitment => ibc-core/ics23-commitment/types/src}/merkle.rs (96%) create mode 100644 crates/ibc-core/ics23-commitment/types/src/serializer.rs rename crates/{ibc/src/core/ics23_commitment => ibc-core/ics23-commitment/types/src}/specs.rs (99%) create mode 100644 crates/ibc-core/ics24-host/Cargo.toml rename crates/{ibc/src/core => ibc-core/ics24-host/src}/context.rs (75%) create mode 100644 crates/ibc-core/ics24-host/src/lib.rs create mode 100644 crates/ibc-core/ics24-host/src/utils.rs create mode 100644 crates/ibc-core/ics24-host/tendermint/Cargo.toml create mode 100644 crates/ibc-core/ics24-host/tendermint/src/lib.rs rename crates/{ibc/src/hosts/tendermint => ibc-core/ics24-host/tendermint/src}/upgrade_proposal/context.rs (88%) rename crates/{ibc/src/hosts/tendermint => ibc-core/ics24-host/tendermint/src}/upgrade_proposal/events.rs (98%) rename crates/{ibc/src/hosts/tendermint => ibc-core/ics24-host/tendermint/src}/upgrade_proposal/handler.rs (77%) rename crates/{ibc/src/hosts/tendermint => ibc-core/ics24-host/tendermint/src}/upgrade_proposal/mod.rs (100%) rename crates/{ibc/src/hosts/tendermint => ibc-core/ics24-host/tendermint/src}/upgrade_proposal/plan.rs (94%) rename crates/{ibc/src/hosts/tendermint => ibc-core/ics24-host/tendermint/src}/upgrade_proposal/proposal.rs (96%) rename crates/{ibc/src/hosts/tendermint => ibc-core/ics24-host/tendermint/src}/validate_self_client.rs (72%) create mode 100644 crates/ibc-core/ics24-host/types/Cargo.toml create mode 100644 crates/ibc-core/ics24-host/types/src/error.rs create mode 100644 crates/ibc-core/ics24-host/types/src/identifiers/chain_id.rs create mode 100644 crates/ibc-core/ics24-host/types/src/identifiers/channel_id.rs create mode 100644 crates/ibc-core/ics24-host/types/src/identifiers/client_id.rs rename crates/{ibc/src/core/ics02_client => ibc-core/ics24-host/types/src/identifiers}/client_type.rs (89%) create mode 100644 crates/ibc-core/ics24-host/types/src/identifiers/connection_id.rs create mode 100644 crates/ibc-core/ics24-host/types/src/identifiers/mod.rs create mode 100644 crates/ibc-core/ics24-host/types/src/identifiers/port_id.rs create mode 100644 crates/ibc-core/ics24-host/types/src/identifiers/sequence.rs create mode 100644 crates/ibc-core/ics24-host/types/src/lib.rs rename crates/{ibc/src/core/ics24_host => ibc-core/ics24-host/types/src}/path.rs (97%) rename crates/{ibc/src/core/ics24_host/identifier => ibc-core/ics24-host/types/src}/validate.rs (98%) create mode 100644 crates/ibc-core/ics25-handler/Cargo.toml rename crates/{ibc/src/core/handler.rs => ibc-core/ics25-handler/src/entrypoint.rs} (79%) create mode 100644 crates/ibc-core/ics25-handler/src/lib.rs create mode 100644 crates/ibc-core/ics25-handler/types/Cargo.toml create mode 100644 crates/ibc-core/ics25-handler/types/src/error.rs rename crates/{ibc/src/core => ibc-core/ics25-handler/types/src}/events.rs (76%) create mode 100644 crates/ibc-core/ics25-handler/types/src/lib.rs create mode 100644 crates/ibc-core/ics25-handler/types/src/msgs.rs create mode 100644 crates/ibc-core/ics26-routing/Cargo.toml create mode 100644 crates/ibc-core/ics26-routing/src/lib.rs rename crates/{ibc/src/core/router.rs => ibc-core/ics26-routing/src/module.rs} (58%) create mode 100644 crates/ibc-core/ics26-routing/src/router.rs create mode 100644 crates/ibc-core/ics26-routing/types/Cargo.toml create mode 100644 crates/ibc-core/ics26-routing/types/src/error.rs create mode 100644 crates/ibc-core/ics26-routing/types/src/event.rs create mode 100644 crates/ibc-core/ics26-routing/types/src/lib.rs create mode 100644 crates/ibc-core/ics26-routing/types/src/module.rs create mode 100644 crates/ibc-core/src/lib.rs create mode 100644 crates/ibc-data-types/Cargo.toml create mode 100644 crates/ibc-data-types/README.md create mode 100644 crates/ibc-data-types/src/lib.rs create mode 100644 crates/ibc-primitives/Cargo.toml create mode 100644 crates/ibc-primitives/README.md create mode 100644 crates/ibc-primitives/src/lib.rs rename crates/{ibc => ibc-primitives}/src/prelude.rs (100%) create mode 100644 crates/ibc-primitives/src/traits/mod.rs create mode 100644 crates/ibc-primitives/src/traits/msg.rs create mode 100644 crates/ibc-primitives/src/types/mod.rs rename crates/{ibc/src => ibc-primitives/src/types}/signer.rs (100%) rename crates/{ibc/src/core => ibc-primitives/src/types}/timestamp.rs (98%) rename crates/{ibc => ibc-primitives}/src/utils/macros.rs (86%) create mode 100644 crates/ibc-primitives/src/utils/mod.rs rename crates/{ibc => ibc-primitives}/src/utils/pretty.rs (92%) delete mode 100644 crates/ibc-testkit/src/testapp/ibc/clients/mock/header copy.rs delete mode 100644 crates/ibc/clippy.toml delete mode 100644 crates/ibc/src/clients/ics07_tendermint/mod.rs delete mode 100644 crates/ibc/src/clients/mod.rs delete mode 100644 crates/ibc/src/core/ics02_client/mod.rs delete mode 100644 crates/ibc/src/core/ics03_connection/handler.rs delete mode 100644 crates/ibc/src/core/ics03_connection/mod.rs delete mode 100644 crates/ibc/src/core/ics04_channel/handler.rs delete mode 100644 crates/ibc/src/core/ics04_channel/mod.rs delete mode 100644 crates/ibc/src/core/ics23_commitment/mod.rs delete mode 100644 crates/ibc/src/core/ics24_host/identifier.rs delete mode 100644 crates/ibc/src/core/ics24_host/mod.rs delete mode 100644 crates/ibc/src/core/mod.rs delete mode 100644 crates/ibc/src/core/msgs.rs delete mode 100644 crates/ibc/src/hosts/mod.rs delete mode 100644 crates/ibc/src/hosts/tendermint/mod.rs delete mode 100644 crates/ibc/src/serializers.rs delete mode 100644 crates/ibc/src/utils/mod.rs diff --git a/Cargo.toml b/Cargo.toml index a2ac8e33a..496aa4f68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,12 +2,36 @@ resolver = "2" members = [ "crates/ibc", + "crates/ibc-data-types", + "crates/ibc-primitives", + "crates/ibc-core", + "crates/ibc-clients", "crates/ibc-apps", + "crates/ibc-derive", + "crates/ibc-testkit", + "crates/ibc-query", + "crates/ibc-core/ics02-client", + "crates/ibc-core/ics02-client/types", + "crates/ibc-core/ics03-connection", + "crates/ibc-core/ics03-connection/types", + "crates/ibc-core/ics04-channel", + "crates/ibc-core/ics04-channel/types", + "crates/ibc-core/ics23-commitment/types", + "crates/ibc-core/ics24-host", + "crates/ibc-core/ics24-host/types", + "crates/ibc-core/ics24-host/tendermint", + "crates/ibc-core/ics25-handler", + "crates/ibc-core/ics25-handler/types", + "crates/ibc-core/ics26-routing", + "crates/ibc-core/ics26-routing/types", "crates/ibc-apps/ics20-transfer", "crates/ibc-apps/ics20-transfer/types", + "crates/ibc-clients/ics07-tendermint", + "crates/ibc-clients/ics07-tendermint/types", "crates/ibc-derive", "crates/ibc-testkit", "crates/ibc-query", + "crates/ibc-clients", ] exclude = [ "ci/cw-check", @@ -25,45 +49,69 @@ authors = ["Informal Systems "] [workspace.dependencies] # external dependencies -borsh = {version = "0.10", default-features = false } -bytes = { version = "1.5.0", default-features = false } -displaydoc = { version = "0.2", default-features = false } -derive_more = { version = "0.99.17", default-features = false, features = ["from", "into", "display", "try_into"] } -env_logger = "0.10.0" -num-traits = { version = "0.2.17", default-features = false } -parking_lot = { version = "0.12.1", default-features = false } -primitive-types = { version = "0.12.2", default-features = false, features = ["serde_no_std"] } -prost = { version = "0.12", default-features = false } -rstest = "0.18.2" -schemars = { version = "0.8.15"} -sha2 = { version = "0.10.8", default-features = false } -serde = { version = "1.0", default-features = false } -serde_derive = { version = "1.0", default-features = false } -serde_json = { package = "serde-json-wasm", version = "1.0.0" , default-features = false } -subtle-encoding = { version = "0.5", default-features = false } -test-log = { version = "0.2.13", features = ["trace"] } -time = { version = ">=0.3.0, <0.3.31", default-features = false } -tracing = { version = "0.1.40", default-features = false } -tracing-subscriber = { version = "0.3.17", features = ["fmt", "env-filter", "json"] } -typed-builder = { version = "0.18.0"} +borsh = {version = "0.10", default-features = false } +bytes = { version = "1.5.0", default-features = false } +displaydoc = { version = "0.2", default-features = false } +derive_more = { version = "0.99.17", default-features = false, features = ["from", "into", "display", "try_into"] } +env_logger = "0.10.0" +num-traits = { version = "0.2.17", default-features = false } +parking_lot = { version = "0.12.1", default-features = false } +primitive-types = { version = "0.12.2", default-features = false, features = ["serde_no_std"] } +prost = { version = "0.12", default-features = false } +rstest = "0.18.2" +schemars = { version = "0.8.15" } +sha2 = { version = "0.10.8", default-features = false } +serde = { version = "1.0", default-features = false } +serde_derive = { version = "1.0", default-features = false } +serde_json = { package = "serde-json-wasm", version = "1.0.0" , default-features = false } +subtle-encoding = { version = "0.5", default-features = false } +test-log = { version = "0.2.13", features = ["trace"] } +time = { version = ">=0.3.0, <0.3.31", default-features = false } +tracing = { version = "0.1.40", default-features = false } +tracing-subscriber = { version = "0.3.17", features = ["fmt", "env-filter", "json"] } +typed-builder = { version = "0.18.0" } # ibc dependencies -ibc = { version = "0.47.0", path = "./crates/ibc", default-features = false } -ibc-testkit = { version = "0.47.0", path = "./crates/ibc-testkit", default-features = false} -ibc-app-transfer = { version = "0.47.0", path = "./crates/ibc-apps/ics20-transfer", default-features = false } -ibc-app-transfer-types = { version = "0.47.0", path = "./crates/ibc-apps/ics20-transfer/types", default-features = false } -ibc-derive = { version = "0.3.0", path = "./crates/ibc-derive" } +ibc = { version = "0.47.0", path = "./crates/ibc", default-features = false } +ibc-core = { version = "0.47.0", path = "./crates//ibc-core", default-features = false } +ibc-clients = { version = "0.47.0", path = "./crates/ibc-clients", default-features = false } +ibc-apps = { version = "0.47.0", path = "./crates/ibc-apps", default-features = false } +ibc-primitives = { version = "0.47.0", path = "./crates/ibc-primitives", default-features = false } +ibc-testkit = { version = "0.47.0", path = "./crates/ibc-testkit" } +ibc-derive = { version = "0.3.0", path = "./crates/ibc-derive" } + +ibc-core-client = { version = "0.47.0", path = "./crates/ibc-core/ics02-client", default-features = false } +ibc-core-connection = { version = "0.47.0", path = "./crates/ibc-core/ics03-connection", default-features = false } +ibc-core-channel = { version = "0.47.0", path = "./crates/ibc-core/ics04-channel", default-features = false } +ibc-core-host = { version = "0.47.0", path = "./crates/ibc-core/ics24-host", default-features = false } +ibc-core-handler = { version = "0.47.0", path = "./crates/ibc-core/ics25-handler", default-features = false } +ibc-core-router = { version = "0.47.0", path = "./crates/ibc-core/ics26-routing", default-features = false } +ibc-client-tendermint = { version = "0.47.0", path = "./crates/ibc-clients/ics07-tendermint", default-features = false } +ibc-app-transfer = { version = "0.47.0", path = "./crates/ibc-apps/ics20-transfer", default-features = false } + +ibc-core-client-context = { version = "0.47.0", path = "./crates/ibc-core/ics02-client/context", default-features = false } +ibc-core-client-types = { version = "0.47.0", path = "./crates/ibc-core/ics02-client/types", default-features = false } +ibc-core-channel-types = { version = "0.47.0", path = "./crates/ibc-core/ics04-channel/types", default-features = false } +ibc-core-connection-types = { version = "0.47.0", path = "./crates/ibc-core/ics03-connection/types", default-features = false } +ibc-core-commitment-types = { version = "0.47.0", path = "./crates/ibc-core/ics23-commitment/types", default-features = false } +ibc-core-host-tendermint = { version = "0.47.0", path = "./crates/ibc-core/ics24-host/tendermint", default-features = false } +ibc-core-host-types = { version = "0.47.0", path = "./crates/ibc-core/ics24-host/types", default-features = false } +ibc-core-handler-types = { version = "0.47.0", path = "./crates/ibc-core/ics25-handler/types", default-features = false } +ibc-core-router-types = { version = "0.47.0", path = "./crates/ibc-core/ics26-routing/types", default-features = false } +ibc-client-tendermint-types = { version = "0.47.0", path = "./crates/ibc-clients/ics07-tendermint/types", default-features = false } +ibc-app-transfer-types = { version = "0.47.0", path = "./crates/ibc-apps/ics20-transfer/types", default-features = false } + ibc-proto = { version = "0.38.0", default-features = false } -ics23 = { version = "0.11", default-features = false } +ics23 = { version = "0.11", default-features = false } # cosmos dependencies -tendermint = { version = "0.34.0", default-features = false } -tendermint-light-client = { version = "0.34.0", default-features = false } +tendermint = { version = "0.34.0", default-features = false } +tendermint-light-client = { version = "0.34.0", default-features = false } tendermint-light-client-verifier = { version = "0.34.0", default-features = false } -tendermint-proto = { version = "0.34.0", default-features = false } -tendermint-rpc = { version = "0.34.0", default-features = false } -tendermint-testgen = { version = "0.34.0", default-features = false } +tendermint-proto = { version = "0.34.0", default-features = false } +tendermint-rpc = { version = "0.34.0", default-features = false } +tendermint-testgen = { version = "0.34.0", default-features = false } # parity dependencies parity-scale-codec = { version = "3.6.5", default-features = false, features = ["full"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } diff --git a/README.md b/README.md index 2c5c8a8a5..ad13d5eeb 100644 --- a/README.md +++ b/README.md @@ -23,28 +23,32 @@ -Rust implementation of the Inter-Blockchain Communication (IBC) protocol. This project hosts -the `ibc` rust crate which defines the main data structures and on-chain logic for the IBC protocol. - -## Libraries - -- [ibc](crates/ibc/README.md) - Data structures and on-chain logic for the IBC protocol. -- [ibc-apps](crates/ibc-apps/README.md) - Contains implementations of various IBC applications. -- [ibc-derive](crates/ibc-derive/README.md) - Derive macros for `ClientState` - and `ConsensusState` traits, reducing boilerplate. -- [ibc-testkit](crates/ibc-testkit/README.md) - Testing toolkit to aid `ibc-rs` and host chains in writing integration tests. -- [ibc-query](crates/ibc-query/README.md) - Utility traits and implementations for querying the -state of an `ibc-rs` enabled chain. +Rust implementation of the Inter-Blockchain Communication (IBC) protocol that +hosts all the data structures and on-chain logic implementations of various IBC +core, clients and applications. This repository organized as a collection of +sub-crates that can be used independently or together. + +## Project Structure + +|
Crate
| Description | +| ---------------------------------------- | ----------- | +|[ibc](crates/ibc) | Re-exports all the data structures and on-chain logic of various IBC core, clients and applications. | +|[ibc-data-types](crates/ibc-data-types) | Re-exports all the IBC data types that are shared across different IBC implementations. | +|[ibc-core](crate/ibc) | Contains data structures and implementations of all the IBC core specifications. | +|[ibc-client](crates/ibc-client) | Contains data structures and implementations of various IBC light clients. | +|[ibc-apps](crates/ibc-apps) | Contains data structures and implementations of various IBC applications. | +|[ibc-testkit](crates/ibc-testkit) | Provides testing toolkit to aid `ibc-rs` and host chains in writing integration tests. | +|[ibc-query](crates/ibc-query) | Contains utility traits and implementations for querying states of an integrated IBC module. | +|[ibc-derive](crates/ibc-derive) | Derive macros for `ClientState` and `ConsensusState` traits, reducing boilerplate. | ## Contributing -IBC is specified in English in the [cosmos/ibc repo][ibc]. Any -protocol changes or clarifications should be contributed there. - -This repo contains the Rust implementation for the IBC modules. If you're interested in -contributing, please comment on an issue or open a new one! +IBC is specified in English in the [cosmos/ibc repo][ibc]. Any protocol changes +or clarifications should be contributed there. -See also [CONTRIBUTING.md](./CONTRIBUTING.md). +If you're interested in contributing, please take a look at the +[CONTRIBUTING](./CONTRIBUTING.md) guidelines. We welcome and appreciate +community contributions! ## Community calls @@ -58,26 +62,30 @@ receive a calendar invitation for the monthly meeting. ## Versioning -We follow [Semantic Versioning][semver], though APIs are still -under active development. +We follow [Semantic Versioning][semver], though APIs are still under active +development. ## Resources - [IBC Website][ibc-homepage] - [IBC Specification][ibc] - [IBC Go implementation][ibc-go] +- [Protobuf definitions in Rust][ibc-proto-rs] ## License Copyright © 2022 Informal Systems Inc. and ibc-rs authors. -Licensed under the Apache License, Version 2.0 (the "License"); you may not use the files in this repository except in compliance with the License. You may +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +the files in this repository except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. [//]: # (badges) [docs-image]: https://docs.rs/ibc/badge.svg @@ -95,6 +103,7 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the speci [//]: # (general links) [ibc]: https://github.com/cosmos/ibc [ibc-go]: https://github.com/cosmos/ibc-go +[ibc-proto-rs]: https://github.com/cosmos/ibc-proto-rs [ibc-homepage]: https://cosmos.network/ibc [cosmos-link]: https://cosmos.network [semver]: https://semver.org/ diff --git a/ci/no-std-check/Cargo.lock b/ci/no-std-check/Cargo.lock index 01cf92efa..e902341ed 100644 --- a/ci/no-std-check/Cargo.lock +++ b/ci/no-std-check/Cargo.lock @@ -1216,26 +1216,325 @@ name = "ibc" version = "0.47.0" dependencies = [ "bytes", - "cfg-if", "derive_more", "displaydoc", + "ibc-apps", + "ibc-clients", + "ibc-core", "ibc-derive", + "ibc-primitives", "ibc-proto", - "ics23", - "primitive-types", "prost", "serde", "serde-json-wasm", - "serde_derive", "sha2 0.10.8", "subtle-encoding", "tendermint", "tendermint-light-client-verifier", "tendermint-proto", "time", +] + +[[package]] +name = "ibc-app-transfer" +version = "0.47.0" +dependencies = [ + "ibc-app-transfer-types", + "ibc-core", + "serde-json-wasm", + "sha2 0.10.8", +] + +[[package]] +name = "ibc-app-transfer-types" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core", + "ibc-proto", + "primitive-types", + "serde", "uint", ] +[[package]] +name = "ibc-apps" +version = "0.47.0" +dependencies = [ + "ibc-app-transfer", +] + +[[package]] +name = "ibc-client-tendermint" +version = "0.47.0" +dependencies = [ + "ibc-client-tendermint-types", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost", + "tendermint-light-client-verifier", +] + +[[package]] +name = "ibc-client-tendermint-types" +version = "0.47.0" +dependencies = [ + "bytes", + "displaydoc", + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost", + "tendermint", + "tendermint-light-client-verifier", + "tendermint-proto", +] + +[[package]] +name = "ibc-clients" +version = "0.47.0" +dependencies = [ + "ibc-client-tendermint", +] + +[[package]] +name = "ibc-core" +version = "0.47.0" +dependencies = [ + "ibc-core-channel", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", +] + +[[package]] +name = "ibc-core-channel" +version = "0.47.0" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", + "prost", +] + +[[package]] +name = "ibc-core-channel-types" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost", + "serde", + "sha2 0.10.8", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-client" +version = "0.47.0" +dependencies = [ + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-derive", + "ibc-primitives", + "prost", +] + +[[package]] +name = "ibc-core-client-context" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-derive", + "ibc-primitives", + "prost", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-client-types" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost", + "serde", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-commitment-types" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-primitives", + "ibc-proto", + "ics23", + "prost", + "serde", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-connection" +version = "0.47.0" +dependencies = [ + "ibc-core-client", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost", +] + +[[package]] +name = "ibc-core-connection-types" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost", + "serde", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-handler" +version = "0.47.0" +dependencies = [ + "ibc-core-channel", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", +] + +[[package]] +name = "ibc-core-handler-types" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-host-types", + "ibc-core-router-types", + "ibc-primitives", + "ibc-proto", + "prost", + "serde", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-host" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-primitives", + "prost", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-host-types" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-primitives", + "serde", +] + +[[package]] +name = "ibc-core-router" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router-types", + "ibc-primitives", + "prost", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-router-types" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "ics23", + "prost", + "serde", + "subtle-encoding", + "tendermint", +] + [[package]] name = "ibc-derive" version = "0.3.0" @@ -1246,6 +1545,19 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "ibc-primitives" +version = "0.47.0" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-proto", + "prost", + "serde", + "tendermint", + "time", +] + [[package]] name = "ibc-proto" version = "0.38.0" diff --git a/crates/ibc-apps/Cargo.toml b/crates/ibc-apps/Cargo.toml index f0c4420cf..9057c5e7f 100644 --- a/crates/ibc-apps/Cargo.toml +++ b/crates/ibc-apps/Cargo.toml @@ -6,11 +6,11 @@ edition = { workspace = true } rust-version = { workspace = true } license = { workspace = true } repository = { workspace = true } -keywords = ["blockchain", "cosmos", "ibc", "applications"] +keywords = ["blockchain", "cosmos", "ibc", "applications", "token-transfer"] readme = "README.md" description = """ - `ibc-apps` provides a comprehensive set of libraries for IBC applications, - facilitating seamless integration of IBC business logic into any blockchain system. + Maintained by `ibc-rs`, re-exports a comprehensive set of libraries that implement various + IBC applications, enabling smooth integration of IBC business logic into any blockchain system. """ [package.metadata.docs.rs] @@ -35,3 +35,6 @@ schema = [ borsh = [ "ibc-app-transfer/borsh", ] +parity-scale-codec = [ + "ibc-app-transfer/parity-scale-codec", +] diff --git a/crates/ibc-apps/README.md b/crates/ibc-apps/README.md index d74d4ad46..c3fd7f090 100644 --- a/crates/ibc-apps/README.md +++ b/crates/ibc-apps/README.md @@ -1,48 +1,37 @@ -# `ibc-apps` +# IBC Applications -This crate is a top-level library that re-exports Inter-Blockchain -Communication (IBC) applications implemented in Rust. It serves as a centralized hub, -simplifying the process of importing and integrating various IBC applications -into your blockchain. IBC is a distributed protocol that enables communication -between distinct sovereign blockchains. IBC applications abstract away the core -transport and authentication layers, letter blockchain app developers -focus solely on business logic implementation. +This crate is a top-level library that re-exports Inter-Blockchain Communication +(IBC) applications implemented. It serves as a meta-crate, simplifying the +process of importing and integrating various IBC applications into your +blockchain. IBC is a distributed protocol that enables communication between +distinct sovereign blockchains. IBC applications abstract away the core +transport, authentication and ordering (TAO) layers, letter blockchain app +developers focus solely on business logic implementation. The structure within the `ibc-apps` crate is designed to provide flexibility for external users. It allows users to either utilize the entire `ibc-apps` crate, -or selectively import specific sub-crates, whether you need a certain IBC -application (e.g. `ibc-app-transfer` crate) or only their associated data +or selectively import specific sub-crates, whether they need a certain IBC +application (e.g. `ibc-app-transfer` crate) or only its associated data structures (e.g. `ibc-app-transfer-types`). This versatility empowers hosts, including chain integrators, relayers, or any IBC tooling projects, to build their solutions on top of the layers that best suit their requirements. -## Libraries +## Sub-Crates -Currently, the `ibc-apps` crate contains the implementation of the following IBC +The `ibc-apps` crate contains the implementation of the following IBC applications: ### ICS-20: Fungible Token Transfer Application -- [ibc-app-transfer](crates/ibc-apps/ics20-transfer) -- [ibc-app-transfer-types](crates/ibc-apps/ics20-transfer/types) +- [ibc-app-transfer](./../ibc-apps/ics20-transfer) +- [ibc-app-transfer-types](./../ibc-apps/ics20-transfer/types) ## Contributing -IBC is specified in English in the [cosmos/ibc repo][ibc]. Any -protocol changes or clarifications should be contributed there. +IBC is specified in English in the [cosmos/ibc +repo](https://github.com/cosmos/ibc). Any protocol changes or clarifications +should be contributed there. -If you're interested in contributing, please comment on an issue or open a new -one! - -See also [CONTRIBUTING.md](./../../CONTRIBUTING.md). - -## Resources - -- [IBC Website][ibc-homepage] -- [IBC Specification][ibc] -- [IBC Go implementation][ibc-go] - -[//]: # (general links) -[ibc]: https://github.com/cosmos/ibc -[ibc-go]: https://github.com/cosmos/ibc-go -[ibc-homepage]: https://cosmos.network/ibc +If you're interested in contributing, please take a look at the +[CONTRIBUTING](./../../CONTRIBUTING.md) guidelines. We welcome and appreciate +community contributions! diff --git a/crates/ibc-apps/ics20-transfer/Cargo.toml b/crates/ibc-apps/ics20-transfer/Cargo.toml index 821e3381b..67bb81f35 100644 --- a/crates/ibc-apps/ics20-transfer/Cargo.toml +++ b/crates/ibc-apps/ics20-transfer/Cargo.toml @@ -9,8 +9,9 @@ repository = { workspace = true } keywords = ["blockchain", "cosmos", "ibc", "transfer", "ics20"] readme = "./../README.md" description = """ - Contains the core implementation of the ICS-20 token transfer application logic - along with re-exporting the data structures from `ibc-app-transfer-types` crate. + Maintained by `ibc-rs`, contains the implementation of the ICS-20 Fungible Token Transfer + application logic and re-exports essential data structures and domain types from + `ibc-app-transfer-types` crate. """ [package.metadata.docs.rs] @@ -22,7 +23,7 @@ serde_json = { workspace = true, optional = true } sha2 = { workspace = true } # ibc dependencies -ibc = { workspace = true } +ibc-core = { workspace = true } ibc-app-transfer-types = { workspace = true } [dev-dependencies] @@ -32,26 +33,26 @@ subtle-encoding = { workspace = true } default = ["std"] std = [ "ibc-app-transfer-types/std", - "ibc/std", + "ibc-core/std", "serde_json/std", "sha2/std", ] serde = [ "ibc-app-transfer-types/serde", - "ibc/serde", + "ibc-core/serde", "serde_json" ] schema = [ "ibc-app-transfer-types/schema", - "ibc/schema", + "ibc-core/schema", "serde", "std", ] borsh = [ "ibc-app-transfer-types/borsh", - "ibc/borsh", + "ibc-core/borsh", ] parity-scale-codec = [ "ibc-app-transfer-types/parity-scale-codec", - "ibc/parity-scale-codec", + "ibc-core/parity-scale-codec", ] diff --git a/crates/ibc-apps/ics20-transfer/src/context.rs b/crates/ibc-apps/ics20-transfer/src/context.rs index 80899b12b..62bd07e1d 100644 --- a/crates/ibc-apps/ics20-transfer/src/context.rs +++ b/crates/ibc-apps/ics20-transfer/src/context.rs @@ -1,10 +1,10 @@ //! Defines the main context traits and IBC module callbacks -use ibc::core::ics24_host::identifier::{ChannelId, PortId}; -use ibc::prelude::*; -use ibc::Signer; use ibc_app_transfer_types::error::TokenTransferError; use ibc_app_transfer_types::{PrefixedCoin, PrefixedDenom, VERSION}; +use ibc_core::host::types::identifiers::{ChannelId, PortId}; +use ibc_core::primitives::prelude::*; +use ibc_core::primitives::Signer; use sha2::{Digest, Sha256}; /// Methods required in token transfer validation, to be implemented by the host diff --git a/crates/ibc-apps/ics20-transfer/src/handler/mod.rs b/crates/ibc-apps/ics20-transfer/src/handler/mod.rs index 730017f6d..967df3918 100644 --- a/crates/ibc-apps/ics20-transfer/src/handler/mod.rs +++ b/crates/ibc-apps/ics20-transfer/src/handler/mod.rs @@ -2,11 +2,10 @@ pub mod on_recv_packet; pub mod send_transfer; -use ibc::core::ics04_channel::packet::Packet; -use ibc::prelude::*; use ibc_app_transfer_types::error::TokenTransferError; use ibc_app_transfer_types::is_sender_chain_source; use ibc_app_transfer_types::packet::PacketData; +use ibc_core::channel::types::packet::Packet; use crate::context::{TokenTransferExecutionContext, TokenTransferValidationContext}; diff --git a/crates/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs b/crates/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs index d150d8399..2baa187f6 100644 --- a/crates/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs +++ b/crates/ibc-apps/ics20-transfer/src/handler/on_recv_packet.rs @@ -1,10 +1,10 @@ -use ibc::core::ics04_channel::packet::Packet; -use ibc::core::router::ModuleExtras; -use ibc::prelude::*; use ibc_app_transfer_types::error::TokenTransferError; use ibc_app_transfer_types::events::DenomTraceEvent; use ibc_app_transfer_types::packet::PacketData; use ibc_app_transfer_types::{is_receiver_chain_source, TracePrefix}; +use ibc_core::channel::types::packet::Packet; +use ibc_core::primitives::prelude::*; +use ibc_core::router::types::module::ModuleExtras; use crate::context::TokenTransferExecutionContext; diff --git a/crates/ibc-apps/ics20-transfer/src/handler/send_transfer.rs b/crates/ibc-apps/ics20-transfer/src/handler/send_transfer.rs index 9fe2662b5..683b96edf 100644 --- a/crates/ibc-apps/ics20-transfer/src/handler/send_transfer.rs +++ b/crates/ibc-apps/ics20-transfer/src/handler/send_transfer.rs @@ -1,13 +1,14 @@ -use ibc::core::events::{MessageEvent, ModuleEvent}; -use ibc::core::ics04_channel::context::{SendPacketExecutionContext, SendPacketValidationContext}; -use ibc::core::ics04_channel::handler::send_packet::{send_packet_execute, send_packet_validate}; -use ibc::core::ics04_channel::packet::Packet; -use ibc::core::ics24_host::path::{ChannelEndPath, SeqSendPath}; -use ibc::prelude::*; use ibc_app_transfer_types::error::TokenTransferError; use ibc_app_transfer_types::events::TransferEvent; use ibc_app_transfer_types::msgs::transfer::MsgTransfer; use ibc_app_transfer_types::{is_sender_chain_source, MODULE_ID_STR}; +use ibc_core::channel::context::{SendPacketExecutionContext, SendPacketValidationContext}; +use ibc_core::channel::handler::{send_packet_execute, send_packet_validate}; +use ibc_core::channel::types::packet::Packet; +use ibc_core::handler::types::events::MessageEvent; +use ibc_core::host::types::path::{ChannelEndPath, SeqSendPath}; +use ibc_core::primitives::prelude::*; +use ibc_core::router::types::event::ModuleEvent; use crate::context::{TokenTransferExecutionContext, TokenTransferValidationContext}; diff --git a/crates/ibc-apps/ics20-transfer/src/module.rs b/crates/ibc-apps/ics20-transfer/src/module.rs index 1c86d139e..a33b67bc3 100644 --- a/crates/ibc-apps/ics20-transfer/src/module.rs +++ b/crates/ibc-apps/ics20-transfer/src/module.rs @@ -1,16 +1,16 @@ -use ibc::core::ics04_channel::acknowledgement::{Acknowledgement, AcknowledgementStatus}; -use ibc::core::ics04_channel::channel::{Counterparty, Order}; -use ibc::core::ics04_channel::packet::Packet; -use ibc::core::ics04_channel::Version; -use ibc::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use ibc::core::router::ModuleExtras; -use ibc::core::ContextError; -use ibc::prelude::*; -use ibc::Signer; use ibc_app_transfer_types::error::TokenTransferError; use ibc_app_transfer_types::events::{AckEvent, AckStatusEvent, RecvEvent, TimeoutEvent}; use ibc_app_transfer_types::packet::PacketData; use ibc_app_transfer_types::{ack_success_b64, VERSION}; +use ibc_core::channel::types::acknowledgement::{Acknowledgement, AcknowledgementStatus}; +use ibc_core::channel::types::channel::{Counterparty, Order}; +use ibc_core::channel::types::packet::Packet; +use ibc_core::channel::types::Version; +use ibc_core::handler::types::error::ContextError; +use ibc_core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; +use ibc_core::primitives::prelude::*; +use ibc_core::primitives::Signer; +use ibc_core::router::types::module::ModuleExtras; use crate::context::{TokenTransferExecutionContext, TokenTransferValidationContext}; use crate::handler::on_recv_packet::process_recv_packet_execute; diff --git a/crates/ibc-apps/ics20-transfer/types/Cargo.toml b/crates/ibc-apps/ics20-transfer/types/Cargo.toml index 495a77de5..84a0c63c8 100644 --- a/crates/ibc-apps/ics20-transfer/types/Cargo.toml +++ b/crates/ibc-apps/ics20-transfer/types/Cargo.toml @@ -9,8 +9,9 @@ repository = { workspace = true } keywords = ["blockchain", "cosmos", "ibc", "transfer", "ics20"] readme = "./../../README.md" description = """ - Contains the universal data structures of the ICS-20 fungible token transfer application - that can be used across various IBC implementations + Maintained by `ibc-rs`, encapsulates essential ICS-20 Fungible Token Transfer data structures and + domain types, as specified in the Inter-Blockchain Communication (IBC) protocol. Designed for universal + applicability to facilitate development and integration across diverse IBC-enabled projects. """ [package.metadata.docs.rs] @@ -18,38 +19,40 @@ all-features = true [dependencies] # external dependencies -borsh = { workspace = true, optional = true } -derive_more = { workspace = true } -displaydoc = { workspace = true } +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } primitive-types = { workspace = true } -schemars = { workspace = true, optional = true } -serde = { workspace = true, optional = true } -serde_json = { workspace = true, optional = true} -uint = { version = "0.9", default-features = false } +schemars = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +uint = { version = "0.9", default-features = false } # ibc dependencies -ibc = { workspace = true } +ibc-core = { workspace = true } ibc-proto = { workspace = true } ## parity dependencies parity-scale-codec = { workspace = true , optional = true } -scale-info = { workspace = true , optional = true } +scale-info = { workspace = true , optional = true } [dev-dependencies] ibc-testkit = { workspace = true } -rstest = { workspace = true } +serde_json = { workspace = true } +rstest = { workspace = true } [features] default = ["std"] std = [ - "ibc-proto/std", "serde/std", "serde_json/std", "displaydoc/std", "uint/std", "primitive-types/std", + "ibc-core/std", + "ibc-proto/std", + "ibc-testkit/std", ] -borsh = ["dep:borsh", "ibc/borsh", "ibc-proto/borsh"] -serde = ["dep:serde", "serde_json", "ibc/serde", "ibc-proto/serde"] -schema = ["dep:schemars", "ibc/schema", "ibc-proto/json-schema", "serde", "std"] -parity-scale-codec = ["dep:parity-scale-codec", "dep:scale-info", "ibc/parity-scale-codec", "ibc-proto/parity-scale-codec"] \ No newline at end of file +serde = ["dep:serde", "ibc-core/serde", "ibc-proto/serde", "ibc-testkit/serde"] +borsh = ["dep:borsh", "ibc-core/borsh", "ibc-proto/borsh"] +schema = ["dep:schemars", "ibc-core/schema", "ibc-proto/json-schema", "serde", "std"] +parity-scale-codec = ["dep:parity-scale-codec", "dep:scale-info", "ibc-core/parity-scale-codec", "ibc-proto/parity-scale-codec"] diff --git a/crates/ibc-apps/ics20-transfer/types/src/amount.rs b/crates/ibc-apps/ics20-transfer/types/src/amount.rs index cc793200b..5c3802d2d 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/amount.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/amount.rs @@ -3,7 +3,7 @@ use core::ops::Deref; use core::str::FromStr; use derive_more::{Display, From, Into}; -use ibc::prelude::*; +use ibc_core::primitives::prelude::*; use primitive_types::U256; use super::error::TokenTransferError; diff --git a/crates/ibc-apps/ics20-transfer/types/src/coin.rs b/crates/ibc-apps/ics20-transfer/types/src/coin.rs index 70f3d832b..65a147218 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/coin.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/coin.rs @@ -2,7 +2,7 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; -use ibc::prelude::*; +use ibc_core::primitives::prelude::*; use ibc_proto::cosmos::base::v1beta1::Coin as ProtoCoin; use super::amount::Amount; diff --git a/crates/ibc-apps/ics20-transfer/types/src/denom.rs b/crates/ibc-apps/ics20-transfer/types/src/denom.rs index 42847ceba..92f60c9d3 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/denom.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/denom.rs @@ -3,8 +3,8 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; use derive_more::{Display, From}; -use ibc::core::ics24_host::identifier::{ChannelId, PortId}; -use ibc::prelude::*; +use ibc_core::host::types::identifiers::{ChannelId, PortId}; +use ibc_core::primitives::prelude::*; use ibc_proto::ibc::applications::transfer::v1::DenomTrace as RawDenomTrace; use super::error::TokenTransferError; diff --git a/crates/ibc-apps/ics20-transfer/types/src/error.rs b/crates/ibc-apps/ics20-transfer/types/src/error.rs index 8372f8aa5..8737ddf96 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/error.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/error.rs @@ -3,11 +3,12 @@ use core::convert::Infallible; use core::str::Utf8Error; use displaydoc::Display; -use ibc::core::ics04_channel::acknowledgement::StatusValue; -use ibc::core::ics04_channel::channel::Order; -use ibc::core::ics24_host::identifier::{ChannelId, IdentifierError, PortId}; -use ibc::core::ContextError; -use ibc::prelude::*; +use ibc_core::channel::types::acknowledgement::StatusValue; +use ibc_core::channel::types::channel::Order; +use ibc_core::handler::types::error::ContextError; +use ibc_core::host::types::error::IdentifierError; +use ibc_core::host::types::identifiers::{ChannelId, PortId}; +use ibc_core::primitives::prelude::*; use uint::FromDecStrErr; #[derive(Display, Debug)] diff --git a/crates/ibc-apps/ics20-transfer/types/src/events.rs b/crates/ibc-apps/ics20-transfer/types/src/events.rs index bee96cf72..565e14430 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/events.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/events.rs @@ -1,8 +1,8 @@ //! Defines all token transfer event types -use ibc::core::events::ModuleEvent; -use ibc::core::ics04_channel::acknowledgement::AcknowledgementStatus; -use ibc::prelude::*; -use ibc::Signer; +use ibc_core::channel::types::acknowledgement::AcknowledgementStatus; +use ibc_core::primitives::prelude::*; +use ibc_core::primitives::Signer; +use ibc_core::router::types::event::ModuleEvent; use super::Memo; use crate::{Amount, PrefixedDenom, MODULE_ID_STR}; @@ -22,7 +22,7 @@ pub enum Event { Transfer(TransferEvent), } -/// Event emitted in the `onRecvPacket` module callback to indicate that the +/// Event emitted by the `onRecvPacket` module callback to indicate the that the /// `RecvPacket` message was processed pub struct RecvEvent { pub sender: Signer, @@ -58,7 +58,7 @@ impl From for ModuleEvent { } } -/// Event emitted by the `onAcknowledgePacket` module callback +/// Event emitted in the `onAcknowledgePacket` module callback pub struct AckEvent { pub sender: Signer, pub receiver: Signer, @@ -93,7 +93,7 @@ impl From for ModuleEvent { } } -/// Event emitted by the `onAcknowledgePacket` module callback to indicate +/// Event emitted in the `onAcknowledgePacket` module callback to indicate /// whether the acknowledgement is a success or a failure pub struct AckStatusEvent { pub acknowledgement: AcknowledgementStatus, @@ -114,7 +114,7 @@ impl From for ModuleEvent { } } -/// Event emitted by the `onTimeoutPacket` module callback +/// Event emitted in the `onTimeoutPacket` module callback pub struct TimeoutEvent { pub refund_receiver: Signer, pub refund_denom: PrefixedDenom, @@ -143,7 +143,7 @@ impl From for ModuleEvent { } } -/// Event emitted by the `onRecvPacket` module callback when new tokens are minted +/// Event emitted in the `onRecvPacket` module callback when new tokens are minted pub struct DenomTraceEvent { pub trace_hash: Option, pub denom: PrefixedDenom, diff --git a/crates/ibc-apps/ics20-transfer/types/src/lib.rs b/crates/ibc-apps/ics20-transfer/types/src/lib.rs index 723a146d3..2cc84f2fe 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/lib.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/lib.rs @@ -41,7 +41,7 @@ pub mod error; mod memo; pub use memo::*; -/// Re-exports ICS-20 token transfer proto types from the `ibc-proto-rs` crate +/// Re-exports ICS-20 token transfer proto types from the `ibc-proto` crate /// for added convenience pub mod proto { pub use ibc_proto::ibc::apps::transfer; @@ -61,7 +61,7 @@ pub const VERSION: &str = "ics20-1"; /// equivalent to `base64::encode(0x01)`. pub const ACK_SUCCESS_B64: &str = "AQ=="; -use ibc::core::ics04_channel::acknowledgement::StatusValue; +use ibc_core::channel::types::acknowledgement::StatusValue; /// Returns a successful acknowledgement status for the token transfer application. pub fn ack_success_b64() -> StatusValue { diff --git a/crates/ibc-apps/ics20-transfer/types/src/memo.rs b/crates/ibc-apps/ics20-transfer/types/src/memo.rs index de7368fa6..9a3caea74 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/memo.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/memo.rs @@ -7,7 +7,7 @@ use core::fmt::{ }; use core::str::FromStr; -use ibc::prelude::*; +use ibc_core::primitives::prelude::*; /// Represents the token transfer memo #[cfg_attr( diff --git a/crates/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs b/crates/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs index eb061d9a2..b892f9f40 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/msgs/transfer.rs @@ -1,10 +1,11 @@ //! Defines the token transfer message type -use ibc::core::ics04_channel::error::PacketError; -use ibc::core::ics04_channel::timeout::TimeoutHeight; -use ibc::core::ics24_host::identifier::{ChannelId, PortId}; -use ibc::core::timestamp::Timestamp; -use ibc::core::{ContextError, Msg}; -use ibc::prelude::*; + +use ibc_core::channel::types::error::PacketError; +use ibc_core::channel::types::timeout::TimeoutHeight; +use ibc_core::handler::types::error::ContextError; +use ibc_core::host::types::identifiers::{ChannelId, PortId}; +use ibc_core::primitives::prelude::*; +use ibc_core::primitives::{Msg, Timestamp}; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::applications::transfer::v1::MsgTransfer as RawMsgTransfer; use ibc_proto::Protobuf; diff --git a/crates/ibc-apps/ics20-transfer/types/src/packet.rs b/crates/ibc-apps/ics20-transfer/types/src/packet.rs index bb556af34..d9d1ace76 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/packet.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/packet.rs @@ -3,8 +3,8 @@ use core::convert::TryFrom; use core::str::FromStr; -use ibc::prelude::*; -use ibc::Signer; +use ibc_core::primitives::prelude::*; +use ibc_core::primitives::Signer; use ibc_proto::ibc::applications::transfer::v2::FungibleTokenPacketData as RawPacketData; use super::error::TokenTransferError; diff --git a/crates/ibc-apps/ics20-transfer/types/src/serializers.rs b/crates/ibc-apps/ics20-transfer/types/src/serializers.rs index 57f6e20d3..65c4d2ba6 100644 --- a/crates/ibc-apps/ics20-transfer/types/src/serializers.rs +++ b/crates/ibc-apps/ics20-transfer/types/src/serializers.rs @@ -1,7 +1,7 @@ use core::fmt::Display; use core::str::FromStr; -use ibc::prelude::*; +use ibc_core::primitives::prelude::*; use serde::{de, Deserialize, Deserializer, Serializer}; // Note: This method serializes to a String instead of a str diff --git a/crates/ibc-clients/Cargo.toml b/crates/ibc-clients/Cargo.toml new file mode 100644 index 000000000..c2bf8b81e --- /dev/null +++ b/crates/ibc-clients/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ibc-clients" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "applications", "tendermint"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, re-exports a comprehensive set of libraries that implement + various IBC light clients, enabling smooth integration with IBC-enabled blockchains. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +ibc-client-tendermint = { workspace = true } + +[features] +default = ["std"] +std = [ + "ibc-client-tendermint/std", +] +serde = [ + "ibc-client-tendermint/serde", +] diff --git a/crates/ibc-clients/README.md b/crates/ibc-clients/README.md new file mode 100644 index 000000000..18c35fc7d --- /dev/null +++ b/crates/ibc-clients/README.md @@ -0,0 +1,46 @@ +# IBC Clients + +This crate is top-level library re-exports implemented Inter-Blockchain +Communication (IBC) light clients serves as a meta-crate, simplifying the +process of importing and integrating various IBC clients into your blockchain. +IBC is a distributed protocol that enables communication between distinct +sovereign blockchains and IBC light clients track the consensus states and proof +specs of external blockchains required to properly verify proofs against the +client's consensus state. + +The structure within the `ibc-clients` crate is designed to provide flexibility +for external users. It allows you to utilize the own `ibc-clients` crate or +selectively import specific libraries, whether you need a certain IBC client +implementation (e.g. `ibc-client-tendermint` crate) or only its associated data +structures (e.g. `ibc-core-tendermint-types`). This versatility empowers hosts, +including chain integrators, relayers, or any IBC tooling projects, to build +their solutions on top of the layers that best suit their requirements. + +## Sub-Crates + +Currently, the `ibc-clients` crate contains the implementation of the following +IBC light clients: + +### ICS-07: Tendermint Light Client + +- [ibc-client-tendermint](../ibc-client-tendermint) +- [ibc-client-tendermint-types](../ibc-client-tendermint-types) + +## Third-party Clients + +Here, we list IBC third-party clients that are compatible with `ibc-rs`. You +should always audit the implementation of any third-party crate. If you have a +client that you'd like to be added to this list, please open a PR! + +- [ICS 6: Solomachine](https://github.com/octopus-network/ics06-solomachine) by + Octopus Network + +## Contributing + +IBC is specified in English in the [cosmos/ibc +repo](https://github.com/cosmos/ibc). Any protocol changes or clarifications +should be contributed there. + +If you're interested in contributing, please take a look at the +[CONTRIBUTING](./../../CONTRIBUTING.md) guidelines. We welcome and appreciate +community contributions! diff --git a/crates/ibc-clients/ics07-tendermint/Cargo.toml b/crates/ibc-clients/ics07-tendermint/Cargo.toml new file mode 100644 index 000000000..f13d4e078 --- /dev/null +++ b/crates/ibc-clients/ics07-tendermint/Cargo.toml @@ -0,0 +1,78 @@ +[package] +name = "ibc-client-tendermint" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +readme = "./../README.md" +keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] +description = """ + Maintained by `ibc-rs`, contains the implementation of the ICS-07 Tendermint Client logic + and re-exports essential data structures and domain types from `ibc-client-tendermint-types` crate. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +prost = { workspace = true } +serde = { workspace = true, optional = true } + +# ibc dependencies +ibc-client-tendermint-types = { workspace = true } +ibc-core-client = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-primitives = { workspace = true } + +# cosmos dependencies +tendermint-light-client-verifier = { workspace = true, features = ["rust-crypto"] } + +[features] +default = ["std"] +std = [ + "prost/std", + "ibc-client-tendermint-types/std", + "ibc-core-client/std", + "ibc-core-commitment-types/std", + "ibc-core-host/std", + "ibc-core-handler-types/std", + "ibc-primitives/std", +] +serde = [ + "dep:serde", + "ibc-client-tendermint-types/serde", + "ibc-core-client/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host/serde", + "ibc-core-handler-types/serde", + "ibc-primitives/serde", +] +schema = [ + "ibc-client-tendermint-types/schema", + "ibc-core-client/schema", + "ibc-core-commitment-types/schema", + "ibc-core-host/schema", + "ibc-core-handler-types/schema", + "ibc-primitives/schema", +] +borsh = [ + "ibc-client-tendermint-types/borsh", + "ibc-core-client/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host/borsh", + "ibc-core-handler-types/borsh", + "ibc-primitives/borsh", +] +parity-scale-codec = [ + "ibc-client-tendermint-types/parity-scale-codec", + "ibc-core-client/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] \ No newline at end of file diff --git a/crates/ibc-clients/ics07-tendermint/src/client_state.rs b/crates/ibc-clients/ics07-tendermint/src/client_state.rs new file mode 100644 index 000000000..4d3e3dce9 --- /dev/null +++ b/crates/ibc-clients/ics07-tendermint/src/client_state.rs @@ -0,0 +1,571 @@ +use ibc_client_tendermint_types::error::Error; +use ibc_client_tendermint_types::proto::v1::ClientState as RawTmClientState; +use ibc_client_tendermint_types::proto::{Any, Protobuf}; +use ibc_client_tendermint_types::{ + client_type as tm_client_type, ClientState as TmClientState, + ConsensusState as TmConsensusState, Header as TmHeader, Misbehaviour as TmMisbehaviour, +}; +use ibc_core_client::context::client_state::{ + ClientStateCommon, ClientStateExecution, ClientStateValidation, +}; +use ibc_core_client::context::{ClientExecutionContext, ClientValidationContext}; +use ibc_core_client::types::error::{ClientError, UpgradeClientError}; +use ibc_core_client::types::{Height, Status, UpdateKind}; +use ibc_core_commitment_types::commitment::{ + CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, +}; +use ibc_core_commitment_types::merkle::{apply_prefix, MerkleProof}; +use ibc_core_commitment_types::proto::v1::MerkleProof as RawMerkleProof; +use ibc_core_host::types::identifiers::{ClientId, ClientType}; +use ibc_core_host::types::path::{ + ClientConsensusStatePath, ClientStatePath, Path, UpgradeClientPath, +}; +use ibc_core_host::ExecutionContext; +use ibc_primitives::prelude::*; +use prost::Message; + +use crate::context::{ + CommonContext, ExecutionContext as TmExecutionContext, ValidationContext as TmValidationContext, +}; + +mod misbehaviour; +mod update_client; + +/// Newtype wrapper around the `ClientState` type imported from the `ibc-client-tendermint-types` +/// crate. This wrapper exists so that we can bypass Rust's orphan rules and implement traits +/// from `ibc::core::client::context` on the `ClientState` type. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, PartialEq)] +pub struct ClientStateWrapper(TmClientState); + +impl ClientStateWrapper { + pub fn inner(&self) -> &TmClientState { + &self.0 + } +} + +impl From for ClientStateWrapper { + fn from(client_state: TmClientState) -> Self { + Self(client_state) + } +} + +impl Protobuf for ClientStateWrapper {} + +impl TryFrom for ClientStateWrapper { + type Error = Error; + + fn try_from(raw: RawTmClientState) -> Result { + Ok(Self(TmClientState::try_from(raw)?)) + } +} + +impl From for RawTmClientState { + fn from(client_state: ClientStateWrapper) -> Self { + client_state.0.into() + } +} + +impl Protobuf for ClientStateWrapper {} + +impl TryFrom for ClientStateWrapper { + type Error = ClientError; + + fn try_from(raw: Any) -> Result { + Ok(Self(TmClientState::try_from(raw)?)) + } +} + +impl From for Any { + fn from(client_state: ClientStateWrapper) -> Self { + client_state.0.into() + } +} + +impl ClientStateCommon for ClientStateWrapper { + fn verify_consensus_state(&self, consensus_state: Any) -> Result<(), ClientError> { + let tm_consensus_state = TmConsensusState::try_from(consensus_state)?; + if tm_consensus_state.root().is_empty() { + return Err(ClientError::Other { + description: "empty commitment root".into(), + }); + }; + + Ok(()) + } + + fn client_type(&self) -> ClientType { + tm_client_type() + } + + fn latest_height(&self) -> Height { + self.0.latest_height + } + + fn validate_proof_height(&self, proof_height: Height) -> Result<(), ClientError> { + if self.latest_height() < proof_height { + return Err(ClientError::InvalidProofHeight { + latest_height: self.latest_height(), + proof_height, + }); + } + Ok(()) + } + + /// Perform client-specific verifications and check all data in the new + /// client state to be the same across all valid Tendermint clients for the + /// new chain. + /// + /// You can learn more about how to upgrade IBC-connected SDK chains in + /// [this](https://ibc.cosmos.network/main/ibc/upgrades/quick-guide.html) + /// guide + fn verify_upgrade_client( + &self, + upgraded_client_state: Any, + upgraded_consensus_state: Any, + proof_upgrade_client: CommitmentProofBytes, + proof_upgrade_consensus_state: CommitmentProofBytes, + root: &CommitmentRoot, + ) -> Result<(), ClientError> { + // Make sure that the client type is of Tendermint type `ClientState` + let upgraded_tm_client_state = Self::try_from(upgraded_client_state.clone())?; + + // Make sure that the consensus type is of Tendermint type `ConsensusState` + TmConsensusState::try_from(upgraded_consensus_state.clone())?; + + // Make sure the latest height of the current client is not greater then + // the upgrade height This condition checks both the revision number and + // the height + if self.latest_height() >= upgraded_tm_client_state.0.latest_height { + return Err(UpgradeClientError::LowUpgradeHeight { + upgraded_height: self.latest_height(), + client_height: upgraded_tm_client_state.0.latest_height, + })?; + } + + // Check to see if the upgrade path is set + let mut upgrade_path = self.0.upgrade_path.clone(); + if upgrade_path.pop().is_none() { + return Err(ClientError::ClientSpecific { + description: "cannot upgrade client as no upgrade path has been set".to_string(), + }); + }; + + let upgrade_path_prefix = CommitmentPrefix::try_from(upgrade_path[0].clone().into_bytes()) + .map_err(ClientError::InvalidCommitmentProof)?; + + let last_height = self.latest_height().revision_height(); + + let mut client_state_value = Vec::new(); + upgraded_client_state + .encode(&mut client_state_value) + .map_err(ClientError::Encode)?; + + // Verify the proof of the upgraded client state + self.verify_membership( + &upgrade_path_prefix, + &proof_upgrade_client, + root, + Path::UpgradeClient(UpgradeClientPath::UpgradedClientState(last_height)), + client_state_value, + )?; + + let mut cons_state_value = Vec::new(); + upgraded_consensus_state + .encode(&mut cons_state_value) + .map_err(ClientError::Encode)?; + + // Verify the proof of the upgraded consensus state + self.verify_membership( + &upgrade_path_prefix, + &proof_upgrade_consensus_state, + root, + Path::UpgradeClient(UpgradeClientPath::UpgradedClientConsensusState(last_height)), + cons_state_value, + )?; + + Ok(()) + } + + fn verify_membership( + &self, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + path: Path, + value: Vec, + ) -> Result<(), ClientError> { + let merkle_path = apply_prefix(prefix, vec![path.to_string()]); + let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone()) + .map_err(ClientError::InvalidCommitmentProof)? + .into(); + + merkle_proof + .verify_membership( + &self.0.proof_specs, + root.clone().into(), + merkle_path, + value, + 0, + ) + .map_err(ClientError::Ics23Verification) + } + + fn verify_non_membership( + &self, + prefix: &CommitmentPrefix, + proof: &CommitmentProofBytes, + root: &CommitmentRoot, + path: Path, + ) -> Result<(), ClientError> { + let merkle_path = apply_prefix(prefix, vec![path.to_string()]); + let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone()) + .map_err(ClientError::InvalidCommitmentProof)? + .into(); + + merkle_proof + .verify_non_membership(&self.0.proof_specs, root.clone().into(), merkle_path) + .map_err(ClientError::Ics23Verification) + } +} + +impl ClientStateValidation for ClientStateWrapper +where + V: ClientValidationContext + TmValidationContext, + V::AnyConsensusState: TryInto, + ClientError: From<>::Error>, +{ + fn verify_client_message( + &self, + ctx: &V, + client_id: &ClientId, + client_message: Any, + update_kind: &UpdateKind, + ) -> Result<(), ClientError> { + match update_kind { + UpdateKind::UpdateClient => { + let header = TmHeader::try_from(client_message)?; + self.verify_header(ctx, client_id, header) + } + UpdateKind::SubmitMisbehaviour => { + let misbehaviour = TmMisbehaviour::try_from(client_message)?; + self.verify_misbehaviour(ctx, client_id, misbehaviour) + } + } + } + + fn check_for_misbehaviour( + &self, + ctx: &V, + client_id: &ClientId, + client_message: Any, + update_kind: &UpdateKind, + ) -> Result { + match update_kind { + UpdateKind::UpdateClient => { + let header = TmHeader::try_from(client_message)?; + self.check_for_misbehaviour_update_client(ctx, client_id, header) + } + UpdateKind::SubmitMisbehaviour => { + let misbehaviour = TmMisbehaviour::try_from(client_message)?; + self.check_for_misbehaviour_misbehavior(&misbehaviour) + } + } + } + + fn status(&self, ctx: &V, client_id: &ClientId) -> Result { + if self.0.is_frozen() { + return Ok(Status::Frozen); + } + + let latest_consensus_state: TmConsensusState = { + let any_latest_consensus_state = + match ctx.consensus_state(&ClientConsensusStatePath::new( + client_id.clone(), + self.0.latest_height.revision_number(), + self.0.latest_height.revision_height(), + )) { + Ok(cs) => cs, + // if the client state does not have an associated consensus state for its latest height + // then it must be expired + Err(_) => return Ok(Status::Expired), + }; + + any_latest_consensus_state.try_into()? + }; + + // Note: if the `duration_since()` is `None`, indicating that the latest + // consensus state is in the future, then we don't consider the client + // to be expired. + let now = ctx.host_timestamp()?; + if let Some(elapsed_since_latest_consensus_state) = + now.duration_since(&latest_consensus_state.timestamp().into()) + { + if elapsed_since_latest_consensus_state > self.0.trusting_period { + return Ok(Status::Expired); + } + } + + Ok(Status::Active) + } +} + +impl ClientStateExecution for ClientStateWrapper +where + E: TmExecutionContext + ExecutionContext, + ::AnyClientState: From, + ::AnyConsensusState: From, +{ + fn initialise( + &self, + ctx: &mut E, + client_id: &ClientId, + consensus_state: Any, + ) -> Result<(), ClientError> { + let host_timestamp = CommonContext::host_timestamp(ctx)?; + let host_height = CommonContext::host_height(ctx)?; + + let tm_consensus_state = TmConsensusState::try_from(consensus_state)?; + + ctx.store_client_state(ClientStatePath::new(client_id), self.clone().into())?; + ctx.store_consensus_state( + ClientConsensusStatePath::new( + client_id.clone(), + self.0.latest_height.revision_number(), + self.0.latest_height.revision_height(), + ), + tm_consensus_state.into(), + )?; + ctx.store_update_time(client_id.clone(), self.latest_height(), host_timestamp)?; + ctx.store_update_height(client_id.clone(), self.latest_height(), host_height)?; + + Ok(()) + } + + fn update_state( + &self, + ctx: &mut E, + client_id: &ClientId, + header: Any, + ) -> Result, ClientError> { + let header = TmHeader::try_from(header)?; + let header_height = header.height(); + + self.prune_oldest_consensus_state(ctx, client_id)?; + + let maybe_existing_consensus_state = { + let path_at_header_height = ClientConsensusStatePath::new( + client_id.clone(), + header_height.revision_number(), + header_height.revision_height(), + ); + + CommonContext::consensus_state(ctx, &path_at_header_height).ok() + }; + + if maybe_existing_consensus_state.is_some() { + // if we already had the header installed by a previous relayer + // then this is a no-op. + // + // Do nothing. + } else { + let host_timestamp = CommonContext::host_timestamp(ctx)?; + let host_height = CommonContext::host_height(ctx)?; + + let new_consensus_state = TmConsensusState::from(header.clone()); + let new_client_state = self.0.clone().with_header(header)?; + + ctx.store_consensus_state( + ClientConsensusStatePath::new( + client_id.clone(), + new_client_state.latest_height.revision_number(), + new_client_state.latest_height.revision_height(), + ), + new_consensus_state.into(), + )?; + ctx.store_client_state( + ClientStatePath::new(client_id), + ClientStateWrapper::from(new_client_state).into(), + )?; + ctx.store_update_time(client_id.clone(), header_height, host_timestamp)?; + ctx.store_update_height(client_id.clone(), header_height, host_height)?; + } + + Ok(vec![header_height]) + } + + fn update_state_on_misbehaviour( + &self, + ctx: &mut E, + client_id: &ClientId, + _client_message: Any, + _update_kind: &UpdateKind, + ) -> Result<(), ClientError> { + let frozen_client_state = self.0.clone().with_frozen_height(Height::min(0)); + + let wrapped_frozen_client_state = ClientStateWrapper::from(frozen_client_state); + + ctx.store_client_state( + ClientStatePath::new(client_id), + wrapped_frozen_client_state.into(), + )?; + + Ok(()) + } + + // Commit the new client state and consensus state to the store + fn update_state_on_upgrade( + &self, + ctx: &mut E, + client_id: &ClientId, + upgraded_client_state: Any, + upgraded_consensus_state: Any, + ) -> Result { + let mut upgraded_tm_client_state = Self::try_from(upgraded_client_state)?; + let upgraded_tm_cons_state = TmConsensusState::try_from(upgraded_consensus_state)?; + + upgraded_tm_client_state.0.zero_custom_fields(); + + // Construct new client state and consensus state relayer chosen client + // parameters are ignored. All chain-chosen parameters come from + // committed client, all client-chosen parameters come from current + // client. + let new_client_state = TmClientState::new( + upgraded_tm_client_state.0.chain_id, + self.0.trust_level, + self.0.trusting_period, + upgraded_tm_client_state.0.unbonding_period, + self.0.max_clock_drift, + upgraded_tm_client_state.0.latest_height, + upgraded_tm_client_state.0.proof_specs, + upgraded_tm_client_state.0.upgrade_path, + self.0.allow_update, + )?; + + // The new consensus state is merely used as a trusted kernel against + // which headers on the new chain can be verified. The root is just a + // stand-in sentinel value as it cannot be known in advance, thus no + // proof verification will pass. The timestamp and the + // NextValidatorsHash of the consensus state is the blocktime and + // NextValidatorsHash of the last block committed by the old chain. This + // will allow the first block of the new chain to be verified against + // the last validators of the old chain so long as it is submitted + // within the TrustingPeriod of this client. + // NOTE: We do not set processed time for this consensus state since + // this consensus state should not be used for packet verification as + // the root is empty. The next consensus state submitted using update + // will be usable for packet-verification. + let sentinel_root = "sentinel_root".as_bytes().to_vec(); + let new_consensus_state = TmConsensusState::new( + sentinel_root.into(), + upgraded_tm_cons_state.timestamp, + upgraded_tm_cons_state.next_validators_hash, + ); + + let latest_height = new_client_state.latest_height; + let host_timestamp = CommonContext::host_timestamp(ctx)?; + let host_height = CommonContext::host_height(ctx)?; + + ctx.store_client_state( + ClientStatePath::new(client_id), + ClientStateWrapper::from(new_client_state).into(), + )?; + ctx.store_consensus_state( + ClientConsensusStatePath::new( + client_id.clone(), + latest_height.revision_number(), + latest_height.revision_height(), + ), + new_consensus_state.into(), + )?; + ctx.store_update_time(client_id.clone(), latest_height, host_timestamp)?; + ctx.store_update_height(client_id.clone(), latest_height, host_height)?; + + Ok(latest_height) + } +} + +#[cfg(test)] +mod tests { + use core::time::Duration; + + use ibc_client_tendermint_types::{ + AllowUpdate, ClientState as ClientStateType, ClientStateParams, TrustThreshold, + }; + use ibc_core_client::types::Height; + use ibc_core_commitment_types::specs::ProofSpecs; + use ibc_core_host::types::identifiers::ChainId; + + use super::*; + + #[test] + fn client_state_verify_height() { + // Define a "default" set of parameters to reuse throughout these tests. + let default_params: ClientStateParams = ClientStateParams { + id: ChainId::new("ibc-1").unwrap(), + trust_level: TrustThreshold::ONE_THIRD, + trusting_period: Duration::new(64000, 0), + unbonding_period: Duration::new(128000, 0), + max_clock_drift: Duration::new(3, 0), + latest_height: Height::new(1, 10).expect("Never fails"), + proof_specs: ProofSpecs::default(), + upgrade_path: Default::default(), + allow_update: AllowUpdate { + after_expiry: false, + after_misbehaviour: false, + }, + }; + + struct Test { + name: String, + height: Height, + setup: Option ClientStateWrapper>>, + want_pass: bool, + } + + let tests = vec![ + Test { + name: "Successful height verification".to_string(), + height: Height::new(1, 8).expect("Never fails"), + setup: None, + want_pass: true, + }, + Test { + name: "Invalid (too large) client height".to_string(), + height: Height::new(1, 12).expect("Never fails"), + setup: None, + want_pass: false, + }, + ]; + + for test in tests { + let p = default_params.clone(); + let client_state = ClientStateType::new( + p.id, + p.trust_level, + p.trusting_period, + p.unbonding_period, + p.max_clock_drift, + p.latest_height, + p.proof_specs, + p.upgrade_path, + p.allow_update, + ) + .expect("Never fails"); + let client_state = match test.setup { + Some(setup) => (setup)(ClientStateWrapper(client_state)), + _ => ClientStateWrapper(client_state), + }; + let res = client_state.validate_proof_height(test.height); + + assert_eq!( + test.want_pass, + res.is_ok(), + "ClientState::validate_proof_height() failed for test {}, \nmsg{:?} with error {:?}", + test.name, + test.height, + res.err(), + ); + } + } +} diff --git a/crates/ibc/src/clients/ics07_tendermint/client_state/misbehaviour.rs b/crates/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs similarity index 75% rename from crates/ibc/src/clients/ics07_tendermint/client_state/misbehaviour.rs rename to crates/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs index 9e3c3141a..9015879ff 100644 --- a/crates/ibc/src/clients/ics07_tendermint/client_state/misbehaviour.rs +++ b/crates/ibc-clients/ics07-tendermint/src/client_state/misbehaviour.rs @@ -1,19 +1,18 @@ +use ibc_client_tendermint_types::error::{Error, IntoResult}; +use ibc_client_tendermint_types::{ + check_header_trusted_next_validator_set, ConsensusState as TmConsensusState, + Header as TmHeader, Misbehaviour as TmMisbehaviour, +}; +use ibc_core_client::types::error::ClientError; +use ibc_core_host::types::identifiers::ClientId; +use ibc_core_host::types::path::ClientConsensusStatePath; +use ibc_primitives::prelude::*; +use ibc_primitives::Timestamp; use tendermint_light_client_verifier::Verifier; -use super::{check_header_trusted_next_validator_set, ClientState}; -use crate::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -use crate::clients::ics07_tendermint::error::{Error, IntoResult}; -use crate::clients::ics07_tendermint::header::Header as TmHeader; -use crate::clients::ics07_tendermint::misbehaviour::Misbehaviour as TmMisbehaviour; -use crate::clients::ics07_tendermint::ValidationContext as TmValidationContext; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::ics24_host::path::ClientConsensusStatePath; -use crate::core::timestamp::Timestamp; -use crate::prelude::*; - -impl ClientState { +use super::{ClientStateWrapper, TmValidationContext}; + +impl ClientStateWrapper { // verify_misbehaviour determines whether or not two conflicting headers at // the same height would have convinced the light client. pub fn verify_misbehaviour( @@ -29,8 +28,11 @@ impl ClientState { let header_1 = misbehaviour.header1(); let trusted_consensus_state_1 = { - let consensus_state_path = - ClientConsensusStatePath::new(client_id, &header_1.trusted_height); + let consensus_state_path = ClientConsensusStatePath::new( + client_id.clone(), + header_1.trusted_height.revision_number(), + header_1.trusted_height.revision_height(), + ); let consensus_state = ctx.consensus_state(&consensus_state_path)?; consensus_state @@ -42,8 +44,11 @@ impl ClientState { let header_2 = misbehaviour.header2(); let trusted_consensus_state_2 = { - let consensus_state_path = - ClientConsensusStatePath::new(client_id, &header_2.trusted_height); + let consensus_state_path = ClientConsensusStatePath::new( + client_id.clone(), + header_2.trusted_height.revision_number(), + header_2.trusted_height.revision_height(), + ); let consensus_state = ctx.consensus_state(&consensus_state_path)?; consensus_state @@ -70,16 +75,16 @@ impl ClientState { // ensure trusted consensus state is within trusting period { let duration_since_consensus_state = current_timestamp - .duration_since(&trusted_consensus_state.timestamp()) + .duration_since(&(trusted_consensus_state.timestamp().into())) .ok_or_else(|| ClientError::InvalidConsensusStateTimestamp { - time1: trusted_consensus_state.timestamp(), + time1: trusted_consensus_state.timestamp().into(), time2: current_timestamp, })?; - if duration_since_consensus_state >= self.trusting_period { + if duration_since_consensus_state >= self.0.trusting_period { return Err(Error::ConsensusStateTimestampGteTrustingPeriod { duration_since_consensus_state, - trusting_period: self.trusting_period, + trusting_period: self.0.trusting_period, } .into()); } @@ -89,6 +94,7 @@ impl ClientState { let untrusted_state = header.as_untrusted_block_state(); let chain_id = self + .0 .chain_id .to_string() .try_into() @@ -97,12 +103,13 @@ impl ClientState { })?; let trusted_state = header.as_trusted_block_state(trusted_consensus_state, &chain_id)?; - let options = self.as_light_client_options()?; + let options = self.0.as_light_client_options()?; let current_timestamp = current_timestamp.into_tm_time().ok_or(ClientError::Other { description: "host timestamp must not be zero".to_string(), })?; - self.verifier + self.0 + .verifier .verify_misbehaviour_header(untrusted_state, trusted_state, &options, current_timestamp) .into_result()?; diff --git a/crates/ibc/src/clients/ics07_tendermint/client_state/update_client.rs b/crates/ibc-clients/ics07-tendermint/src/client_state/update_client.rs similarity index 77% rename from crates/ibc/src/clients/ics07_tendermint/client_state/update_client.rs rename to crates/ibc-clients/ics07-tendermint/src/client_state/update_client.rs index a2fabec1a..b08c0ae79 100644 --- a/crates/ibc/src/clients/ics07_tendermint/client_state/update_client.rs +++ b/crates/ibc-clients/ics07-tendermint/src/client_state/update_client.rs @@ -1,19 +1,19 @@ +use ibc_client_tendermint_types::error::{Error, IntoResult}; +use ibc_client_tendermint_types::{ + check_header_trusted_next_validator_set, ConsensusState as TmConsensusState, Header as TmHeader, +}; +use ibc_core_client::context::ClientExecutionContext; +use ibc_core_client::types::error::ClientError; +use ibc_core_host::types::identifiers::ClientId; +use ibc_core_host::types::path::ClientConsensusStatePath; +use ibc_primitives::prelude::*; use tendermint_light_client_verifier::types::{TrustedBlockState, UntrustedBlockState}; use tendermint_light_client_verifier::Verifier; -use super::{check_header_trusted_next_validator_set, ClientState}; -use crate::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -use crate::clients::ics07_tendermint::error::{Error, IntoResult}; -use crate::clients::ics07_tendermint::header::Header as TmHeader; -use crate::clients::ics07_tendermint::{CommonContext, ValidationContext as TmValidationContext}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics02_client::ClientExecutionContext; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::ics24_host::path::ClientConsensusStatePath; -use crate::prelude::*; - -impl ClientState { +use super::ClientStateWrapper; +use crate::context::{CommonContext, ValidationContext as TmValidationContext}; + +impl ClientStateWrapper { pub fn verify_header( &self, ctx: &ClientValidationContext, @@ -28,15 +28,18 @@ impl ClientState { // The tendermint-light-client crate though works on heights that are assumed // to have the same revision number. We ensure this here. - header.verify_chain_id_version_matches_height(&self.chain_id())?; + header.verify_chain_id_version_matches_height(&self.0.chain_id())?; // Delegate to tendermint-light-client, which contains the required checks // of the new header against the trusted consensus state. { let trusted_state = { - let trusted_client_cons_state_path = - ClientConsensusStatePath::new(client_id, &header.trusted_height); + let trusted_client_cons_state_path = ClientConsensusStatePath::new( + client_id.clone(), + header.trusted_height.revision_number(), + header.trusted_height.revision_height(), + ); let trusted_consensus_state: TmConsensusState = ctx .consensus_state(&trusted_client_cons_state_path)? .try_into() @@ -47,7 +50,7 @@ impl ClientState { check_header_trusted_next_validator_set(&header, &trusted_consensus_state)?; TrustedBlockState { - chain_id: &self.chain_id.to_string().try_into().map_err(|e| { + chain_id: &self.0.chain_id.to_string().try_into().map_err(|e| { ClientError::Other { description: format!("failed to parse chain id: {}", e), } @@ -75,7 +78,7 @@ impl ClientState { next_validators: None, }; - let options = self.as_light_client_options()?; + let options = self.0.as_light_client_options()?; let now = ctx.host_timestamp()?.into_tm_time().ok_or_else(|| { ClientError::ClientSpecific { description: "host timestamp is not a valid TM timestamp".to_string(), @@ -83,7 +86,8 @@ impl ClientState { })?; // main header verification, delegated to the tendermint-light-client crate. - self.verifier + self.0 + .verifier .verify_update_header(untrusted_state, trusted_state, &options, now) .into_result()?; } @@ -103,7 +107,11 @@ impl ClientState { let header_consensus_state = TmConsensusState::from(header.clone()); let maybe_existing_consensus_state = { - let path_at_header_height = ClientConsensusStatePath::new(client_id, &header.height()); + let path_at_header_height = ClientConsensusStatePath::new( + client_id.clone(), + header.height().revision_number(), + header.height().revision_height(), + ); ctx.consensus_state(&path_at_header_height).ok() }; @@ -144,7 +152,7 @@ impl ClientState { // 2. if a header comes in and is not the “last” header, then we also ensure // that its timestamp is less than the “next header” - if header.height() < self.latest_height { + if header.height() < self.0.latest_height { let maybe_next_cs = ctx.next_consensus_state(client_id, &header.height())?; if let Some(next_cs) = maybe_next_cs { @@ -179,7 +187,11 @@ impl ClientState { heights.sort(); for height in heights { - let client_consensus_state_path = ClientConsensusStatePath::new(client_id, &height); + let client_consensus_state_path = ClientConsensusStatePath::new( + client_id.clone(), + height.revision_number(), + height.revision_height(), + ); let consensus_state = CommonContext::consensus_state(ctx, &client_consensus_state_path)?; let tm_consensus_state: TmConsensusState = @@ -189,10 +201,19 @@ impl ClientState { description: err.to_string(), })?; - let host_timestamp = ctx.host_timestamp()?; - let tm_consensus_state_expiry = (tm_consensus_state.timestamp() + self.trusting_period) + let host_timestamp = + ctx.host_timestamp()? + .into_tm_time() + .ok_or_else(|| ClientError::Other { + description: String::from("host timestamp is not a valid TM timestamp"), + })?; + let tm_consensus_state_timestamp = tm_consensus_state.timestamp(); + let tm_consensus_state_expiry = (tm_consensus_state_timestamp + + self.0.trusting_period) .map_err(|_| ClientError::Other { - description: String::from("Timestamp overflow error occurred while attempting to parse TmConsensusState") + description: String::from( + "Timestamp overflow error occurred while attempting to parse TmConsensusState", + ), })?; if tm_consensus_state_expiry > host_timestamp { diff --git a/crates/ibc/src/clients/ics07_tendermint/context.rs b/crates/ibc-clients/ics07-tendermint/src/context.rs similarity index 83% rename from crates/ibc/src/clients/ics07_tendermint/context.rs rename to crates/ibc-clients/ics07-tendermint/src/context.rs index 449efa7dd..99fcb4b0a 100644 --- a/crates/ibc/src/clients/ics07_tendermint/context.rs +++ b/crates/ibc-clients/ics07-tendermint/src/context.rs @@ -1,13 +1,13 @@ use alloc::string::ToString; -use super::consensus_state::ConsensusState as TmConsensusState; -use crate::core::ics02_client::ClientExecutionContext; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::ics24_host::path::ClientConsensusStatePath; -use crate::core::timestamp::Timestamp; -use crate::core::ContextError; -use crate::prelude::*; -use crate::Height; +use ibc_client_tendermint_types::ConsensusState as TmConsensusState; +use ibc_core_client::context::ClientExecutionContext; +use ibc_core_client::types::Height; +use ibc_core_handler_types::error::ContextError; +use ibc_core_host::types::identifiers::ClientId; +use ibc_core_host::types::path::ClientConsensusStatePath; +use ibc_primitives::prelude::*; +use ibc_primitives::Timestamp; /// Client's context required during both validation and execution pub trait CommonContext { diff --git a/crates/ibc-clients/ics07-tendermint/src/lib.rs b/crates/ibc-clients/ics07-tendermint/src/lib.rs new file mode 100644 index 000000000..64aca6719 --- /dev/null +++ b/crates/ibc-clients/ics07-tendermint/src/lib.rs @@ -0,0 +1,30 @@ +//! ICS 07: Tendermint light client implementation along with re-exporting data +//! structures and implementations of IBC core client module. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_casts, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +extern crate alloc; + +#[cfg(any(test, feature = "std"))] +extern crate std; + +pub mod client_state; +pub mod context; + +pub const TENDERMINT_CLIENT_TYPE: &str = "07-tendermint"; + +/// Re-export of Tendermint light client data structures from `ibc-client-tendermint` crate. +pub mod types { + #[doc(inline)] + pub use ibc_client_tendermint_types::*; +} diff --git a/crates/ibc-clients/ics07-tendermint/types/Cargo.toml b/crates/ibc-clients/ics07-tendermint/types/Cargo.toml new file mode 100644 index 000000000..55935dad4 --- /dev/null +++ b/crates/ibc-clients/ics07-tendermint/types/Cargo.toml @@ -0,0 +1,106 @@ +[package] +name = "ibc-client-tendermint-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "transfer", "ics20", "types"] +readme = "./../../README.md" +description = """ + Maintained by `ibc-rs`, encapsulates essential ICS-07 Tendermint Client data structures and domain types, + as specified in the Inter-Blockchain Communication (IBC) protocol. Designed for universal applicability + to facilitate development and integration across diverse IBC-enabled projects. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +bytes = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +serde = { workspace = true, optional = true } + +# ibc dependencies +ibc-core-client-context = { workspace = true } +ibc-core-client-types = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-primitives = { workspace = true } +ibc-proto = { workspace = true } + +# cosmos dependencies +tendermint = { workspace = true } +tendermint-light-client-verifier = { workspace = true, features = ["rust-crypto"] } +tendermint-proto = { workspace = true } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[dev-dependencies] +ibc-testkit = { workspace = true } +serde_json = { workspace = true } +tendermint-rpc = { workspace = true } + +[features] +default = ["std"] +std = [ + "bytes/std", + "displaydoc/std", + "prost/std", + "serde/std", + "serde_json/std", + "ibc-core-client-context/std", + "ibc-core-client-types/std", + "ibc-core-commitment-types/std", + "ibc-core-handler-types/std", + "ibc-core-host-types/std", + "ibc-primitives/std", + "ibc-proto/std", + "tendermint/std", +] +serde = [ + "dep:serde", + "ibc-core-client-context/serde", + "ibc-core-client-types/serde", + "ibc-core-commitment-types/serde", + "ibc-core-handler-types/serde", + "ibc-core-host-types/serde", + "ibc-primitives/serde", + "ibc-proto/serde", +] +schema = [ + "ibc-core-client-types/schema", + "ibc-core-commitment-types/schema", + "ibc-core-handler-types/schema", + "ibc-core-host-types/schema", + "ibc-primitives/schema", + "ibc-proto/json-schema", + "serde", + "std" +] +borsh = [ + "dep:borsh", + "ibc-core-client-types/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-handler-types/borsh", + "ibc-core-host-types/borsh", + "ibc-primitives/borsh", + "ibc-proto/borsh", +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-core-client-types/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", + "ibc-proto/parity-scale-codec", +] \ No newline at end of file diff --git a/crates/ibc-clients/ics07-tendermint/types/README.md b/crates/ibc-clients/ics07-tendermint/types/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/crates/ibc/src/clients/ics07_tendermint/client_state.rs b/crates/ibc-clients/ics07-tendermint/types/src/client_state.rs similarity index 55% rename from crates/ibc/src/clients/ics07_tendermint/client_state.rs rename to crates/ibc-clients/ics07-tendermint/types/src/client_state.rs index d7ada244f..d2a9f81c8 100644 --- a/crates/ibc/src/clients/ics07_tendermint/client_state.rs +++ b/crates/ibc-clients/ics07-tendermint/types/src/client_state.rs @@ -1,17 +1,19 @@ //! Implements the core [`ClientState`](crate::core::ics02_client::client_state::ClientState) trait //! for the Tendermint light client. -mod misbehaviour; -mod update_client; - use core::cmp::max; use core::convert::{TryFrom, TryInto}; use core::str::FromStr; use core::time::Duration; +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::Height; +use ibc_core_commitment_types::specs::ProofSpecs; +use ibc_core_host_types::identifiers::ChainId; +use ibc_primitives::prelude::*; +use ibc_primitives::ZERO_DURATION; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::Height as RawHeight; -use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; use ibc_proto::ibc::lightclients::tendermint::v1::ClientState as RawTmClientState; use ibc_proto::Protobuf; use prost::Message; @@ -20,36 +22,10 @@ use tendermint::trust_threshold::TrustThresholdFraction as TendermintTrustThresh use tendermint_light_client_verifier::options::Options; use tendermint_light_client_verifier::ProdVerifier; -use super::trust_threshold::TrustThreshold; -use super::{ - client_type as tm_client_type, ExecutionContext as TmExecutionContext, - ValidationContext as TmValidationContext, -}; -use crate::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -use crate::clients::ics07_tendermint::error::Error; -use crate::clients::ics07_tendermint::header::Header as TmHeader; -use crate::clients::ics07_tendermint::misbehaviour::Misbehaviour as TmMisbehaviour; -use crate::clients::ics07_tendermint::CommonContext; -use crate::core::ics02_client::client_state::{ - ClientStateCommon, ClientStateExecution, ClientStateValidation, Status, UpdateKind, -}; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::{ClientError, UpgradeClientError}; -use crate::core::ics02_client::{ClientExecutionContext, ClientValidationContext}; -use crate::core::ics23_commitment::commitment::{ - CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, -}; -use crate::core::ics23_commitment::merkle::{apply_prefix, MerkleProof}; -use crate::core::ics23_commitment::specs::ProofSpecs; -use crate::core::ics24_host::identifier::{ChainId, ClientId}; -use crate::core::ics24_host::path::{ - ClientConsensusStatePath, ClientStatePath, Path, UpgradeClientPath, -}; -use crate::core::timestamp::ZERO_DURATION; -use crate::core::ExecutionContext; -use crate::prelude::*; -use crate::Height; +use crate::consensus_state::ConsensusState as TmConsensusState; +use crate::error::Error; +use crate::header::Header as TmHeader; +use crate::trust_threshold::TrustThreshold; pub const TENDERMINT_CLIENT_STATE_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.ClientState"; @@ -60,6 +36,22 @@ pub struct AllowUpdate { pub after_misbehaviour: bool, } +/// Parameters needed when initializing a new `ClientState`. This type +/// exists mainly as a convenience for providing default values in +/// testing scenarios. +#[derive(Clone, Debug, PartialEq)] +pub struct ClientStateParams { + pub id: ChainId, + pub trust_level: TrustThreshold, + pub trusting_period: Duration, + pub unbonding_period: Duration, + pub max_clock_drift: Duration, + pub latest_height: Height, + pub proof_specs: ProofSpecs, + pub upgrade_path: Vec, + pub allow_update: AllowUpdate, +} + /// Contains the core implementation of the Tendermint light client #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Debug, PartialEq)] @@ -68,14 +60,14 @@ pub struct ClientState { pub trust_level: TrustThreshold, pub trusting_period: Duration, pub unbonding_period: Duration, - max_clock_drift: Duration, + pub max_clock_drift: Duration, pub latest_height: Height, pub proof_specs: ProofSpecs, pub upgrade_path: Vec, - allow_update: AllowUpdate, - frozen_height: Option, + pub allow_update: AllowUpdate, + pub frozen_height: Option, #[cfg_attr(feature = "serde", serde(skip))] - verifier: ProdVerifier, + pub verifier: ProdVerifier, } impl ClientState { @@ -244,7 +236,7 @@ impl ClientState { }) } - fn chain_id(&self) -> ChainId { + pub fn chain_id(&self) -> ChainId { self.chain_id.clone() } @@ -263,379 +255,6 @@ impl ClientState { } } -impl ClientStateCommon for ClientState { - fn verify_consensus_state(&self, consensus_state: Any) -> Result<(), ClientError> { - let tm_consensus_state = TmConsensusState::try_from(consensus_state)?; - if tm_consensus_state.root().is_empty() { - return Err(ClientError::Other { - description: "empty commitment root".into(), - }); - }; - - Ok(()) - } - - fn client_type(&self) -> ClientType { - tm_client_type() - } - - fn latest_height(&self) -> Height { - self.latest_height - } - - fn validate_proof_height(&self, proof_height: Height) -> Result<(), ClientError> { - if self.latest_height() < proof_height { - return Err(ClientError::InvalidProofHeight { - latest_height: self.latest_height(), - proof_height, - }); - } - Ok(()) - } - - /// Perform client-specific verifications and check all data in the new - /// client state to be the same across all valid Tendermint clients for the - /// new chain. - /// - /// You can learn more about how to upgrade IBC-connected SDK chains in - /// [this](https://ibc.cosmos.network/main/ibc/upgrades/quick-guide.html) - /// guide - fn verify_upgrade_client( - &self, - upgraded_client_state: Any, - upgraded_consensus_state: Any, - proof_upgrade_client: CommitmentProofBytes, - proof_upgrade_consensus_state: CommitmentProofBytes, - root: &CommitmentRoot, - ) -> Result<(), ClientError> { - // Make sure that the client type is of Tendermint type `ClientState` - let upgraded_tm_client_state = Self::try_from(upgraded_client_state.clone())?; - - // Make sure that the consensus type is of Tendermint type `ConsensusState` - TmConsensusState::try_from(upgraded_consensus_state.clone())?; - - // Make sure the latest height of the current client is not greater then - // the upgrade height This condition checks both the revision number and - // the height - if self.latest_height() >= upgraded_tm_client_state.latest_height { - return Err(UpgradeClientError::LowUpgradeHeight { - upgraded_height: self.latest_height(), - client_height: upgraded_tm_client_state.latest_height, - })?; - } - - // Check to see if the upgrade path is set - let mut upgrade_path = self.upgrade_path.clone(); - if upgrade_path.pop().is_none() { - return Err(ClientError::ClientSpecific { - description: "cannot upgrade client as no upgrade path has been set".to_string(), - }); - }; - - let upgrade_path_prefix = CommitmentPrefix::try_from(upgrade_path[0].clone().into_bytes()) - .map_err(ClientError::InvalidCommitmentProof)?; - - let last_height = self.latest_height().revision_height(); - - let mut client_state_value = Vec::new(); - upgraded_client_state - .encode(&mut client_state_value) - .map_err(ClientError::Encode)?; - - // Verify the proof of the upgraded client state - self.verify_membership( - &upgrade_path_prefix, - &proof_upgrade_client, - root, - Path::UpgradeClient(UpgradeClientPath::UpgradedClientState(last_height)), - client_state_value, - )?; - - let mut cons_state_value = Vec::new(); - upgraded_consensus_state - .encode(&mut cons_state_value) - .map_err(ClientError::Encode)?; - - // Verify the proof of the upgraded consensus state - self.verify_membership( - &upgrade_path_prefix, - &proof_upgrade_consensus_state, - root, - Path::UpgradeClient(UpgradeClientPath::UpgradedClientConsensusState(last_height)), - cons_state_value, - )?; - - Ok(()) - } - - fn verify_membership( - &self, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - path: Path, - value: Vec, - ) -> Result<(), ClientError> { - let merkle_path = apply_prefix(prefix, vec![path.to_string()]); - let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone()) - .map_err(ClientError::InvalidCommitmentProof)? - .into(); - - merkle_proof - .verify_membership( - &self.proof_specs, - root.clone().into(), - merkle_path, - value, - 0, - ) - .map_err(ClientError::Ics23Verification) - } - - fn verify_non_membership( - &self, - prefix: &CommitmentPrefix, - proof: &CommitmentProofBytes, - root: &CommitmentRoot, - path: Path, - ) -> Result<(), ClientError> { - let merkle_path = apply_prefix(prefix, vec![path.to_string()]); - let merkle_proof: MerkleProof = RawMerkleProof::try_from(proof.clone()) - .map_err(ClientError::InvalidCommitmentProof)? - .into(); - - merkle_proof - .verify_non_membership(&self.proof_specs, root.clone().into(), merkle_path) - .map_err(ClientError::Ics23Verification) - } -} - -impl ClientStateValidation for ClientState -where - V: ClientValidationContext + TmValidationContext, - V::AnyConsensusState: TryInto, - ClientError: From<>::Error>, -{ - fn verify_client_message( - &self, - ctx: &V, - client_id: &ClientId, - client_message: Any, - update_kind: &UpdateKind, - ) -> Result<(), ClientError> { - match update_kind { - UpdateKind::UpdateClient => { - let header = TmHeader::try_from(client_message)?; - self.verify_header(ctx, client_id, header) - } - UpdateKind::SubmitMisbehaviour => { - let misbehaviour = TmMisbehaviour::try_from(client_message)?; - self.verify_misbehaviour(ctx, client_id, misbehaviour) - } - } - } - - fn check_for_misbehaviour( - &self, - ctx: &V, - client_id: &ClientId, - client_message: Any, - update_kind: &UpdateKind, - ) -> Result { - match update_kind { - UpdateKind::UpdateClient => { - let header = TmHeader::try_from(client_message)?; - self.check_for_misbehaviour_update_client(ctx, client_id, header) - } - UpdateKind::SubmitMisbehaviour => { - let misbehaviour = TmMisbehaviour::try_from(client_message)?; - self.check_for_misbehaviour_misbehavior(&misbehaviour) - } - } - } - - fn status(&self, ctx: &V, client_id: &ClientId) -> Result { - if self.is_frozen() { - return Ok(Status::Frozen); - } - - let latest_consensus_state: TmConsensusState = { - let any_latest_consensus_state = match ctx.consensus_state( - &ClientConsensusStatePath::new(client_id, &self.latest_height), - ) { - Ok(cs) => cs, - // if the client state does not have an associated consensus state for its latest height - // then it must be expired - Err(_) => return Ok(Status::Expired), - }; - - any_latest_consensus_state.try_into()? - }; - - // Note: if the `duration_since()` is `None`, indicating that the latest - // consensus state is in the future, then we don't consider the client - // to be expired. - let now = ctx.host_timestamp()?; - if let Some(elapsed_since_latest_consensus_state) = - now.duration_since(&latest_consensus_state.timestamp()) - { - if elapsed_since_latest_consensus_state > self.trusting_period { - return Ok(Status::Expired); - } - } - - Ok(Status::Active) - } -} - -impl ClientStateExecution for ClientState -where - E: TmExecutionContext + ExecutionContext, - ::AnyClientState: From, - ::AnyConsensusState: From, -{ - fn initialise( - &self, - ctx: &mut E, - client_id: &ClientId, - consensus_state: Any, - ) -> Result<(), ClientError> { - let host_timestamp = CommonContext::host_timestamp(ctx)?; - let host_height = CommonContext::host_height(ctx)?; - - let tm_consensus_state = TmConsensusState::try_from(consensus_state)?; - - ctx.store_client_state(ClientStatePath::new(client_id), self.clone().into())?; - ctx.store_consensus_state( - ClientConsensusStatePath::new(client_id, &self.latest_height), - tm_consensus_state.into(), - )?; - ctx.store_update_time(client_id.clone(), self.latest_height(), host_timestamp)?; - ctx.store_update_height(client_id.clone(), self.latest_height(), host_height)?; - - Ok(()) - } - - fn update_state( - &self, - ctx: &mut E, - client_id: &ClientId, - header: Any, - ) -> Result, ClientError> { - let header = TmHeader::try_from(header)?; - let header_height = header.height(); - - self.prune_oldest_consensus_state(ctx, client_id)?; - - let maybe_existing_consensus_state = { - let path_at_header_height = ClientConsensusStatePath::new(client_id, &header_height); - - CommonContext::consensus_state(ctx, &path_at_header_height).ok() - }; - - if maybe_existing_consensus_state.is_some() { - // if we already had the header installed by a previous relayer - // then this is a no-op. - // - // Do nothing. - } else { - let host_timestamp = CommonContext::host_timestamp(ctx)?; - let host_height = CommonContext::host_height(ctx)?; - - let new_consensus_state = TmConsensusState::from(header.clone()); - let new_client_state = self.clone().with_header(header)?; - - ctx.store_consensus_state( - ClientConsensusStatePath::new(client_id, &new_client_state.latest_height), - new_consensus_state.into(), - )?; - ctx.store_client_state(ClientStatePath::new(client_id), new_client_state.into())?; - ctx.store_update_time(client_id.clone(), header_height, host_timestamp)?; - ctx.store_update_height(client_id.clone(), header_height, host_height)?; - } - - Ok(vec![header_height]) - } - - fn update_state_on_misbehaviour( - &self, - ctx: &mut E, - client_id: &ClientId, - _client_message: Any, - _update_kind: &UpdateKind, - ) -> Result<(), ClientError> { - let frozen_client_state = self.clone().with_frozen_height(Height::min(0)); - - ctx.store_client_state(ClientStatePath::new(client_id), frozen_client_state.into())?; - - Ok(()) - } - - // Commit the new client state and consensus state to the store - fn update_state_on_upgrade( - &self, - ctx: &mut E, - client_id: &ClientId, - upgraded_client_state: Any, - upgraded_consensus_state: Any, - ) -> Result { - let mut upgraded_tm_client_state = Self::try_from(upgraded_client_state)?; - let upgraded_tm_cons_state = TmConsensusState::try_from(upgraded_consensus_state)?; - - upgraded_tm_client_state.zero_custom_fields(); - - // Construct new client state and consensus state relayer chosen client - // parameters are ignored. All chain-chosen parameters come from - // committed client, all client-chosen parameters come from current - // client. - let new_client_state = ClientState::new( - upgraded_tm_client_state.chain_id, - self.trust_level, - self.trusting_period, - upgraded_tm_client_state.unbonding_period, - self.max_clock_drift, - upgraded_tm_client_state.latest_height, - upgraded_tm_client_state.proof_specs, - upgraded_tm_client_state.upgrade_path, - self.allow_update, - )?; - - // The new consensus state is merely used as a trusted kernel against - // which headers on the new chain can be verified. The root is just a - // stand-in sentinel value as it cannot be known in advance, thus no - // proof verification will pass. The timestamp and the - // NextValidatorsHash of the consensus state is the blocktime and - // NextValidatorsHash of the last block committed by the old chain. This - // will allow the first block of the new chain to be verified against - // the last validators of the old chain so long as it is submitted - // within the TrustingPeriod of this client. - // NOTE: We do not set processed time for this consensus state since - // this consensus state should not be used for packet verification as - // the root is empty. The next consensus state submitted using update - // will be usable for packet-verification. - let sentinel_root = "sentinel_root".as_bytes().to_vec(); - let new_consensus_state = TmConsensusState::new( - sentinel_root.into(), - upgraded_tm_cons_state.timestamp, - upgraded_tm_cons_state.next_validators_hash, - ); - - let latest_height = new_client_state.latest_height; - let host_timestamp = CommonContext::host_timestamp(ctx)?; - let host_height = CommonContext::host_height(ctx)?; - - ctx.store_client_state(ClientStatePath::new(client_id), new_client_state.into())?; - ctx.store_consensus_state( - ClientConsensusStatePath::new(client_id, &latest_height), - new_consensus_state.into(), - )?; - ctx.store_update_time(client_id.clone(), latest_height, host_timestamp)?; - ctx.store_update_height(client_id.clone(), latest_height, host_height)?; - - Ok(latest_height) - } -} - impl Protobuf for ClientState {} impl TryFrom for ClientState { @@ -778,7 +397,7 @@ impl From for Any { // `header.trusted_validator_set` was given to us by the relayer. Thus, we // need to ensure that the relayer gave us the right set, i.e. by ensuring // that it matches the hash we have stored on chain. -fn check_header_trusted_next_validator_set( +pub fn check_header_trusted_next_validator_set( header: &TmHeader, trusted_consensus_state: &TmConsensusState, ) -> Result<(), ClientError> { @@ -793,15 +412,35 @@ fn check_header_trusted_next_validator_set( } #[cfg(all(test, feature = "serde"))] -mod serde_tests { +pub(crate) mod serde_tests { + use serde::de::DeserializeOwned; + use serde::Serialize; use tendermint_rpc::endpoint::abci_query::AbciQuery; - use crate::serializers::tests::test_serialization_roundtrip; + pub fn test_serialization_roundtrip(json_data: &str) + where + T: core::fmt::Debug + PartialEq + Serialize + DeserializeOwned, + { + let parsed0 = serde_json::from_str::(json_data); + assert!(parsed0.is_ok()); + let parsed0 = parsed0.unwrap(); + + let serialized = serde_json::to_string(&parsed0); + assert!(serialized.is_ok()); + let serialized = serialized.unwrap(); + + let parsed1 = serde_json::from_str::(&serialized); + assert!(parsed1.is_ok()); + let parsed1 = parsed1.unwrap(); + + assert_eq!(parsed0, parsed1); + } + #[test] fn serialization_roundtrip_no_proof() { let json_data = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), - "/../ibc-testkit/tests/data/json/client_state.json" + "/../../../ibc-testkit/tests/data/json/client_state.json" )); test_serialization_roundtrip::(json_data); } @@ -810,7 +449,7 @@ mod serde_tests { fn serialization_roundtrip_with_proof() { let json_data = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), - "/../ibc-testkit/tests/data/json/client_state_proof.json" + "/../../../ibc-testkit/tests/data/json/client_state_proof.json" )); test_serialization_roundtrip::(json_data); } @@ -821,21 +460,18 @@ mod tests { use core::str::FromStr; use core::time::Duration; + use ibc_core_client_types::Height; + use ibc_core_commitment_types::specs::ProofSpecs; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::Height as RawHeight; use ibc_proto::ibc::lightclients::tendermint::v1::{ClientState as RawTmClientState, Fraction}; use ibc_proto::ics23::ProofSpec as Ics23ProofSpec; use ibc_testkit::utils::clients::tendermint::dummy_tendermint_header; use tendermint::block::Header; - use test_log::test; use super::*; - use crate::clients::ics07_tendermint::client_state::{AllowUpdate, ClientState}; - use crate::clients::ics07_tendermint::error::Error; - use crate::core::ics02_client::height::Height; - use crate::core::ics23_commitment::specs::ProofSpecs; - use crate::core::ics24_host::identifier::ChainId; - use crate::core::timestamp::ZERO_DURATION; + use crate::client_state::{AllowUpdate, ClientState}; + use crate::error::Error; impl ClientState { pub fn new_dummy_from_raw(frozen_height: RawHeight) -> Result { @@ -883,19 +519,6 @@ mod tests { } } - #[derive(Clone, Debug, PartialEq)] - struct ClientStateParams { - id: ChainId, - trust_level: TrustThreshold, - trusting_period: Duration, - unbonding_period: Duration, - max_clock_drift: Duration, - latest_height: Height, - proof_specs: ProofSpecs, - upgrade_path: Vec, - allow_update: AllowUpdate, - } - #[test] fn client_state_new() { // Define a "default" set of parameters to reuse throughout these tests. @@ -1062,77 +685,6 @@ mod tests { } } - #[test] - fn client_state_verify_height() { - // Define a "default" set of parameters to reuse throughout these tests. - let default_params: ClientStateParams = ClientStateParams { - id: ChainId::new("ibc-1").unwrap(), - trust_level: TrustThreshold::ONE_THIRD, - trusting_period: Duration::new(64000, 0), - unbonding_period: Duration::new(128000, 0), - max_clock_drift: Duration::new(3, 0), - latest_height: Height::new(1, 10).expect("Never fails"), - proof_specs: ProofSpecs::default(), - upgrade_path: Default::default(), - allow_update: AllowUpdate { - after_expiry: false, - after_misbehaviour: false, - }, - }; - - struct Test { - name: String, - height: Height, - setup: Option ClientState>>, - want_pass: bool, - } - - let tests = vec![ - Test { - name: "Successful height verification".to_string(), - height: Height::new(1, 8).expect("Never fails"), - setup: None, - want_pass: true, - }, - Test { - name: "Invalid (too large) client height".to_string(), - height: Height::new(1, 12).expect("Never fails"), - setup: None, - want_pass: false, - }, - ]; - - for test in tests { - let p = default_params.clone(); - let client_state = ClientState::new( - p.id, - p.trust_level, - p.trusting_period, - p.unbonding_period, - p.max_clock_drift, - p.latest_height, - p.proof_specs, - p.upgrade_path, - p.allow_update, - ) - .expect("Never fails"); - let client_state = match test.setup { - Some(setup) => (setup)(client_state), - _ => client_state, - }; - let res = client_state.validate_proof_height(test.height); - - assert_eq!( - test.want_pass, - res.is_ok(), - "ClientState::validate_proof_height() failed for test {}, \nmsg{:?} with error {:?}", - test.name, - test.height, - res.err(), - ); - } - } - #[test] fn tm_client_state_conversions_healthy() { // check client state creation path from a proto type diff --git a/crates/ibc/src/clients/ics07_tendermint/consensus_state.rs b/crates/ibc-clients/ics07-tendermint/types/src/consensus_state.rs similarity index 88% rename from crates/ibc/src/clients/ics07_tendermint/consensus_state.rs rename to crates/ibc-clients/ics07-tendermint/types/src/consensus_state.rs index f00a70b8c..1cb9a5f5f 100644 --- a/crates/ibc/src/clients/ics07_tendermint/consensus_state.rs +++ b/crates/ibc-clients/ics07-tendermint/types/src/consensus_state.rs @@ -1,5 +1,10 @@ //! Defines Tendermint's `ConsensusState` type +use ibc_core_client_context::consensus_state::ConsensusState as ConsensusStateTrait; +use ibc_core_client_types::error::ClientError; +use ibc_core_commitment_types::commitment::CommitmentRoot; +use ibc_primitives::prelude::*; +use ibc_primitives::Timestamp; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::lightclients::tendermint::v1::ConsensusState as RawConsensusState; use ibc_proto::Protobuf; @@ -8,13 +13,8 @@ use tendermint::time::Time; use tendermint::Hash; use tendermint_proto::google::protobuf as tpb; -use crate::clients::ics07_tendermint::error::Error; -use crate::clients::ics07_tendermint::header::Header; -use crate::core::ics02_client::consensus_state::ConsensusState as ConsensusStateTrait; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics23_commitment::commitment::CommitmentRoot; -use crate::core::timestamp::Timestamp; -use crate::prelude::*; +use crate::error::Error; +use crate::header::Header; pub const TENDERMINT_CONSENSUS_STATE_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.ConsensusState"; @@ -36,6 +36,28 @@ impl ConsensusState { next_validators_hash, } } + + pub fn timestamp(&self) -> Time { + self.timestamp + } + + pub fn root(&self) -> CommitmentRoot { + self.root.clone() + } +} + +impl ConsensusStateTrait for ConsensusState { + fn root(&self) -> &CommitmentRoot { + &self.root + } + + fn timestamp(&self) -> Timestamp { + self.timestamp.into() + } + + fn encode_vec(self) -> Vec { + >::encode_vec(self) + } } impl Protobuf for ConsensusState {} @@ -147,32 +169,17 @@ impl From
for ConsensusState { } } -impl ConsensusStateTrait for ConsensusState { - fn root(&self) -> &CommitmentRoot { - &self.root - } - - fn timestamp(&self) -> Timestamp { - self.timestamp.into() - } - - fn encode_vec(self) -> Vec { - >::encode_vec(self) - } -} - #[cfg(all(test, feature = "serde"))] mod tests { use tendermint_rpc::endpoint::abci_query::AbciQuery; - use test_log::test; - use crate::serializers::tests::test_serialization_roundtrip; + use crate::serde_tests::test_serialization_roundtrip; #[test] fn serialization_roundtrip_no_proof() { let json_data = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), - "/../ibc-testkit/tests/data/json/consensus_state.json" + "/../../../ibc-testkit/tests/data/json/consensus_state.json" )); test_serialization_roundtrip::(json_data); } @@ -181,7 +188,7 @@ mod tests { fn serialization_roundtrip_with_proof() { let json_data = include_str!(concat!( env!("CARGO_MANIFEST_DIR"), - "/../ibc-testkit/tests/data/json/consensus_state_proof.json" + "/../../../ibc-testkit/tests/data/json/consensus_state_proof.json" )); test_serialization_roundtrip::(json_data); } diff --git a/crates/ibc/src/clients/ics07_tendermint/error.rs b/crates/ibc-clients/ics07-tendermint/types/src/error.rs similarity index 95% rename from crates/ibc/src/clients/ics07_tendermint/error.rs rename to crates/ibc-clients/ics07-tendermint/types/src/error.rs index 135cb1948..661b116a5 100644 --- a/crates/ibc/src/clients/ics07_tendermint/error.rs +++ b/crates/ibc-clients/ics07-tendermint/types/src/error.rs @@ -3,16 +3,16 @@ use core::time::Duration; use displaydoc::Display; +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::Height; +use ibc_core_host_types::error::IdentifierError; +use ibc_core_host_types::identifiers::ClientId; +use ibc_primitives::prelude::*; use tendermint::{Error as TendermintError, Hash}; use tendermint_light_client_verifier::errors::VerificationErrorDetail as LightClientErrorDetail; use tendermint_light_client_verifier::operations::VotingPowerTally; use tendermint_light_client_verifier::Verdict; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics24_host::identifier::{ClientId, IdentifierError}; -use crate::prelude::*; -use crate::Height; - /// The main error type #[derive(Debug, Display)] pub enum Error { @@ -124,7 +124,7 @@ impl From for Error { } } -pub(crate) trait IntoResult { +pub trait IntoResult { fn into_result(self) -> Result; } diff --git a/crates/ibc/src/clients/ics07_tendermint/header.rs b/crates/ibc-clients/ics07-tendermint/types/src/header.rs similarity index 94% rename from crates/ibc/src/clients/ics07_tendermint/header.rs rename to crates/ibc-clients/ics07-tendermint/types/src/header.rs index cb1f56c4f..f9fd3d375 100644 --- a/crates/ibc/src/clients/ics07_tendermint/header.rs +++ b/crates/ibc-clients/ics07-tendermint/types/src/header.rs @@ -5,6 +5,11 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; use bytes::Buf; +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::Height; +use ibc_core_host_types::identifiers::ChainId; +use ibc_primitives::prelude::*; +use ibc_primitives::Timestamp; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::lightclients::tendermint::v1::Header as RawHeader; use ibc_proto::Protobuf; @@ -15,13 +20,8 @@ use tendermint::chain::Id as TmChainId; use tendermint::validator::Set as ValidatorSet; use tendermint_light_client_verifier::types::{TrustedBlockState, UntrustedBlockState}; -use crate::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -use crate::clients::ics07_tendermint::error::Error; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics24_host::identifier::ChainId; -use crate::core::timestamp::Timestamp; -use crate::prelude::*; -use crate::Height; +use crate::consensus_state::ConsensusState as TmConsensusState; +use crate::error::Error; pub const TENDERMINT_HEADER_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.Header"; @@ -62,7 +62,7 @@ impl Header { .expect("malformed tendermint header domain type has an illegal height of 0") } - pub(crate) fn as_untrusted_block_state(&self) -> UntrustedBlockState<'_> { + pub fn as_untrusted_block_state(&self) -> UntrustedBlockState<'_> { UntrustedBlockState { signed_header: &self.signed_header, validators: &self.validator_set, @@ -70,7 +70,7 @@ impl Header { } } - pub(crate) fn as_trusted_block_state<'a>( + pub fn as_trusted_block_state<'a>( &'a self, consensus_state: &TmConsensusState, chain_id: &'a TmChainId, @@ -207,8 +207,9 @@ impl From
for RawHeader { } mod pretty { + use ibc_primitives::utils::PrettySlice; + pub use super::*; - use crate::utils::pretty::PrettySlice; pub struct PrettySignedHeader<'a>(pub &'a SignedHeader); diff --git a/crates/ibc-clients/ics07-tendermint/types/src/lib.rs b/crates/ibc-clients/ics07-tendermint/types/src/lib.rs new file mode 100644 index 000000000..6d312d9c3 --- /dev/null +++ b/crates/ibc-clients/ics07-tendermint/types/src/lib.rs @@ -0,0 +1,63 @@ +//! ICS-07: Tendermint Client implements a client verification algorithm for blockchains which use +//! the Tendermint consensus algorithm. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_casts, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +use core::str::FromStr; + +use ibc_core_host_types::identifiers::ClientType; + +extern crate alloc; + +#[cfg(any(test, feature = "std"))] +extern crate std; + +mod client_state; +mod consensus_state; +mod header; +mod misbehaviour; +mod trust_threshold; + +pub use client_state::*; +pub use consensus_state::*; +pub use header::*; +pub use misbehaviour::*; +pub use trust_threshold::*; + +pub mod error; + +/// Re-exports necessary proto types for Tendermint light client implementation +/// from `ibc-proto` crate. +pub mod proto { + pub use ibc_proto::google::protobuf::Any; + pub use ibc_proto::ibc::lightclients::tendermint::*; + pub use ibc_proto::Protobuf; +} + +pub const TENDERMINT_CLIENT_TYPE: &str = "07-tendermint"; + +/// Returns the tendermint `ClientType` +pub fn client_type() -> ClientType { + ClientType::from_str(TENDERMINT_CLIENT_TYPE).expect("Never fails because it's valid") +} + +#[cfg(test)] +mod tests { + use super::*; + + // Ensures that the validation in `ClientType::from_str` doesn't fail for the tendermint client type + #[test] + pub fn test_tm_client_type() { + let _ = ClientType::from_str(TENDERMINT_CLIENT_TYPE).unwrap(); + } +} diff --git a/crates/ibc/src/clients/ics07_tendermint/misbehaviour.rs b/crates/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs similarity index 94% rename from crates/ibc/src/clients/ics07_tendermint/misbehaviour.rs rename to crates/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs index 8697a7c11..010b2a40f 100644 --- a/crates/ibc/src/clients/ics07_tendermint/misbehaviour.rs +++ b/crates/ibc-clients/ics07-tendermint/types/src/misbehaviour.rs @@ -1,16 +1,16 @@ //! Defines the misbehaviour type for the tendermint light client use bytes::Buf; +use ibc_core_client_types::error::ClientError; +use ibc_core_host_types::identifiers::ClientId; +use ibc_primitives::prelude::*; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::lightclients::tendermint::v1::Misbehaviour as RawMisbehaviour; use ibc_proto::Protobuf; use prost::Message; -use crate::clients::ics07_tendermint::error::Error; -use crate::clients::ics07_tendermint::header::Header; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics24_host::identifier::ClientId; -use crate::prelude::*; +use crate::error::Error; +use crate::header::Header; const TENDERMINT_MISBEHAVIOUR_TYPE_URL: &str = "/ibc.lightclients.tendermint.v1.Misbehaviour"; diff --git a/crates/ibc/src/clients/ics07_tendermint/trust_threshold.rs b/crates/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs similarity index 98% rename from crates/ibc/src/clients/ics07_tendermint/trust_threshold.rs rename to crates/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs index 744dbf14d..c601f3e25 100644 --- a/crates/ibc/src/clients/ics07_tendermint/trust_threshold.rs +++ b/crates/ibc-clients/ics07-tendermint/types/src/trust_threshold.rs @@ -5,12 +5,11 @@ use core::convert::TryFrom; use core::fmt::{Display, Error as FmtError, Formatter}; +use ibc_core_client_types::error::ClientError; use ibc_proto::ibc::lightclients::tendermint::v1::Fraction; use ibc_proto::Protobuf; use tendermint::trust_threshold::TrustThresholdFraction; -use crate::core::ics02_client::error::ClientError; - /// [`TrustThreshold`] defines the level of trust that a client has /// towards a set of validators of a chain. /// diff --git a/crates/ibc-clients/src/lib.rs b/crates/ibc-clients/src/lib.rs new file mode 100644 index 000000000..12f039089 --- /dev/null +++ b/crates/ibc-clients/src/lib.rs @@ -0,0 +1,18 @@ +//! Exports data structures and implementations of different IBC applications. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +/// Re-exports implementations of ICS-07 Tendermint light client. +pub mod tendermint { + #[doc(inline)] + pub use ibc_client_tendermint::*; +} diff --git a/crates/ibc-core/Cargo.toml b/crates/ibc-core/Cargo.toml new file mode 100644 index 000000000..f8853a76f --- /dev/null +++ b/crates/ibc-core/Cargo.toml @@ -0,0 +1,75 @@ +[package] +name = "ibc-core" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "core"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, re-exports a comprehensive set of libraries that implement IBC core (TAO) + modules, facilitating seamless integration of IBC core business logic into any blockchain system. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +ibc-core-client = { workspace = true } +ibc-core-connection = { workspace = true } +ibc-core-channel = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host = { workspace = true } +ibc-core-router = { workspace = true } +ibc-core-handler = { workspace = true } +ibc-primitives = { workspace = true } + +[features] +default = ["std"] +std = [ + "ibc-core-client/std", + "ibc-core-connection/std", + "ibc-core-channel/std", + "ibc-core-commitment-types/std", + "ibc-core-host/std", + "ibc-core-router/std", + "ibc-core-handler/std", +] +serde = [ + "ibc-core-client/serde", + "ibc-core-connection/serde", + "ibc-core-channel/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host/serde", + "ibc-core-router/serde", + "ibc-core-handler/serde", +] +borsh = [ + "ibc-core-client/borsh", + "ibc-core-connection/borsh", + "ibc-core-channel/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host/borsh", + "ibc-core-router/borsh", + "ibc-core-handler/borsh", +] +schema = [ + "ibc-core-client/schema", + "ibc-core-connection/schema", + "ibc-core-channel/schema", + "ibc-core-commitment-types/schema", + "ibc-core-host/schema", + "ibc-core-router/schema", + "ibc-core-handler/schema", +] +parity-scale-codec = [ + "ibc-core-client/parity-scale-codec", + "ibc-core-connection/parity-scale-codec", + "ibc-core-channel/parity-scale-codec", + "ibc-core-host/parity-scale-codec", + "ibc-core-router/parity-scale-codec", + "ibc-core-handler/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] diff --git a/crates/ibc-core/README.md b/crates/ibc-core/README.md new file mode 100644 index 000000000..9bb5da58b --- /dev/null +++ b/crates/ibc-core/README.md @@ -0,0 +1,124 @@ +# IBC Core + +This crate is top-level library re-exports implemented Inter-Blockchain +Communication (IBC) core modules serves as a meta-crate, simplifying the +process of importing and integrating various IBC core modules into your +blockchain. IBC is a distributed protocol that enables communication between +distinct sovereign blockchains and IBC core is the part of the protocol that +handles transport, authentication and ordering (TAO) layers of data packets. + +The structure within the `ibc-core` crate is designed to provide flexibility for +external users. It allows you to utilize the own `ibc-core` crate or selectively +import specific libraries, whether you need a certain IBC core module (e.g. +`ibc-core-client` crate) or only their associated data structures (e.g. +`ibc-core-client-types`). This versatility empowers hosts, including chain +integrators, relayers, or any IBC tooling projects, to build their solutions on +top of the layers that best suit their requirements. + +## Sub-Crates + +Currently, the `ibc-core` crate contains the implementation of the following IBC +core specifications: + +### ICS-02: Client Semantics + +- [ibc-core-client](./../ibc-core/ics02-client) +- [ibc-core-client-context](./../ibc-core/ics02-client/context) +- [ibc-core-client-types](./../ibc-apps/ics02-client/types) + +### ICS-03: Connection Semantics + +- [ibc-core-connection](./../ibc-core/ics03-connection) +- [ibc-core-connection-types](./../ibc-core/ics03-connection/types) + +### ICS-04: Channel and Packet Semantics + +- [ibc-core-channel](./../ibc-core/ics04-channel) +- [ibc-core-channel-types](./../ibc-core/ics04-channel/types) + +### ICS-24: Host Requirements + +- [ibc-core-host](./../ibc-core/ics24-host) +- [ibc-core-host-types](./../ibc-core/ics24-host/types) + +### ICS-25: Handler Interface + +- [ibc-core-handler](./../ibc-core/ics25-handler) +- [ibc-core-handler-types](./../ibc-core/ics25-handler/types) + +### ICS-26: Routing Module + +- [ibc-core-routing](./../ibc-core/ics26-routing) +- [ibc-core-routing-types](./../ibc-core/ics26-routing/types) + +## Divergence from the Interchain Standards (ICS) + +This crate diverges from the [ICS specification](https://github.com/cosmos/ibc) +in a number of ways. See below for more details. + +### Module system: no support for untrusted modules + +ICS-24 (Host Requirements) gives the [following +requirement](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#module-system) +about the module system that the host state machine must support: + +> The host state machine must support a module system, whereby self-contained, +> potentially mutually distrusted packages of code can safely execute on the +> same ledger [...]. + +**This crate currently does not support mutually distrusted packages**. That is, +modules on the host state machine are assumed to be fully trusted. In practice, +this means that every module has either been written by the host state machine +developers, or fully vetted by them. + +### Port system: No object capability system + +ICS-05 (Port Allocation) requires the host system to support either +object-capability reference or source authentication for modules. + +> In the former object-capability case, the IBC handler must have the ability to +> generate object-capabilities, unique, opaque references which can be passed to +> a module and will not be duplicable by other modules. [...] In the latter +> source authentication case, the IBC handler must have the ability to securely +> read the source identifier of the calling module, a unique string for each +> module in the host state machine, which cannot be altered by the module or +> faked by another module. + +**This crate currently requires neither of the host system**. Since modules are +assumed to be trusted, there is no need for this object capability system that +protects resources for potentially malicious modules. + +For more background on this, see [this issue](https://github.com/informalsystems/ibc-rs/issues/2159). + +### Port system: transferring and releasing a port + +ICS-05 (Port Allocation) requires the IBC handler to permit [transferring +ownership of a +port](https://github.com/cosmos/ibc/tree/master/spec/core/ics-005-port-allocation#transferring-ownership-of-a-port) +and [releasing a +port](https://github.com/cosmos/ibc/tree/master/spec/core/ics-005-port-allocation#releasing-a-port). + +We currently support neither. + +### Asynchronous acknowledgements + +The standard gives the ability for modules to [acknowledge packets +asynchronously](https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics#writing-acknowledgements). +This allows modules to receive the packet, but only applying the changes at a +later time (after which they would write the acknowledgement). + +We currently force applications to process the packets as part of +`onRecvPacket()`. If you need asynchronous acknowledgements for your +application, please open an issue. + +Note that this still makes us 100% compatible with `ibc-go`. + +## Contributing + +IBC is specified in English in the [cosmos/ibc +repo](https://github.com/cosmos/ibc). Any protocol changes or clarifications +should be contributed there. + +If you're interested in contributing, please take a look at the +[CONTRIBUTING](./../../CONTRIBUTING.md) guidelines. We welcome and appreciate +community contributions! diff --git a/crates/ibc-core/ics02-client/Cargo.toml b/crates/ibc-core/ics02-client/Cargo.toml new file mode 100644 index 000000000..51c83e1cf --- /dev/null +++ b/crates/ibc-core/ics02-client/Cargo.toml @@ -0,0 +1,76 @@ +[package] +name = "ibc-core-client" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "light-client"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, contains the implementation of ICS-02 Client Semantics and + re-exports essential data structures and domain types from `ibc-core-client-types` crate. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +prost = { workspace = true } + +# ibc dependencies +ibc-core-client-types = { workspace = true } +ibc-core-client-context = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-derive = { workspace = true } +ibc-primitives = { workspace = true } + +[features] +default = ["std"] +std = [ + "prost/std", + "ibc-core-client-types/std", + "ibc-core-client-context/std", + "ibc-core-commitment-types/std", + "ibc-core-host/std", + "ibc-core-handler-types/std", + "ibc-primitives/std", +] +serde = [ + "ibc-core-client-types/serde", + "ibc-core-client-context/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host/serde", + "ibc-core-handler-types/serde", + "ibc-primitives/serde", +] +borsh = [ + "ibc-core-client-types/borsh", + "ibc-core-client-context/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host/borsh", + "ibc-core-handler-types/borsh", + "ibc-primitives/borsh", +] +schema = [ + "ibc-core-client-types/schema", + "ibc-core-client-context/schema", + "ibc-core-commitment-types/schema", + "ibc-core-host/schema", + "ibc-core-handler-types/schema", + "ibc-primitives/schema", + "serde", + "std" +] +parity-scale-codec = [ + "ibc-core-client-types/parity-scale-codec", + "ibc-core-client-context/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] diff --git a/crates/ibc-core/ics02-client/context/Cargo.toml b/crates/ibc-core/ics02-client/context/Cargo.toml new file mode 100644 index 000000000..06a23157b --- /dev/null +++ b/crates/ibc-core/ics02-client/context/Cargo.toml @@ -0,0 +1,81 @@ +[package] +name = "ibc-core-client-context" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc"] +readme = "./../README.md" +description = """ + Maintaind by `ibc-rs`, contains essential APIs to interface with the host chain's store, + enabling smooth client state transitions. Additionally, provides necessary traits for + implementing custom IBC light clients. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-core-client-types = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-derive = { workspace = true } +ibc-primitives = { workspace = true } + +# cosmos dependencies +tendermint = { workspace = true } + +[dev-dependencies] +ibc-testkit = { workspace = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "subtle-encoding/std", + "ibc-core-client-types/std", + "ibc-core-commitment-types/std", + "ibc-core-host-types/std", + "ibc-core-handler-types/std", + "ibc-primitives/std", + "tendermint/std", +] +serde = [ + "ibc-core-client-types/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host-types/serde", + "ibc-core-handler-types/serde", + "ibc-primitives/serde", +] +borsh = [ + "ibc-core-client-types/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host-types/borsh", + "ibc-core-handler-types/borsh", + "ibc-primitives/borsh", +] +schema = [ + "ibc-core-client-types/schema", + "ibc-core-host-types/schema", + "ibc-core-handler-types/schema", + "serde", + "std" +] +parity-scale-codec = [ + "ibc-core-client-types/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] diff --git a/crates/ibc/src/core/ics02_client/client_state.rs b/crates/ibc-core/ics02-client/context/src/client_state.rs similarity index 80% rename from crates/ibc/src/core/ics02_client/client_state.rs rename to crates/ibc-core/ics02-client/context/src/client_state.rs index 05ee1e37b..e671c0319 100644 --- a/crates/ibc/src/core/ics02_client/client_state.rs +++ b/crates/ibc-core/ics02-client/context/src/client_state.rs @@ -1,66 +1,16 @@ //! Defines `ClientState`, the core type to be implemented by light clients -use core::fmt::{Debug, Display, Formatter}; use core::marker::{Send, Sync}; -use ibc_proto::google::protobuf::Any; - -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics02_client::ClientExecutionContext; -use crate::core::ics23_commitment::commitment::{ +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::{Height, Status, UpdateKind}; +use ibc_core_commitment_types::commitment::{ CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, }; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::ics24_host::path::Path; -use crate::prelude::*; -use crate::Height; - -/// `UpdateKind` represents the 2 ways that a client can be updated -/// in IBC: either through a `MsgUpdateClient`, or a `MsgSubmitMisbehaviour`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum UpdateKind { - /// this is the typical scenario where a new header is submitted to the client - /// to update the client. Note that light clients are free to define the type - /// of the object used to update them (e.g. could be a list of headers). - UpdateClient, - /// this is the scenario where misbehaviour is submitted to the client - /// (e.g 2 headers with the same height in Tendermint) - SubmitMisbehaviour, -} - -/// Represents the status of a client -#[derive(Debug, PartialEq, Eq)] -pub enum Status { - /// The client is active and allowed to be used - Active, - /// The client is frozen and not allowed to be used - Frozen, - /// The client is expired and not allowed to be used - Expired, - /// Unauthorized indicates that the client type is not registered as an allowed client type. - Unauthorized, -} - -impl Status { - pub fn is_active(&self) -> bool { - *self == Status::Active - } - - pub fn is_frozen(&self) -> bool { - *self == Status::Frozen - } - - pub fn is_expired(&self) -> bool { - *self == Status::Expired - } -} - -impl Display for Status { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!(f, "{self:?}") - } -} +use ibc_core_host_types::identifiers::{ClientId, ClientType}; +use ibc_core_host_types::path::Path; +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Any; /// `ClientState` methods needed in both validation and execution. /// @@ -242,7 +192,7 @@ where /// `ClientExecutionContext` (e.g. `MyType` would not be supported). pub use ibc_derive::ClientState; -use super::ClientValidationContext; +use crate::context::{ClientExecutionContext, ClientValidationContext}; /// Primary client trait. Defines all the methods that clients must implement. /// diff --git a/crates/ibc/src/core/ics02_client/consensus_state.rs b/crates/ibc-core/ics02-client/context/src/consensus_state.rs similarity index 88% rename from crates/ibc/src/core/ics02_client/consensus_state.rs rename to crates/ibc-core/ics02-client/context/src/consensus_state.rs index ea5e05e37..8331428a5 100644 --- a/crates/ibc/src/core/ics02_client/consensus_state.rs +++ b/crates/ibc-core/ics02-client/context/src/consensus_state.rs @@ -2,13 +2,12 @@ use core::marker::{Send, Sync}; +use ibc_core_commitment_types::commitment::CommitmentRoot; /// Derive macro that implements [`ConsensusState`] for enums containing /// variants that implement [`ConsensusState`] pub use ibc_derive::ConsensusState; - -use crate::core::ics23_commitment::commitment::CommitmentRoot; -use crate::core::timestamp::Timestamp; -use crate::prelude::*; +use ibc_primitives::prelude::*; +use ibc_primitives::Timestamp; /// Defines methods that all `ConsensusState`s should provide. /// diff --git a/crates/ibc/src/core/ics02_client/context.rs b/crates/ibc-core/ics02-client/context/src/context.rs similarity index 90% rename from crates/ibc/src/core/ics02_client/context.rs rename to crates/ibc-core/ics02-client/context/src/context.rs index 093cdf610..368e2c446 100644 --- a/crates/ibc/src/core/ics02_client/context.rs +++ b/crates/ibc-core/ics02-client/context/src/context.rs @@ -1,14 +1,15 @@ +use ibc_core_client_types::Height; +use ibc_core_handler_types::error::ContextError; +use ibc_core_host_types::identifiers::ClientId; +use ibc_core_host_types::path::{ClientConsensusStatePath, ClientStatePath}; +use ibc_primitives::Timestamp; + use super::client_state::ClientState; use super::consensus_state::ConsensusState; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::ics24_host::path::{ClientConsensusStatePath, ClientStatePath}; -use crate::core::timestamp::Timestamp; -use crate::core::ContextError; -use crate::Height; /// Defines the methods available to clients for validating client state /// transitions. The generic `V` parameter in -/// [crate::core::ics02_client::client_state::ClientStateValidation] must +/// [crate::client_state::ClientStateValidation] must /// inherit from this trait. pub trait ClientValidationContext { /// Returns the time when the client state for the given [`ClientId`] was updated with a header for the given [`Height`] @@ -28,7 +29,7 @@ pub trait ClientValidationContext { /// Defines the methods that all client `ExecutionContext`s (precisely the /// generic parameter of -/// [`crate::core::ics02_client::client_state::ClientStateExecution`] ) must +/// [`crate::client_state::ClientStateExecution`] ) must /// implement. /// /// Specifically, clients have the responsibility to store their client state diff --git a/crates/ibc-core/ics02-client/context/src/lib.rs b/crates/ibc-core/ics02-client/context/src/lib.rs new file mode 100644 index 000000000..d1aaa5ebc --- /dev/null +++ b/crates/ibc-core/ics02-client/context/src/lib.rs @@ -0,0 +1,30 @@ +//! This crate functions as an intermediary layer between the storage of host +//! chains and an IBC client implementation, providing developers with necessary +//! traits to craft their custom light clients. It streamlines the process of +//! integrating light clients with the host, enabling interaction with the store +//! for pertinent client state transitions. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +pub mod client_state; +pub mod consensus_state; + +mod context; +pub use context::*; + +pub mod types { + #[doc(inline)] + pub use ibc_core_client_types::*; +} diff --git a/crates/ibc/src/core/ics02_client/handler/create_client.rs b/crates/ibc-core/ics02-client/src/handler/create_client.rs similarity index 75% rename from crates/ibc/src/core/ics02_client/handler/create_client.rs rename to crates/ibc-core/ics02-client/src/handler/create_client.rs index 342fefb16..c4624fefb 100644 --- a/crates/ibc/src/core/ics02_client/handler/create_client.rs +++ b/crates/ibc-core/ics02-client/src/handler/create_client.rs @@ -1,16 +1,16 @@ //! Protocol logic specific to processing ICS2 messages of type `MsgCreateClient`. -use crate::core::context::ContextError; -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateExecution}; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics02_client::events::CreateClient; -use crate::core::ics02_client::msgs::create_client::MsgCreateClient; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::{ExecutionContext, ValidationContext}; -use crate::prelude::*; - -pub(crate) fn validate(ctx: &Ctx, msg: MsgCreateClient) -> Result<(), ContextError> +use ibc_core_client_context::client_state::{ClientStateCommon, ClientStateExecution}; +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::events::CreateClient; +use ibc_core_client_types::msgs::MsgCreateClient; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::identifiers::ClientId; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_primitives::prelude::*; + +pub fn validate(ctx: &Ctx, msg: MsgCreateClient) -> Result<(), ContextError> where Ctx: ValidationContext, { @@ -46,7 +46,7 @@ where Ok(()) } -pub(crate) fn execute(ctx: &mut Ctx, msg: MsgCreateClient) -> Result<(), ContextError> +pub fn execute(ctx: &mut Ctx, msg: MsgCreateClient) -> Result<(), ContextError> where Ctx: ExecutionContext, { diff --git a/crates/ibc/src/core/ics02_client/handler.rs b/crates/ibc-core/ics02-client/src/handler/mod.rs similarity index 100% rename from crates/ibc/src/core/ics02_client/handler.rs rename to crates/ibc-core/ics02-client/src/handler/mod.rs diff --git a/crates/ibc/src/core/ics02_client/handler/update_client.rs b/crates/ibc-core/ics02-client/src/handler/update_client.rs similarity index 83% rename from crates/ibc/src/core/ics02_client/handler/update_client.rs rename to crates/ibc-core/ics02-client/src/handler/update_client.rs index f4ce3013d..8970bc527 100644 --- a/crates/ibc/src/core/ics02_client/handler/update_client.rs +++ b/crates/ibc-core/ics02-client/src/handler/update_client.rs @@ -1,19 +1,19 @@ //! Protocol logic specific to processing ICS2 messages of type `MsgUpdateAnyClient`. -use prost::Message; - -use crate::core::context::ContextError; -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ - ClientStateCommon, ClientStateExecution, ClientStateValidation, UpdateKind, +use ibc_core_client_context::client_state::{ + ClientStateCommon, ClientStateExecution, ClientStateValidation, }; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics02_client::events::{ClientMisbehaviour, UpdateClient}; -use crate::core::ics02_client::msgs::MsgUpdateOrMisbehaviour; -use crate::core::{ExecutionContext, ValidationContext}; -use crate::prelude::*; +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::events::{ClientMisbehaviour, UpdateClient}; +use ibc_core_client_types::msgs::MsgUpdateOrMisbehaviour; +use ibc_core_client_types::UpdateKind; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_primitives::prelude::*; +use prost::Message; -pub(crate) fn validate(ctx: &Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ContextError> +pub fn validate(ctx: &Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ContextError> where Ctx: ValidationContext, { @@ -47,7 +47,7 @@ where Ok(()) } -pub(crate) fn execute(ctx: &mut Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ContextError> +pub fn execute(ctx: &mut Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ContextError> where Ctx: ExecutionContext, { diff --git a/crates/ibc/src/core/ics02_client/handler/upgrade_client.rs b/crates/ibc-core/ics02-client/src/handler/upgrade_client.rs similarity index 68% rename from crates/ibc/src/core/ics02_client/handler/upgrade_client.rs rename to crates/ibc-core/ics02-client/src/handler/upgrade_client.rs index de5ebfbbd..f15c4ce99 100644 --- a/crates/ibc/src/core/ics02_client/handler/upgrade_client.rs +++ b/crates/ibc-core/ics02-client/src/handler/upgrade_client.rs @@ -1,19 +1,19 @@ //! Protocol logic specific to processing ICS2 messages of type `MsgUpgradeAnyClient`. //! -use crate::core::context::ContextError; -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ +use ibc_core_client_context::client_state::{ ClientStateCommon, ClientStateExecution, ClientStateValidation, }; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics02_client::events::UpgradeClient; -use crate::core::ics02_client::msgs::upgrade_client::MsgUpgradeClient; -use crate::core::ics24_host::path::ClientConsensusStatePath; -use crate::core::{ExecutionContext, ValidationContext}; -use crate::prelude::*; +use ibc_core_client_context::consensus_state::ConsensusState; +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::events::UpgradeClient; +use ibc_core_client_types::msgs::MsgUpgradeClient; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::path::ClientConsensusStatePath; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_primitives::prelude::*; -pub(crate) fn validate(ctx: &Ctx, msg: MsgUpgradeClient) -> Result<(), ContextError> +pub fn validate(ctx: &Ctx, msg: MsgUpgradeClient) -> Result<(), ContextError> where Ctx: ValidationContext, { @@ -35,12 +35,15 @@ where } // Read the latest consensus state from the host chain store. - let old_client_cons_state_path = - ClientConsensusStatePath::new(&client_id, &old_client_state.latest_height()); + let old_client_cons_state_path = ClientConsensusStatePath::new( + client_id.clone(), + old_client_state.latest_height().revision_number(), + old_client_state.latest_height().revision_height(), + ); let old_consensus_state = ctx .consensus_state(&old_client_cons_state_path) .map_err(|_| ClientError::ConsensusStateNotFound { - client_id: client_id.clone(), + client_id, height: old_client_state.latest_height(), })?; @@ -56,7 +59,7 @@ where Ok(()) } -pub(crate) fn execute(ctx: &mut Ctx, msg: MsgUpgradeClient) -> Result<(), ContextError> +pub fn execute(ctx: &mut Ctx, msg: MsgUpgradeClient) -> Result<(), ContextError> where Ctx: ExecutionContext, { diff --git a/crates/ibc-core/ics02-client/src/lib.rs b/crates/ibc-core/ics02-client/src/lib.rs new file mode 100644 index 000000000..b692624c8 --- /dev/null +++ b/crates/ibc-core/ics02-client/src/lib.rs @@ -0,0 +1,31 @@ +//! ICS-02: Client Semantics implementation for verifying remote IBC-enabled chains, +//! along with re-exporting data structures from `ibc-core-client-types` crate. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +pub mod handler; + +/// Re-exports ICS-02 traits from `ibc-core-client-context` for custom IBC +/// client implementation. +pub mod context { + #[doc(inline)] + pub use ibc_core_client_context::*; +} + +/// Re-exports ICS-02 data structures from the `ibc-core-client-types` crate. +pub mod types { + #[doc(inline)] + pub use ibc_core_client_types::*; +} diff --git a/crates/ibc-core/ics02-client/types/Cargo.toml b/crates/ibc-core/ics02-client/types/Cargo.toml new file mode 100644 index 000000000..eaea18e03 --- /dev/null +++ b/crates/ibc-core/ics02-client/types/Cargo.toml @@ -0,0 +1,88 @@ +[package] +name = "ibc-core-client-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "types"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, encapsulates essential ICS-02 Client Semantics data structures and domain types, + as specified in the Inter-Blockchain Communication (IBC) protocol. Designed for universal applicability + to facilitate development and integration across diverse IBC-enabled projects. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +schemars = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-core-commitment-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-primitives = { workspace = true } +ibc-proto = { workspace = true } + +# cosmos dependencies +tendermint = { workspace = true } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[dev-dependencies] +ibc-testkit = { workspace = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "serde/std", + "subtle-encoding/std", + "ibc-core-commitment-types/std", + "ibc-core-host-types/std", + "ibc-primitives/std", + "ibc-proto/std", + "tendermint/std", +] +serde = [ + "ibc-core-host-types/serde", + "ibc-core-commitment-types/serde", + "ibc-primitives/serde", + "ibc-proto/serde", + "dep:serde", +] +borsh = [ + "dep:borsh", + "ibc-core-host-types/borsh", + "ibc-core-commitment-types/borsh", + "ibc-primitives/borsh", + "ibc-proto/borsh", +] +schema = [ + "dep:schemars", + "ibc-core-host-types/schema", + "ibc-core-commitment-types/schema", + "ibc-primitives/schema", + "ibc-proto/json-schema", + "serde", + "std" +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] diff --git a/crates/ibc/src/core/ics02_client/error.rs b/crates/ibc-core/ics02-client/types/src/error.rs similarity index 90% rename from crates/ibc/src/core/ics02_client/error.rs rename to crates/ibc-core/ics02-client/types/src/error.rs index f9b79f194..ab40103f1 100644 --- a/crates/ibc/src/core/ics02_client/error.rs +++ b/crates/ibc-core/ics02-client/types/src/error.rs @@ -1,15 +1,15 @@ //! Defines the client error type use displaydoc::Display; +// use ibc::core::ContextError; +use ibc_core_commitment_types::error::CommitmentError; +use ibc_core_host_types::error::IdentifierError; +use ibc_core_host_types::identifiers::{ClientId, ClientType}; +use ibc_primitives::prelude::*; +use ibc_primitives::Timestamp; -use super::client_state::Status; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics23_commitment::error::CommitmentError; -use crate::core::ics24_host::identifier::{ClientId, IdentifierError}; -use crate::core::timestamp::Timestamp; -use crate::core::ContextError; -use crate::prelude::*; -use crate::Height; +use super::status::Status; +use crate::height::Height; /// Encodes all the possible client errors #[derive(Debug, Display)] @@ -84,7 +84,7 @@ pub enum ClientError { /// invalid commitment proof bytes error: `{0}` InvalidCommitmentProof(CommitmentError), /// invalid packet timeout timestamp value error: `{0}` - InvalidPacketTimestamp(crate::core::timestamp::ParseTimestampError), + InvalidPacketTimestamp(ibc_primitives::ParseTimestampError), /// mismatch between client and arguments types ClientArgsTypeMismatch { client_type: ClientType }, /// received header height (`{header_height}`) is lower than (or equal to) client latest height (`{latest_height}`) @@ -110,17 +110,6 @@ pub enum ClientError { Other { description: String }, } -impl From for ClientError { - fn from(context_error: ContextError) -> Self { - match context_error { - ContextError::ClientError(e) => e, - _ => ClientError::Other { - description: context_error.to_string(), - }, - } - } -} - impl From<&'static str> for ClientError { fn from(s: &'static str) -> Self { Self::Other { diff --git a/crates/ibc/src/core/ics02_client/events.rs b/crates/ibc-core/ics02-client/types/src/events.rs similarity index 98% rename from crates/ibc/src/core/ics02_client/events.rs rename to crates/ibc-core/ics02-client/types/src/events.rs index e55bb9017..31625757b 100644 --- a/crates/ibc/src/core/ics02_client/events.rs +++ b/crates/ibc-core/ics02-client/types/src/events.rs @@ -1,12 +1,11 @@ //! Types for the IBC events emitted from Tendermint Websocket by the client module. use derive_more::From; +use ibc_core_host_types::identifiers::{ClientId, ClientType}; +use ibc_primitives::prelude::*; use subtle_encoding::hex; use tendermint::abci; -use crate::core::ics02_client::client_type::ClientType; -use crate::core::ics02_client::height::Height; -use crate::core::ics24_host::identifier::ClientId; -use crate::prelude::*; +use crate::height::Height; /// Client event types const CREATE_CLIENT_EVENT: &str = "create_client"; @@ -420,7 +419,7 @@ impl From for abci::Event { #[cfg(test)] mod tests { - use std::str::FromStr; + use core::str::FromStr; use ibc_proto::google::protobuf::Any; use ibc_testkit::utils::clients::mock::dummy_new_mock_header; diff --git a/crates/ibc/src/core/ics02_client/height.rs b/crates/ibc-core/ics02-client/types/src/height.rs similarity index 98% rename from crates/ibc/src/core/ics02_client/height.rs rename to crates/ibc-core/ics02-client/types/src/height.rs index fbdf42def..889c47c81 100644 --- a/crates/ibc/src/core/ics02_client/height.rs +++ b/crates/ibc-core/ics02-client/types/src/height.rs @@ -5,11 +5,11 @@ use core::num::ParseIntError; use core::str::FromStr; use displaydoc::Display; +use ibc_primitives::prelude::*; use ibc_proto::ibc::core::client::v1::Height as RawHeight; use ibc_proto::Protobuf; -use crate::core::ics02_client::error::ClientError; -use crate::prelude::*; +use crate::error::ClientError; /// The core IBC height type, which represents the height of a chain, /// which typically is the number of blocks since genesis diff --git a/crates/ibc-core/ics02-client/types/src/lib.rs b/crates/ibc-core/ics02-client/types/src/lib.rs new file mode 100644 index 000000000..f7c1f9593 --- /dev/null +++ b/crates/ibc-core/ics02-client/types/src/lib.rs @@ -0,0 +1,29 @@ +//! Implementation of the Client Semantics (ICS-02) data structures. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +pub mod error; +pub mod events; +mod height; +pub mod msgs; +mod status; + +pub use height::*; +pub use status::*; + +/// Re-exports ICS-02 proto types from the `ibc-proto` crate for added convenience. +pub mod proto { + pub use ibc_proto::ibc::core::client::*; +} diff --git a/crates/ibc/src/core/ics02_client/msgs/create_client.rs b/crates/ibc-core/ics02-client/types/src/msgs/create_client.rs similarity index 88% rename from crates/ibc/src/core/ics02_client/msgs/create_client.rs rename to crates/ibc-core/ics02-client/types/src/msgs/create_client.rs index 9e1e6af13..7c3347980 100644 --- a/crates/ibc/src/core/ics02_client/msgs/create_client.rs +++ b/crates/ibc-core/ics02-client/types/src/msgs/create_client.rs @@ -1,15 +1,14 @@ //! Definition of domain type message `MsgCreateClient`. +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::MsgCreateClient as RawMsgCreateClient; use ibc_proto::Protobuf; -use crate::core::ics02_client::error::ClientError; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; +use crate::error::ClientError; -pub(crate) const TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient"; +pub const CREATE_CLIENT_TYPE_URL: &str = "/ibc.core.client.v1.MsgCreateClient"; /// A type of message that triggers the creation of a new on-chain (IBC) client. #[cfg_attr( @@ -38,7 +37,7 @@ impl Msg for MsgCreateClient { type Raw = RawMsgCreateClient; fn type_url(&self) -> String { - TYPE_URL.to_string() + CREATE_CLIENT_TYPE_URL.to_string() } } @@ -77,9 +76,8 @@ mod tests { use ibc_proto::ibc::core::client::v1::MsgCreateClient as RawMsgCreateClient; use ibc_testkit::utils::core::client::dummy_raw_msg_create_client; - use test_log::test; - use crate::core::ics02_client::msgs::create_client::MsgCreateClient; + use crate::msgs::create_client::MsgCreateClient; #[test] fn msg_create_client_serialization() { diff --git a/crates/ibc/src/core/ics02_client/msgs/misbehaviour.rs b/crates/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs similarity index 86% rename from crates/ibc/src/core/ics02_client/msgs/misbehaviour.rs rename to crates/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs index 925bd69f9..d33651821 100644 --- a/crates/ibc/src/core/ics02_client/msgs/misbehaviour.rs +++ b/crates/ibc-core/ics02-client/types/src/msgs/misbehaviour.rs @@ -1,16 +1,15 @@ //! Definition of domain type message `MsgSubmitMisbehaviour`. +use ibc_core_host_types::identifiers::ClientId; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::google::protobuf::Any as ProtoAny; use ibc_proto::ibc::core::client::v1::MsgSubmitMisbehaviour as RawMsgSubmitMisbehaviour; use ibc_proto::Protobuf; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; +use crate::error::ClientError; -pub(crate) const TYPE_URL: &str = "/ibc.core.client.v1.MsgSubmitMisbehaviour"; +pub const SUBMIT_MISBEHAVIOUR_TYPE_URL: &str = "/ibc.core.client.v1.MsgSubmitMisbehaviour"; /// A type of message that submits client misbehaviour proof. #[cfg_attr( @@ -32,7 +31,7 @@ impl Msg for MsgSubmitMisbehaviour { type Raw = RawMsgSubmitMisbehaviour; fn type_url(&self) -> String { - TYPE_URL.to_string() + SUBMIT_MISBEHAVIOUR_TYPE_URL.to_string() } } diff --git a/crates/ibc/src/core/ics02_client/msgs.rs b/crates/ibc-core/ics02-client/types/src/msgs/mod.rs similarity index 65% rename from crates/ibc/src/core/ics02_client/msgs.rs rename to crates/ibc-core/ics02-client/types/src/msgs/mod.rs index 22140248f..33330a77d 100644 --- a/crates/ibc/src/core/ics02_client/msgs.rs +++ b/crates/ibc-core/ics02-client/types/src/msgs/mod.rs @@ -1,18 +1,18 @@ //! Defines the client message types that are sent to the chain by the relayer. +use ibc_core_host_types::identifiers::ClientId; +use ibc_primitives::prelude::*; +use ibc_primitives::Signer; use ibc_proto::google::protobuf::Any; -use crate::core::ics02_client::msgs::create_client::MsgCreateClient; -use crate::core::ics02_client::msgs::misbehaviour::MsgSubmitMisbehaviour; -use crate::core::ics02_client::msgs::update_client::MsgUpdateClient; -use crate::core::ics02_client::msgs::upgrade_client::MsgUpgradeClient; -use crate::core::ics24_host::identifier::ClientId; -use crate::prelude::*; -use crate::signer::Signer; +mod create_client; +mod misbehaviour; +mod update_client; +mod upgrade_client; -pub mod create_client; -pub mod misbehaviour; -pub mod update_client; -pub mod upgrade_client; +pub use create_client::*; +pub use misbehaviour::*; +pub use update_client::*; +pub use upgrade_client::*; /// Encodes all the different client messages #[allow(dead_code)] @@ -29,27 +29,27 @@ pub enum ClientMsg { UpgradeClient(MsgUpgradeClient), } -pub(crate) enum MsgUpdateOrMisbehaviour { +pub enum MsgUpdateOrMisbehaviour { UpdateClient(MsgUpdateClient), Misbehaviour(MsgSubmitMisbehaviour), } impl MsgUpdateOrMisbehaviour { - pub(crate) fn client_id(&self) -> &ClientId { + pub fn client_id(&self) -> &ClientId { match self { MsgUpdateOrMisbehaviour::UpdateClient(msg) => &msg.client_id, MsgUpdateOrMisbehaviour::Misbehaviour(msg) => &msg.client_id, } } - pub(crate) fn client_message(self) -> Any { + pub fn client_message(self) -> Any { match self { MsgUpdateOrMisbehaviour::UpdateClient(msg) => msg.client_message, MsgUpdateOrMisbehaviour::Misbehaviour(msg) => msg.misbehaviour, } } - pub(crate) fn signer(&self) -> &Signer { + pub fn signer(&self) -> &Signer { match self { MsgUpdateOrMisbehaviour::UpdateClient(msg) => &msg.signer, MsgUpdateOrMisbehaviour::Misbehaviour(msg) => &msg.signer, diff --git a/crates/ibc/src/core/ics02_client/msgs/update_client.rs b/crates/ibc-core/ics02-client/types/src/msgs/update_client.rs similarity index 86% rename from crates/ibc/src/core/ics02_client/msgs/update_client.rs rename to crates/ibc-core/ics02-client/types/src/msgs/update_client.rs index 9c19e77d2..60c70cfc2 100644 --- a/crates/ibc/src/core/ics02_client/msgs/update_client.rs +++ b/crates/ibc-core/ics02-client/types/src/msgs/update_client.rs @@ -1,16 +1,15 @@ //! Definition of domain type message `MsgUpdateClient`. +use ibc_core_host_types::identifiers::ClientId; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::MsgUpdateClient as RawMsgUpdateClient; use ibc_proto::Protobuf; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; +use crate::error::ClientError; -pub(crate) const TYPE_URL: &str = "/ibc.core.client.v1.MsgUpdateClient"; +pub const UPDATE_CLIENT_TYPE_URL: &str = "/ibc.core.client.v1.MsgUpdateClient"; /// Represents the message that triggers the update of an on-chain (IBC) client /// either with new headers, or evidence of misbehaviour. @@ -32,7 +31,7 @@ impl Msg for MsgUpdateClient { type Raw = RawMsgUpdateClient; fn type_url(&self) -> String { - TYPE_URL.to_string() + UPDATE_CLIENT_TYPE_URL.to_string() } } @@ -69,10 +68,9 @@ impl From for RawMsgUpdateClient { mod tests { use ibc_proto::ibc::core::client::v1::MsgUpdateClient as RawMsgUpdateClient; use ibc_testkit::utils::core::client::dummy_raw_msg_update_client; - use test_log::test; use super::*; - use crate::core::ics02_client::msgs::MsgUpdateClient; + use crate::msgs::MsgUpdateClient; #[test] fn msg_update_client_serialization() { diff --git a/crates/ibc/src/core/ics02_client/msgs/upgrade_client.rs b/crates/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs similarity index 88% rename from crates/ibc/src/core/ics02_client/msgs/upgrade_client.rs rename to crates/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs index baf363b38..2175a3cb4 100644 --- a/crates/ibc/src/core/ics02_client/msgs/upgrade_client.rs +++ b/crates/ibc-core/ics02-client/types/src/msgs/upgrade_client.rs @@ -2,19 +2,18 @@ use core::str::FromStr; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_commitment_types::error::CommitmentError; +use ibc_core_host_types::identifiers::ClientId; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::MsgUpgradeClient as RawMsgUpgradeClient; use ibc_proto::Protobuf; -use crate::core::ics02_client::error::{ClientError, UpgradeClientError}; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics23_commitment::error::CommitmentError; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; +use crate::error::{ClientError, UpgradeClientError}; -pub(crate) const TYPE_URL: &str = "/ibc.core.client.v1.MsgUpgradeClient"; +pub const UPGRADE_CLIENT_TYPE_URL: &str = "/ibc.core.client.v1.MsgUpgradeClient"; /// A type of message that triggers the upgrade of an on-chain (IBC) client. #[cfg_attr( @@ -43,7 +42,7 @@ impl Msg for MsgUpgradeClient { type Raw = RawMsgUpgradeClient; fn type_url(&self) -> String { - TYPE_URL.to_string() + UPGRADE_CLIENT_TYPE_URL.to_string() } } @@ -102,7 +101,7 @@ mod tests { use ibc_proto::ibc::core::client::v1::MsgUpgradeClient as RawMsgUpgradeClient; use ibc_testkit::utils::core::client::dummy_raw_msg_upgrade_client; - use crate::core::ics02_client::msgs::upgrade_client::MsgUpgradeClient; + use crate::msgs::upgrade_client::MsgUpgradeClient; #[test] fn msg_upgrade_client_serialization() { diff --git a/crates/ibc-core/ics02-client/types/src/status.rs b/crates/ibc-core/ics02-client/types/src/status.rs new file mode 100644 index 000000000..b15ed61e7 --- /dev/null +++ b/crates/ibc-core/ics02-client/types/src/status.rs @@ -0,0 +1,47 @@ +use core::fmt::{Debug, Display, Formatter}; + +/// `UpdateKind` represents the 2 ways that a client can be updated +/// in IBC: either through a `MsgUpdateClient`, or a `MsgSubmitMisbehaviour`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum UpdateKind { + /// this is the typical scenario where a new header is submitted to the client + /// to update the client. Note that light clients are free to define the type + /// of the object used to update them (e.g. could be a list of headers). + UpdateClient, + /// this is the scenario where misbehaviour is submitted to the client + /// (e.g 2 headers with the same height in Tendermint) + SubmitMisbehaviour, +} + +/// Represents the status of a client +#[derive(Debug, PartialEq, Eq)] +pub enum Status { + /// The client is active and allowed to be used + Active, + /// The client is frozen and not allowed to be used + Frozen, + /// The client is expired and not allowed to be used + Expired, + /// Unauthorized indicates that the client type is not registered as an allowed client type. + Unauthorized, +} + +impl Status { + pub fn is_active(&self) -> bool { + *self == Status::Active + } + + pub fn is_frozen(&self) -> bool { + *self == Status::Frozen + } + + pub fn is_expired(&self) -> bool { + *self == Status::Expired + } +} + +impl Display for Status { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + write!(f, "{self:?}") + } +} diff --git a/crates/ibc-core/ics03-connection/Cargo.toml b/crates/ibc-core/ics03-connection/Cargo.toml new file mode 100644 index 000000000..a123f584f --- /dev/null +++ b/crates/ibc-core/ics03-connection/Cargo.toml @@ -0,0 +1,66 @@ +[package] +name = "ibc-core-connection" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "connection"] +readme = "./../README.md" +description = """ + Maintained by `ibc-rs`, contains the implementation of the ICS-03 Connection Semantics and + re-exports essential data structures and domain types from `ibc-core-connection-types` crate. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +prost = { workspace = true } + +# ibc dependencies +ibc-core-client = { workspace = true } +ibc-core-connection-types = { workspace = true } +ibc-core-host = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-primitives = { workspace = true } + +[features] +default = ["std"] +std = [ + "prost/std", + "ibc-core-client/std", + "ibc-core-connection-types/std", + "ibc-core-host/std", + "ibc-core-handler-types/std", + "ibc-primitives/std", +] +serde = [ + "ibc-core-client/serde", + "ibc-core-connection-types/serde", + "ibc-core-host/serde", + "ibc-core-handler-types/serde", + "ibc-primitives/serde", +] +schema = [ + "ibc-core-client/schema", + "ibc-core-connection-types/schema", + "ibc-core-host/schema", + "ibc-primitives/schema", + "serde", + "std" +] +borsh = [ + "ibc-core-client/borsh", + "ibc-core-host/borsh", + "ibc-core-handler-types/borsh", + "ibc-primitives/borsh", +] +parity-scale-codec = [ + "ibc-core-client/parity-scale-codec", + "ibc-core-host/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] \ No newline at end of file diff --git a/crates/ibc/src/core/ics03_connection/delay.rs b/crates/ibc-core/ics03-connection/src/delay.rs similarity index 87% rename from crates/ibc/src/core/ics03_connection/delay.rs rename to crates/ibc-core/ics03-connection/src/delay.rs index 9b3865fac..d573a6eac 100644 --- a/crates/ibc/src/core/ics03_connection/delay.rs +++ b/crates/ibc-core/ics03-connection/src/delay.rs @@ -1,8 +1,9 @@ -use super::connection::ConnectionEnd; -use super::error::ConnectionError; -use crate::core::ics02_client::height::Height; -use crate::core::ics02_client::ClientValidationContext; -use crate::core::{ContextError, ValidationContext}; +use ibc_core_client::context::ClientValidationContext; +use ibc_core_client::types::Height; +use ibc_core_connection_types::error::ConnectionError; +use ibc_core_connection_types::ConnectionEnd; +use ibc_core_handler_types::error::ContextError; +use ibc_core_host::ValidationContext; pub fn verify_conn_delay_passed( ctx: &Ctx, diff --git a/crates/ibc/src/core/ics03_connection/handler/conn_open_ack.rs b/crates/ibc-core/ics03-connection/src/handler/conn_open_ack.rs similarity index 79% rename from crates/ibc/src/core/ics03_connection/handler/conn_open_ack.rs rename to crates/ibc-core/ics03-connection/src/handler/conn_open_ack.rs index cdc137d66..af44a4ee9 100644 --- a/crates/ibc/src/core/ics03_connection/handler/conn_open_ack.rs +++ b/crates/ibc-core/ics03-connection/src/handler/conn_open_ack.rs @@ -1,25 +1,22 @@ //! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenAck`. -use ibc_proto::Protobuf; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection_types::error::ConnectionError; +use ibc_core_connection_types::events::OpenAck; +use ibc_core_connection_types::msgs::MsgConnectionOpenAck; +use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::identifiers::ClientId; +use ibc_core_host::types::path::{ClientConsensusStatePath, ClientStatePath, ConnectionPath, Path}; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Protobuf; use prost::Message; -use crate::core::context::ContextError; -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics03_connection::events::OpenAck; -use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::ics24_host::path::{ - ClientConsensusStatePath, ClientStatePath, ConnectionPath, Path, -}; -use crate::core::{ExecutionContext, ValidationContext}; -use crate::prelude::*; - -pub(crate) fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenAck) -> Result<(), ContextError> +pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenAck) -> Result<(), ContextError> where Ctx: ValidationContext, { @@ -68,8 +65,12 @@ where } client_state_of_b_on_a.validate_proof_height(msg.proofs_height_on_b)?; - let client_cons_state_path_on_a = - ClientConsensusStatePath::new(vars.client_id_on_a(), &msg.proofs_height_on_b); + let client_cons_state_path_on_a = ClientConsensusStatePath::new( + vars.client_id_on_a().clone(), + msg.proofs_height_on_b.revision_number(), + msg.proofs_height_on_b.revision_height(), + ); + let consensus_state_of_b_on_a = ctx_a.consensus_state(&client_cons_state_path_on_a)?; let prefix_on_a = ctx_a.commitment_prefix(); @@ -115,8 +116,11 @@ where let expected_consensus_state_of_a_on_b = ctx_a.host_consensus_state(&msg.consensus_height_of_a_on_b)?; - let client_cons_state_path_on_b = - ClientConsensusStatePath::new(vars.client_id_on_b(), &msg.consensus_height_of_a_on_b); + let client_cons_state_path_on_b = ClientConsensusStatePath::new( + vars.client_id_on_b().clone(), + msg.consensus_height_of_a_on_b.revision_number(), + msg.consensus_height_of_a_on_b.revision_height(), + ); client_state_of_b_on_a .verify_membership( @@ -135,7 +139,7 @@ where Ok(()) } -pub(crate) fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenAck) -> Result<(), ContextError> +pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenAck) -> Result<(), ContextError> where Ctx: ExecutionContext, { diff --git a/crates/ibc/src/core/ics03_connection/handler/conn_open_confirm.rs b/crates/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs similarity index 77% rename from crates/ibc/src/core/ics03_connection/handler/conn_open_confirm.rs rename to crates/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs index 83392ff6d..a6a53f6e9 100644 --- a/crates/ibc/src/core/ics03_connection/handler/conn_open_confirm.rs +++ b/crates/ibc-core/ics03-connection/src/handler/conn_open_confirm.rs @@ -1,22 +1,21 @@ //! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenConfirm`. -use ibc_proto::Protobuf; - -use crate::core::context::ContextError; -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics03_connection::events::OpenConfirm; -use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::core::ics24_host::path::{ClientConsensusStatePath, ConnectionPath, Path}; -use crate::core::{ExecutionContext, ValidationContext}; -use crate::prelude::*; - -pub(crate) fn validate(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), ContextError> +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection_types::error::ConnectionError; +use ibc_core_connection_types::events::OpenConfirm; +use ibc_core_connection_types::msgs::MsgConnectionOpenConfirm; +use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::identifiers::{ClientId, ConnectionId}; +use ibc_core_host::types::path::{ClientConsensusStatePath, ConnectionPath, Path}; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Protobuf; + +pub fn validate(ctx_b: &Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), ContextError> where Ctx: ValidationContext, { @@ -55,8 +54,11 @@ where } client_state_of_a_on_b.validate_proof_height(msg.proof_height_on_a)?; - let client_cons_state_path_on_b = - ClientConsensusStatePath::new(client_id_on_b, &msg.proof_height_on_a); + let client_cons_state_path_on_b = ClientConsensusStatePath::new( + client_id_on_b.clone(), + msg.proof_height_on_a.revision_number(), + msg.proof_height_on_a.revision_height(), + ); let consensus_state_of_a_on_b = ctx_b.consensus_state(&client_cons_state_path_on_b)?; let prefix_on_a = conn_end_on_b.counterparty().prefix(); @@ -88,10 +90,7 @@ where Ok(()) } -pub(crate) fn execute( - ctx_b: &mut Ctx, - msg: &MsgConnectionOpenConfirm, -) -> Result<(), ContextError> +pub fn execute(ctx_b: &mut Ctx, msg: &MsgConnectionOpenConfirm) -> Result<(), ContextError> where Ctx: ExecutionContext, { diff --git a/crates/ibc/src/core/ics03_connection/handler/conn_open_init.rs b/crates/ibc-core/ics03-connection/src/handler/conn_open_init.rs similarity index 72% rename from crates/ibc/src/core/ics03_connection/handler/conn_open_init.rs rename to crates/ibc-core/ics03-connection/src/handler/conn_open_init.rs index f1ba3c95a..b7deac746 100644 --- a/crates/ibc/src/core/ics03_connection/handler/conn_open_init.rs +++ b/crates/ibc-core/ics03-connection/src/handler/conn_open_init.rs @@ -1,17 +1,17 @@ //! Protocol logic specific to ICS3 messages of type `MsgConnectionOpenInit`. -use crate::core::context::ContextError; -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::ClientStateValidation; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::core::ics03_connection::events::OpenInit; -use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use crate::core::ics24_host::identifier::ConnectionId; -use crate::core::ics24_host::path::{ClientConnectionPath, ConnectionPath}; -use crate::core::{ExecutionContext, ValidationContext}; -use crate::prelude::*; +use ibc_core_client::context::client_state::ClientStateValidation; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection_types::events::OpenInit; +use ibc_core_connection_types::msgs::MsgConnectionOpenInit; +use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::identifiers::ConnectionId; +use ibc_core_host::types::path::{ClientConnectionPath, ConnectionPath}; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_primitives::prelude::*; -pub(crate) fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenInit) -> Result<(), ContextError> +pub fn validate(ctx_a: &Ctx, msg: MsgConnectionOpenInit) -> Result<(), ContextError> where Ctx: ValidationContext, { @@ -35,7 +35,7 @@ where Ok(()) } -pub(crate) fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenInit) -> Result<(), ContextError> +pub fn execute(ctx_a: &mut Ctx, msg: MsgConnectionOpenInit) -> Result<(), ContextError> where Ctx: ExecutionContext, { diff --git a/crates/ibc/src/core/ics03_connection/handler/conn_open_try.rs b/crates/ibc-core/ics03-connection/src/handler/conn_open_try.rs similarity index 80% rename from crates/ibc/src/core/ics03_connection/handler/conn_open_try.rs rename to crates/ibc-core/ics03-connection/src/handler/conn_open_try.rs index 965cd4b0d..6d70604f9 100644 --- a/crates/ibc/src/core/ics03_connection/handler/conn_open_try.rs +++ b/crates/ibc-core/ics03-connection/src/handler/conn_open_try.rs @@ -1,25 +1,23 @@ -//! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenTry`. - -use ibc_proto::Protobuf; -use prost::Message; - -use crate::core::context::ContextError; -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::{ConnectionEnd, Counterparty, State}; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics03_connection::events::OpenTry; -use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::core::ics24_host::path::{ +//! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenTry`.; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection_types::error::ConnectionError; +use ibc_core_connection_types::events::OpenTry; +use ibc_core_connection_types::msgs::MsgConnectionOpenTry; +use ibc_core_connection_types::{ConnectionEnd, Counterparty, State}; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::identifiers::{ClientId, ConnectionId}; +use ibc_core_host::types::path::{ ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, ConnectionPath, Path, }; -use crate::core::{ExecutionContext, ValidationContext}; -use crate::prelude::*; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Protobuf; +use prost::Message; -pub(crate) fn validate(ctx_b: &Ctx, msg: MsgConnectionOpenTry) -> Result<(), ContextError> +pub fn validate(ctx_b: &Ctx, msg: MsgConnectionOpenTry) -> Result<(), ContextError> where Ctx: ValidationContext, { @@ -66,8 +64,12 @@ where } client_state_of_a_on_b.validate_proof_height(msg.proofs_height_on_a)?; - let client_cons_state_path_on_b = - ClientConsensusStatePath::new(&msg.client_id_on_b, &msg.proofs_height_on_a); + let client_cons_state_path_on_b = ClientConsensusStatePath::new( + msg.client_id_on_b.clone(), + msg.proofs_height_on_a.revision_number(), + msg.proofs_height_on_a.revision_height(), + ); + let consensus_state_of_a_on_b = ctx_b.consensus_state(&client_cons_state_path_on_b)?; let prefix_on_a = vars.conn_end_on_b.counterparty().prefix(); @@ -109,8 +111,11 @@ where let expected_consensus_state_of_b_on_a = ctx_b.host_consensus_state(&msg.consensus_height_of_b_on_a)?; - let client_cons_state_path_on_a = - ClientConsensusStatePath::new(client_id_on_a, &msg.consensus_height_of_b_on_a); + let client_cons_state_path_on_a = ClientConsensusStatePath::new( + client_id_on_a.clone(), + msg.consensus_height_of_b_on_a.revision_number(), + msg.consensus_height_of_b_on_a.revision_height(), + ); client_state_of_a_on_b .verify_membership( @@ -129,7 +134,7 @@ where Ok(()) } -pub(crate) fn execute(ctx_b: &mut Ctx, msg: MsgConnectionOpenTry) -> Result<(), ContextError> +pub fn execute(ctx_b: &mut Ctx, msg: MsgConnectionOpenTry) -> Result<(), ContextError> where Ctx: ExecutionContext, { diff --git a/crates/ibc-core/ics03-connection/src/handler/mod.rs b/crates/ibc-core/ics03-connection/src/handler/mod.rs new file mode 100644 index 000000000..c504edc00 --- /dev/null +++ b/crates/ibc-core/ics03-connection/src/handler/mod.rs @@ -0,0 +1,4 @@ +pub mod conn_open_ack; +pub mod conn_open_confirm; +pub mod conn_open_init; +pub mod conn_open_try; diff --git a/crates/ibc-core/ics03-connection/src/lib.rs b/crates/ibc-core/ics03-connection/src/lib.rs new file mode 100644 index 000000000..0892189d1 --- /dev/null +++ b/crates/ibc-core/ics03-connection/src/lib.rs @@ -0,0 +1,26 @@ +//! ICS-03: Connection Semantics implementation to process connection open +//! handshake. Exports data structures and implementations of IBC core +//! connection module. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +pub mod delay; +pub mod handler; + +/// Re-exports ICS-03 data structures from the `ibc-core-connection-types` crate +pub mod types { + #[doc(inline)] + pub use ibc_core_connection_types::*; +} diff --git a/crates/ibc-core/ics03-connection/types/Cargo.toml b/crates/ibc-core/ics03-connection/types/Cargo.toml new file mode 100644 index 000000000..af90c2ea1 --- /dev/null +++ b/crates/ibc-core/ics03-connection/types/Cargo.toml @@ -0,0 +1,92 @@ +[package] +name = "ibc-core-connection-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "types"] +readme = "./../../README.md" +description = """ + Maintained by `ibc-rs`, encapsulates essential ICS-03 Connection Semantics data structures and domain types, + as specified in the Inter-Blockchain Communication (IBC) protocol. Designed for universal applicability + to facilitate development and integration across diverse IBC-enabled projects. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +schemars = { workspace = true, optional = true} +serde = { workspace = true, optional = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-core-client-types = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-primitives = { workspace = true } +ibc-proto = { workspace = true } + +# cosmos dependencies +tendermint = { workspace = true } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[dev-dependencies] +ibc-testkit = { workspace = true } +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "subtle-encoding/std", + "serde/std", + "ibc-core-client-types/std", + "ibc-core-commitment-types/std", + "ibc-core-host-types/std", + "ibc-primitives/std", + "ibc-proto/std", + "tendermint/std", +] +serde = [ + "dep:serde", + "ibc-core-client-types/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host-types/serde", + "ibc-primitives/serde", + "ibc-proto/serde", +] +schema = [ + "dep:schemars", + "ibc-core-client-types/schema", + "ibc-core-commitment-types/schema", + "ibc-core-host-types/schema", + "ibc-proto/json-schema", + "ibc-primitives/schema", + "serde", + "std" +] +borsh = [ + "dep:borsh", + "ibc-core-client-types/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host-types/borsh", + "ibc-primitives/borsh", +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-core-client-types/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] \ No newline at end of file diff --git a/crates/ibc/src/core/ics03_connection/connection.rs b/crates/ibc-core/ics03-connection/types/src/connection.rs similarity index 97% rename from crates/ibc/src/core/ics03_connection/connection.rs rename to crates/ibc-core/ics03-connection/types/src/connection.rs index ae989a9a0..2af44ec5f 100644 --- a/crates/ibc/src/core/ics03_connection/connection.rs +++ b/crates/ibc-core/ics03-connection/types/src/connection.rs @@ -4,19 +4,19 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::time::Duration; use core::u64; +use ibc_core_client_types::error::ClientError; +use ibc_core_commitment_types::commitment::CommitmentPrefix; +use ibc_core_host_types::identifiers::{ClientId, ConnectionId}; +use ibc_primitives::prelude::*; +use ibc_primitives::ZERO_DURATION; use ibc_proto::ibc::core::connection::v1::{ ConnectionEnd as RawConnectionEnd, Counterparty as RawCounterparty, IdentifiedConnection as RawIdentifiedConnection, }; use ibc_proto::Protobuf; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics03_connection::version::Version; -use crate::core::ics23_commitment::commitment::CommitmentPrefix; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::core::timestamp::ZERO_DURATION; -use crate::prelude::*; +use crate::error::ConnectionError; +use crate::version::Version; #[cfg_attr( feature = "parity-scale-codec", diff --git a/crates/ibc/src/core/ics03_connection/error.rs b/crates/ibc-core/ics03-connection/types/src/error.rs similarity index 92% rename from crates/ibc/src/core/ics03_connection/error.rs rename to crates/ibc-core/ics03-connection/types/src/error.rs index db7e95dd8..b9cb0460b 100644 --- a/crates/ibc/src/core/ics03_connection/error.rs +++ b/crates/ibc-core/ics03-connection/types/src/error.rs @@ -1,14 +1,13 @@ //! Defines the connection error type -use alloc::string::String; - use displaydoc::Display; +use ibc_core_client_types::{error as client_error, Height}; +use ibc_core_host_types::error::IdentifierError; +use ibc_core_host_types::identifiers::{ClientId, ConnectionId}; +use ibc_primitives::prelude::*; +use ibc_primitives::{Timestamp, TimestampOverflowError}; -use crate::core::ics02_client::error as client_error; -use crate::core::ics03_connection::version::Version; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId, IdentifierError}; -use crate::core::timestamp::{Timestamp, TimestampOverflowError}; -use crate::Height; +use crate::version::Version; #[derive(Debug, Display)] pub enum ConnectionError { diff --git a/crates/ibc/src/core/ics03_connection/events.rs b/crates/ibc-core/ics03-connection/types/src/events.rs similarity index 98% rename from crates/ibc/src/core/ics03_connection/events.rs rename to crates/ibc-core/ics03-connection/types/src/events.rs index dcc0f38f9..4b6ef6df0 100644 --- a/crates/ibc/src/core/ics03_connection/events.rs +++ b/crates/ibc-core/ics03-connection/types/src/events.rs @@ -1,10 +1,9 @@ //! Types for the IBC events emitted from Tendermint Websocket by the connection module. +use ibc_core_host_types::identifiers::{ClientId, ConnectionId}; +use ibc_primitives::prelude::*; use tendermint::abci; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::prelude::*; - /// Connection event types const CONNECTION_OPEN_INIT_EVENT: &str = "connection_open_init"; const CONNECTION_OPEN_TRY_EVENT: &str = "connection_open_try"; @@ -306,12 +305,12 @@ impl From for abci::Event { #[cfg(test)] mod tests { - use std::str::FromStr; + use core::str::FromStr; + use ibc_core_host_types::identifiers::ClientType; use tendermint::abci::Event as AbciEvent; use super::*; - use crate::core::ics02_client::client_type::ClientType; #[test] fn ibc_to_abci_connection_events() { diff --git a/crates/ibc-core/ics03-connection/types/src/lib.rs b/crates/ibc-core/ics03-connection/types/src/lib.rs new file mode 100644 index 000000000..345e7eee1 --- /dev/null +++ b/crates/ibc-core/ics03-connection/types/src/lib.rs @@ -0,0 +1,29 @@ +//! Implementation of the Connection Semantics (ICS-03) data structures. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +mod connection; +pub use connection::*; + +pub mod error; +pub mod events; +pub mod msgs; +pub mod version; + +/// Re-exports ICS-03 proto types from the `ibc-proto` crate for added +/// convenience +pub mod proto { + pub use ibc_proto::ibc::core::connection::*; +} diff --git a/crates/ibc/src/core/ics03_connection/msgs/conn_open_ack.rs b/crates/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs similarity index 93% rename from crates/ibc/src/core/ics03_connection/msgs/conn_open_ack.rs rename to crates/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs index cbdbbfcba..3ba244ed9 100644 --- a/crates/ibc/src/core/ics03_connection/msgs/conn_open_ack.rs +++ b/crates/ibc-core/ics03-connection/types/src/msgs/conn_open_ack.rs @@ -1,17 +1,16 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::identifiers::ConnectionId; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenAck as RawMsgConnectionOpenAck; use ibc_proto::Protobuf; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics03_connection::version::Version; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics24_host::identifier::ConnectionId; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::error::ConnectionError; +use crate::version::Version; -pub(crate) const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenAck"; +pub const CONN_OPEN_ACK_TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenAck"; /// Per our convention, this message is sent to chain A. /// The handler will check proofs of chain B. @@ -49,7 +48,7 @@ impl Msg for MsgConnectionOpenAck { type Raw = RawMsgConnectionOpenAck; fn type_url(&self) -> String { - TYPE_URL.to_string() + CONN_OPEN_ACK_TYPE_URL.to_string() } } @@ -132,13 +131,12 @@ impl From for RawMsgConnectionOpenAck { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::client::v1::Height; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenAck as RawMsgConnectionOpenAck; use ibc_testkit::utils::core::connection::dummy_raw_msg_conn_open_ack; - use test_log::test; - use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; - use crate::prelude::*; + use crate::msgs::conn_open_ack::MsgConnectionOpenAck; #[test] fn parse_connection_open_ack_msg() { diff --git a/crates/ibc/src/core/ics03_connection/msgs/conn_open_confirm.rs b/crates/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs similarity index 89% rename from crates/ibc/src/core/ics03_connection/msgs/conn_open_confirm.rs rename to crates/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs index 5a1200c78..545805c37 100644 --- a/crates/ibc/src/core/ics03_connection/msgs/conn_open_confirm.rs +++ b/crates/ibc-core/ics03-connection/types/src/msgs/conn_open_confirm.rs @@ -1,15 +1,14 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::identifiers::ConnectionId; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; use ibc_proto::Protobuf; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics24_host::identifier::ConnectionId; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::error::ConnectionError; -pub(crate) const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenConfirm"; +pub const CONN_OPEN_CONFIRM_TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenConfirm"; /// Per our convention, this message is sent to chain B. /// The handler will check proofs of chain A. @@ -33,7 +32,7 @@ impl Msg for MsgConnectionOpenConfirm { type Raw = RawMsgConnectionOpenConfirm; fn type_url(&self) -> String { - TYPE_URL.to_string() + CONN_OPEN_CONFIRM_TYPE_URL.to_string() } } @@ -74,13 +73,12 @@ impl From for RawMsgConnectionOpenConfirm { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::client::v1::Height; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; use ibc_testkit::utils::core::connection::dummy_raw_msg_conn_open_confirm; - use test_log::test; - use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; - use crate::prelude::*; + use crate::msgs::conn_open_confirm::MsgConnectionOpenConfirm; #[test] fn parse_connection_open_confirm_msg() { diff --git a/crates/ibc/src/core/ics03_connection/msgs/conn_open_init.rs b/crates/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs similarity index 94% rename from crates/ibc/src/core/ics03_connection/msgs/conn_open_init.rs rename to crates/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs index d0fd2572a..1638fc8ae 100644 --- a/crates/ibc/src/core/ics03_connection/msgs/conn_open_init.rs +++ b/crates/ibc-core/ics03-connection/types/src/msgs/conn_open_init.rs @@ -1,17 +1,16 @@ use core::time::Duration; +use ibc_core_host_types::identifiers::ClientId; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenInit as RawMsgConnectionOpenInit; use ibc_proto::Protobuf; -use crate::core::ics03_connection::connection::Counterparty; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics03_connection::version::Version; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; +use crate::connection::Counterparty; +use crate::error::ConnectionError; +use crate::version::Version; -pub(crate) const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenInit"; +pub const CONN_OPEN_INIT_TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenInit"; /// Per our convention, this message is sent to chain A. /// The handler will check proofs of chain B. @@ -30,7 +29,7 @@ impl Msg for MsgConnectionOpenInit { type Raw = RawMsgConnectionOpenInit; fn type_url(&self) -> String { - TYPE_URL.to_string() + CONN_OPEN_INIT_TYPE_URL.to_string() } } @@ -130,16 +129,15 @@ impl From for RawMsgConnectionOpenInit { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::connection::v1::{ Counterparty as RawCounterparty, MsgConnectionOpenInit as RawMsgConnectionOpenInit, }; use ibc_testkit::utils::core::connection::{ dummy_raw_counterparty_conn, dummy_raw_msg_conn_open_init, }; - use test_log::test; use super::MsgConnectionOpenInit; - use crate::prelude::*; #[test] fn parse_connection_open_init_msg() { diff --git a/crates/ibc/src/core/ics03_connection/msgs/conn_open_try.rs b/crates/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs similarity index 96% rename from crates/ibc/src/core/ics03_connection/msgs/conn_open_try.rs rename to crates/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs index ab778f2e3..4999f54c4 100644 --- a/crates/ibc/src/core/ics03_connection/msgs/conn_open_try.rs +++ b/crates/ibc-core/ics03-connection/types/src/msgs/conn_open_try.rs @@ -1,21 +1,20 @@ use core::convert::{TryFrom, TryInto}; use core::time::Duration; +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::identifiers::ClientId; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; use ibc_proto::Protobuf; -use crate::core::ics03_connection::connection::Counterparty; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics03_connection::version::Version; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics24_host::identifier::ClientId; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::connection::Counterparty; +use crate::error::ConnectionError; +use crate::version::Version; -pub(crate) const TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenTry"; +pub const CONN_OPEN_TRY_TYPE_URL: &str = "/ibc.core.connection.v1.MsgConnectionOpenTry"; /// Per our convention, this message is sent to chain B. /// The handler will check proofs of chain A. @@ -55,7 +54,7 @@ impl Msg for MsgConnectionOpenTry { type Raw = RawMsgConnectionOpenTry; fn type_url(&self) -> String { - TYPE_URL.to_string() + CONN_OPEN_TRY_TYPE_URL.to_string() } } #[allow(deprecated)] @@ -244,6 +243,7 @@ impl From for RawMsgConnectionOpenTry { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::client::v1::Height; use ibc_proto::ibc::core::connection::v1::{ Counterparty as RawCounterparty, MsgConnectionOpenTry as RawMsgConnectionOpenTry, @@ -251,10 +251,8 @@ mod tests { use ibc_testkit::utils::core::connection::{ dummy_raw_counterparty_conn, dummy_raw_msg_conn_open_try, }; - use test_log::test; - use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::prelude::*; + use crate::msgs::conn_open_try::MsgConnectionOpenTry; #[test] fn parse_connection_open_try_msg() { diff --git a/crates/ibc/src/core/ics03_connection/msgs.rs b/crates/ibc-core/ics03-connection/types/src/msgs/mod.rs similarity index 75% rename from crates/ibc/src/core/ics03_connection/msgs.rs rename to crates/ibc-core/ics03-connection/types/src/msgs/mod.rs index f80617d82..406001e36 100644 --- a/crates/ibc/src/core/ics03_connection/msgs.rs +++ b/crates/ibc-core/ics03-connection/types/src/msgs/mod.rs @@ -12,16 +12,17 @@ //! Another difference to ICS3 specs is that each message comprises an additional field called //! `signer` which is specific to Cosmos-SDK. -use crate::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; -use crate::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; -use crate::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use crate::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; -use crate::prelude::*; +use ibc_primitives::prelude::*; -pub mod conn_open_ack; -pub mod conn_open_confirm; -pub mod conn_open_init; -pub mod conn_open_try; +mod conn_open_ack; +mod conn_open_confirm; +mod conn_open_init; +mod conn_open_try; + +pub use conn_open_ack::*; +pub use conn_open_confirm::*; +pub use conn_open_init::*; +pub use conn_open_try::*; /// Enumeration of all possible messages that the ICS3 protocol processes. #[cfg_attr( diff --git a/crates/ibc/src/core/ics03_connection/version.rs b/crates/ibc-core/ics03-connection/types/src/version.rs similarity index 95% rename from crates/ibc/src/core/ics03_connection/version.rs rename to crates/ibc-core/ics03-connection/types/src/version.rs index 2052bb12c..46029c68c 100644 --- a/crates/ibc/src/core/ics03_connection/version.rs +++ b/crates/ibc-core/ics03-connection/types/src/version.rs @@ -2,13 +2,12 @@ use core::fmt::Display; +use ibc_primitives::prelude::*; +use ibc_primitives::utils::PrettySlice; use ibc_proto::ibc::core::connection::v1::Version as RawVersion; use ibc_proto::Protobuf; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics04_channel::channel::Order; -use crate::prelude::*; -use crate::utils::pretty::PrettySlice; +use crate::error::ConnectionError; /// Stores the identifier and the features supported by a version #[cfg_attr( @@ -94,10 +93,7 @@ impl Default for Version { fn default() -> Self { Version { identifier: "1".to_string(), - features: vec![ - Order::Ordered.as_str().to_owned(), - Order::Unordered.as_str().to_owned(), - ], + features: vec!["ORDER_ORDERED".to_string(), "ORDER_UNORDERED".to_string()], } } } @@ -189,12 +185,11 @@ fn get_feature_set_intersection( #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::connection::v1::Version as RawVersion; - use test_log::test; - use crate::core::ics03_connection::error::ConnectionError; - use crate::core::ics03_connection::version::{get_compatible_versions, pick_version, Version}; - use crate::prelude::*; + use crate::error::ConnectionError; + use crate::version::{get_compatible_versions, pick_version, Version}; fn get_dummy_features() -> Vec { vec!["ORDER_RANDOM".to_string(), "ORDER_UNORDERED".to_string()] diff --git a/crates/ibc-core/ics04-channel/Cargo.toml b/crates/ibc-core/ics04-channel/Cargo.toml new file mode 100644 index 000000000..f81ce1f32 --- /dev/null +++ b/crates/ibc-core/ics04-channel/Cargo.toml @@ -0,0 +1,84 @@ +[package] +name = "ibc-core-channel" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "channel"] +readme = "./../../README.md" +description = """ + Maintained by `ibc-rs`, contains the implementation of the ICS-04 Channel & Packet Semantics and + re-exports essential data structures and domain types from `ibc-core-channel-types` crate. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +prost = { workspace = true } + +# ibc dependencies +ibc-core-client = { workspace = true } +ibc-core-connection = { workspace = true } +ibc-core-channel-types = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-core-router = { workspace = true } +ibc-primitives = { workspace = true } + +[features] +default = ["std"] +std = [ + "ibc-core-client/std", + "ibc-core-connection/std", + "ibc-core-channel-types/std", + "ibc-core-commitment-types/std", + "ibc-core-host/std", + "ibc-core-handler-types/std", + "ibc-core-router/std", + "ibc-primitives/std", +] +serde = [ + "ibc-core-client/serde", + "ibc-core-connection/serde", + "ibc-core-channel-types/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host/serde", + "ibc-core-handler-types/serde", + "ibc-core-router/serde", + "ibc-primitives/serde", +] +schema = [ + "ibc-core-client/schema", + "ibc-core-connection/schema", + "ibc-core-channel-types/schema", + "ibc-core-commitment-types/schema", + "ibc-core-host/schema", + "ibc-core-handler-types/schema", + "ibc-core-router/schema", + "ibc-primitives/schema", +] +borsh = [ + "ibc-core-client/borsh", + "ibc-core-connection/borsh", + "ibc-core-channel-types/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host/borsh", + "ibc-core-handler-types/borsh", + "ibc-core-router/borsh", + "ibc-primitives/borsh", +] +parity-scale-codec = [ + "ibc-core-client/parity-scale-codec", + "ibc-core-connection/parity-scale-codec", + "ibc-core-channel-types/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-core-router/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] diff --git a/crates/ibc/src/core/ics04_channel/context.rs b/crates/ibc-core/ics04-channel/src/context.rs similarity index 67% rename from crates/ibc/src/core/ics04_channel/context.rs rename to crates/ibc-core/ics04-channel/src/context.rs index 40c51d3fc..8dcd05fac 100644 --- a/crates/ibc/src/core/ics04_channel/context.rs +++ b/crates/ibc-core/ics04-channel/src/context.rs @@ -1,21 +1,19 @@ //! ICS4 (channel) context. -use core::time::Duration; - -use super::packet::Sequence; -use crate::core::events::IbcEvent; -use crate::core::ics02_client::client_state::ClientState; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::{ClientExecutionContext, ClientValidationContext}; -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::commitment::PacketCommitment; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::core::ics24_host::path::{ +use ibc_core_channel_types::channel::ChannelEnd; +use ibc_core_channel_types::commitment::PacketCommitment; +use ibc_core_client::context::client_state::ClientState; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::context::{ClientExecutionContext, ClientValidationContext}; +use ibc_core_connection::types::ConnectionEnd; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::IbcEvent; +use ibc_core_host::types::identifiers::{ClientId, ConnectionId, Sequence}; +use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath, }; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_primitives::prelude::*; /// Methods required in send packet validation, to be implemented by the host pub trait SendPacketValidationContext { @@ -135,47 +133,3 @@ where self.log_message(message) } } - -pub(crate) fn calculate_block_delay( - delay_period_time: &Duration, - max_expected_time_per_block: &Duration, -) -> u64 { - let delay_period_time = delay_period_time.as_secs(); - let max_expected_time_per_block = max_expected_time_per_block.as_secs(); - if max_expected_time_per_block == 0 { - return 0; - } - if delay_period_time % max_expected_time_per_block == 0 { - return delay_period_time / max_expected_time_per_block; - } - (delay_period_time / max_expected_time_per_block) + 1 -} - -#[cfg(test)] -mod tests { - - use rstest::rstest; - - use super::*; - - #[rstest] - #[case::remainder_zero(10, 2, 5)] - #[case::remainder_not_zero(10, 3, 4)] - #[case::max_expected_zero(10, 0, 0)] - #[case::delay_period_zero(0, 2, 0)] - #[case::both_zero(0, 0, 0)] - #[case::delay_less_than_max(10, 11, 1)] - fn test_calculate_block_delay_zero( - #[case] delay_period_time: u64, - #[case] max_expected_time_per_block: u64, - #[case] expected: u64, - ) { - assert_eq!( - calculate_block_delay( - &Duration::from_secs(delay_period_time), - &Duration::from_secs(max_expected_time_per_block) - ), - expected - ); - } -} diff --git a/crates/ibc/src/core/ics04_channel/handler/acknowledgement.rs b/crates/ibc-core/ics04-channel/src/handler/acknowledgement.rs similarity index 84% rename from crates/ibc/src/core/ics04_channel/handler/acknowledgement.rs rename to crates/ibc-core/ics04-channel/src/handler/acknowledgement.rs index 4680e86d2..2ae3a39e6 100644 --- a/crates/ibc/src/core/ics04_channel/handler/acknowledgement.rs +++ b/crates/ibc-core/ics04-channel/src/handler/acknowledgement.rs @@ -1,22 +1,23 @@ -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics03_connection::delay::verify_conn_delay_passed; -use crate::core::ics04_channel::channel::{Counterparty, Order, State as ChannelState}; -use crate::core::ics04_channel::commitment::{compute_ack_commitment, compute_packet_commitment}; -use crate::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::core::ics04_channel::events::AcknowledgePacket; -use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; -use crate::core::ics24_host::path::{ +use ibc_core_channel_types::channel::{Counterparty, Order, State as ChannelState}; +use ibc_core_channel_types::commitment::{compute_ack_commitment, compute_packet_commitment}; +use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::events::AcknowledgePacket; +use ibc_core_channel_types::msgs::MsgAcknowledgement; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection::delay::verify_conn_delay_passed; +use ibc_core_connection::types::State as ConnectionState; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, SeqAckPath, }; -use crate::core::router::Module; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; +use ibc_primitives::prelude::*; -pub(crate) fn acknowledgement_packet_validate( +pub fn acknowledgement_packet_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgAcknowledgement, @@ -31,7 +32,7 @@ where .map_err(ContextError::PacketError) } -pub(crate) fn acknowledgement_packet_execute( +pub fn acknowledgement_packet_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgAcknowledgement, @@ -186,8 +187,11 @@ where } client_state_of_b_on_a.validate_proof_height(msg.proof_height_on_b)?; - let client_cons_state_path_on_a = - ClientConsensusStatePath::new(client_id_on_a, &msg.proof_height_on_b); + let client_cons_state_path_on_a = ClientConsensusStatePath::new( + client_id_on_a.clone(), + msg.proof_height_on_b.revision_number(), + msg.proof_height_on_b.revision_height(), + ); let consensus_state_of_b_on_a = ctx_a.consensus_state(&client_cons_state_path_on_a)?; let ack_commitment = compute_ack_commitment(&msg.acknowledgement); let ack_path_on_b = diff --git a/crates/ibc/src/core/ics04_channel/handler/chan_close_confirm.rs b/crates/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs similarity index 81% rename from crates/ibc/src/core/ics04_channel/handler/chan_close_confirm.rs rename to crates/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs index 28ce154d9..30024afd3 100644 --- a/crates/ibc/src/core/ics04_channel/handler/chan_close_confirm.rs +++ b/crates/ibc-core/ics04-channel/src/handler/chan_close_confirm.rs @@ -1,22 +1,22 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelCloseConfirm`. -use ibc_proto::Protobuf; - -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State, State as ChannelState}; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::events::CloseConfirm; -use crate::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; -use crate::core::ics24_host::path::{ChannelEndPath, ClientConsensusStatePath, Path}; -use crate::core::router::Module; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; - -pub(crate) fn chan_close_confirm_validate( +use ibc_core_channel_types::channel::{ChannelEnd, Counterparty, State, State as ChannelState}; +use ibc_core_channel_types::error::ChannelError; +use ibc_core_channel_types::events::CloseConfirm; +use ibc_core_channel_types::msgs::MsgChannelCloseConfirm; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection::types::State as ConnectionState; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Protobuf; + +pub fn chan_close_confirm_validate( ctx_b: &ValCtx, module: &dyn Module, msg: MsgChannelCloseConfirm, @@ -31,7 +31,7 @@ where Ok(()) } -pub(crate) fn chan_close_confirm_execute( +pub fn chan_close_confirm_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelCloseConfirm, @@ -124,8 +124,11 @@ where } client_state_of_a_on_b.validate_proof_height(msg.proof_height_on_a)?; - let client_cons_state_path_on_b = - ClientConsensusStatePath::new(client_id_on_b, &msg.proof_height_on_a); + let client_cons_state_path_on_b = ClientConsensusStatePath::new( + client_id_on_b.clone(), + msg.proof_height_on_a.revision_number(), + msg.proof_height_on_a.revision_height(), + ); let consensus_state_of_a_on_b = ctx_b.consensus_state(&client_cons_state_path_on_b)?; let prefix_on_a = conn_end_on_b.counterparty().prefix(); let port_id_on_a = &chan_end_on_b.counterparty().port_id; diff --git a/crates/ibc/src/core/ics04_channel/handler/chan_close_init.rs b/crates/ibc-core/ics04-channel/src/handler/chan_close_init.rs similarity index 82% rename from crates/ibc/src/core/ics04_channel/handler/chan_close_init.rs rename to crates/ibc-core/ics04-channel/src/handler/chan_close_init.rs index b5856e9f6..a7f03163e 100644 --- a/crates/ibc/src/core/ics04_channel/handler/chan_close_init.rs +++ b/crates/ibc-core/ics04-channel/src/handler/chan_close_init.rs @@ -1,18 +1,19 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelCloseInit`. -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::ClientStateValidation; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::State; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::events::CloseInit; -use crate::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; -use crate::core::ics24_host::path::ChannelEndPath; -use crate::core::router::Module; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; - -pub(crate) fn chan_close_init_validate( +use ibc_core_channel_types::channel::State; +use ibc_core_channel_types::error::ChannelError; +use ibc_core_channel_types::events::CloseInit; +use ibc_core_channel_types::msgs::MsgChannelCloseInit; +use ibc_core_client::context::client_state::ClientStateValidation; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection::types::State as ConnectionState; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::path::ChannelEndPath; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; +use ibc_primitives::prelude::*; + +pub fn chan_close_init_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgChannelCloseInit, @@ -27,7 +28,7 @@ where Ok(()) } -pub(crate) fn chan_close_init_execute( +pub fn chan_close_init_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelCloseInit, diff --git a/crates/ibc/src/core/ics04_channel/handler/chan_open_ack.rs b/crates/ibc-core/ics04-channel/src/handler/chan_open_ack.rs similarity index 80% rename from crates/ibc/src/core/ics04_channel/handler/chan_open_ack.rs rename to crates/ibc-core/ics04-channel/src/handler/chan_open_ack.rs index 4267437d2..c40fb2561 100644 --- a/crates/ibc/src/core/ics04_channel/handler/chan_open_ack.rs +++ b/crates/ibc-core/ics04-channel/src/handler/chan_open_ack.rs @@ -1,22 +1,21 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelOpenAck`. - -use ibc_proto::Protobuf; - -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State, State as ChannelState}; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::events::OpenAck; -use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; -use crate::core::ics24_host::path::{ChannelEndPath, ClientConsensusStatePath, Path}; -use crate::core::router::Module; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; - -pub(crate) fn chan_open_ack_validate( +use ibc_core_channel_types::channel::{ChannelEnd, Counterparty, State, State as ChannelState}; +use ibc_core_channel_types::error::ChannelError; +use ibc_core_channel_types::events::OpenAck; +use ibc_core_channel_types::msgs::MsgChannelOpenAck; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection::types::State as ConnectionState; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Protobuf; + +pub fn chan_open_ack_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgChannelOpenAck, @@ -31,7 +30,7 @@ where Ok(()) } -pub(crate) fn chan_open_ack_execute( +pub fn chan_open_ack_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenAck, @@ -122,8 +121,11 @@ where } client_state_of_b_on_a.validate_proof_height(msg.proof_height_on_b)?; - let client_cons_state_path_on_a = - ClientConsensusStatePath::new(client_id_on_a, &msg.proof_height_on_b); + let client_cons_state_path_on_a = ClientConsensusStatePath::new( + client_id_on_a.clone(), + msg.proof_height_on_b.revision_number(), + msg.proof_height_on_b.revision_height(), + ); let consensus_state_of_b_on_a = ctx_a.consensus_state(&client_cons_state_path_on_a)?; let prefix_on_b = conn_end_on_a.counterparty().prefix(); let port_id_on_b = &chan_end_on_a.counterparty().port_id; diff --git a/crates/ibc/src/core/ics04_channel/handler/chan_open_confirm.rs b/crates/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs similarity index 81% rename from crates/ibc/src/core/ics04_channel/handler/chan_open_confirm.rs rename to crates/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs index 7e5ecf93b..5ef8bd769 100644 --- a/crates/ibc/src/core/ics04_channel/handler/chan_open_confirm.rs +++ b/crates/ibc-core/ics04-channel/src/handler/chan_open_confirm.rs @@ -1,22 +1,22 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelOpenConfirm`. -use ibc_proto::Protobuf; - -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State, State as ChannelState}; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::events::OpenConfirm; -use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; -use crate::core::ics24_host::path::{ChannelEndPath, ClientConsensusStatePath, Path}; -use crate::core::router::Module; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; - -pub(crate) fn chan_open_confirm_validate( +use ibc_core_channel_types::channel::{ChannelEnd, Counterparty, State, State as ChannelState}; +use ibc_core_channel_types::error::ChannelError; +use ibc_core_channel_types::events::OpenConfirm; +use ibc_core_channel_types::msgs::MsgChannelOpenConfirm; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection::types::State as ConnectionState; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::path::{ChannelEndPath, ClientConsensusStatePath, Path}; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Protobuf; + +pub fn chan_open_confirm_validate( ctx_b: &ValCtx, module: &dyn Module, msg: MsgChannelOpenConfirm, @@ -31,7 +31,7 @@ where Ok(()) } -pub(crate) fn chan_open_confirm_execute( +pub fn chan_open_confirm_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenConfirm, @@ -126,8 +126,11 @@ where } client_state_of_a_on_b.validate_proof_height(msg.proof_height_on_a)?; - let client_cons_state_path_on_b = - ClientConsensusStatePath::new(client_id_on_b, &msg.proof_height_on_a); + let client_cons_state_path_on_b = ClientConsensusStatePath::new( + client_id_on_b.clone(), + msg.proof_height_on_a.revision_number(), + msg.proof_height_on_a.revision_height(), + ); let consensus_state_of_a_on_b = ctx_b.consensus_state(&client_cons_state_path_on_b)?; let prefix_on_a = conn_end_on_b.counterparty().prefix(); let port_id_on_a = &chan_end_on_b.counterparty().port_id; diff --git a/crates/ibc/src/core/ics04_channel/handler/chan_open_init.rs b/crates/ibc-core/ics04-channel/src/handler/chan_open_init.rs similarity index 83% rename from crates/ibc/src/core/ics04_channel/handler/chan_open_init.rs rename to crates/ibc-core/ics04-channel/src/handler/chan_open_init.rs index 17dc77df3..31f74ce0c 100644 --- a/crates/ibc/src/core/ics04_channel/handler/chan_open_init.rs +++ b/crates/ibc-core/ics04-channel/src/handler/chan_open_init.rs @@ -1,18 +1,19 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelOpenInit`. -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::ClientStateValidation; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State}; -use crate::core::ics04_channel::events::OpenInit; -use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; -use crate::core::ics24_host::identifier::ChannelId; -use crate::core::ics24_host::path::{ChannelEndPath, SeqAckPath, SeqRecvPath, SeqSendPath}; -use crate::core::router::Module; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; - -pub(crate) fn chan_open_init_validate( +use ibc_core_channel_types::channel::{ChannelEnd, Counterparty, State}; +use ibc_core_channel_types::events::OpenInit; +use ibc_core_channel_types::msgs::MsgChannelOpenInit; +use ibc_core_client::context::client_state::ClientStateValidation; +use ibc_core_client::types::error::ClientError; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::identifiers::ChannelId; +use ibc_core_host::types::path::{ChannelEndPath, SeqAckPath, SeqRecvPath, SeqSendPath}; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; +use ibc_primitives::prelude::*; + +pub fn chan_open_init_validate( ctx_a: &ValCtx, module: &dyn Module, msg: MsgChannelOpenInit, @@ -35,7 +36,7 @@ where Ok(()) } -pub(crate) fn chan_open_init_execute( +pub fn chan_open_init_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenInit, diff --git a/crates/ibc/src/core/ics04_channel/handler/chan_open_try.rs b/crates/ibc-core/ics04-channel/src/handler/chan_open_try.rs similarity index 82% rename from crates/ibc/src/core/ics04_channel/handler/chan_open_try.rs rename to crates/ibc-core/ics04-channel/src/handler/chan_open_try.rs index ff27b0eff..cbc9ec590 100644 --- a/crates/ibc/src/core/ics04_channel/handler/chan_open_try.rs +++ b/crates/ibc-core/ics04-channel/src/handler/chan_open_try.rs @@ -1,25 +1,25 @@ //! Protocol logic specific to ICS4 messages of type `MsgChannelOpenTry`. -use ibc_proto::Protobuf; - -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, State, State as ChannelState}; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::events::OpenTry; -use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; -use crate::core::ics24_host::identifier::ChannelId; -use crate::core::ics24_host::path::{ +use ibc_core_channel_types::channel::{ChannelEnd, Counterparty, State as ChannelState}; +use ibc_core_channel_types::error::ChannelError; +use ibc_core_channel_types::events::OpenTry; +use ibc_core_channel_types::msgs::MsgChannelOpenTry; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection::types::State as ConnectionState; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::identifiers::ChannelId; +use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, Path, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use crate::core::router::Module; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Protobuf; -pub(crate) fn chan_open_try_validate( +pub fn chan_open_try_validate( ctx_b: &ValCtx, module: &dyn Module, msg: MsgChannelOpenTry, @@ -43,7 +43,7 @@ where Ok(()) } -pub(crate) fn chan_open_try_execute( +pub fn chan_open_try_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgChannelOpenTry, @@ -66,7 +66,7 @@ where // state changes { let chan_end_on_b = ChannelEnd::new( - State::TryOpen, + ChannelState::TryOpen, msg.ordering, Counterparty::new(msg.port_id_on_a.clone(), Some(msg.chan_id_on_a.clone())), msg.connection_hops_on_b.clone(), @@ -147,8 +147,11 @@ where } client_state_of_a_on_b.validate_proof_height(msg.proof_height_on_a)?; - let client_cons_state_path_on_b = - ClientConsensusStatePath::new(client_id_on_b, &msg.proof_height_on_a); + let client_cons_state_path_on_b = ClientConsensusStatePath::new( + client_id_on_b.clone(), + msg.proof_height_on_a.revision_number(), + msg.proof_height_on_a.revision_height(), + ); let consensus_state_of_a_on_b = ctx_b.consensus_state(&client_cons_state_path_on_b)?; let prefix_on_a = conn_end_on_b.counterparty().prefix(); let port_id_on_a = msg.port_id_on_a.clone(); diff --git a/crates/ibc-core/ics04-channel/src/handler/mod.rs b/crates/ibc-core/ics04-channel/src/handler/mod.rs new file mode 100644 index 000000000..b1ea237a1 --- /dev/null +++ b/crates/ibc-core/ics04-channel/src/handler/mod.rs @@ -0,0 +1,24 @@ +//! This module implements the processing logic for ICS4 (channel) messages. +mod acknowledgement; +mod chan_close_confirm; +mod chan_close_init; +mod chan_open_ack; +mod chan_open_confirm; +mod chan_open_init; +mod chan_open_try; +mod recv_packet; +mod send_packet; +mod timeout; +mod timeout_on_close; + +pub use acknowledgement::*; +pub use chan_close_confirm::*; +pub use chan_close_init::*; +pub use chan_open_ack::*; +pub use chan_open_confirm::*; +pub use chan_open_init::*; +pub use chan_open_try::*; +pub use recv_packet::*; +pub use send_packet::*; +pub use timeout::*; +pub use timeout_on_close::*; diff --git a/crates/ibc/src/core/ics04_channel/handler/recv_packet.rs b/crates/ibc-core/ics04-channel/src/handler/recv_packet.rs similarity index 86% rename from crates/ibc/src/core/ics04_channel/handler/recv_packet.rs rename to crates/ibc-core/ics04-channel/src/handler/recv_packet.rs index f99d184a1..cc59d9100 100644 --- a/crates/ibc/src/core/ics04_channel/handler/recv_packet.rs +++ b/crates/ibc-core/ics04-channel/src/handler/recv_packet.rs @@ -1,28 +1,26 @@ -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::State as ConnectionState; -use crate::core::ics03_connection::delay::verify_conn_delay_passed; -use crate::core::ics04_channel::channel::{Counterparty, Order, State as ChannelState}; -use crate::core::ics04_channel::commitment::{compute_ack_commitment, compute_packet_commitment}; -use crate::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::core::ics04_channel::events::{ReceivePacket, WriteAcknowledgement}; -use crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; -use crate::core::ics04_channel::packet::Receipt; -use crate::core::ics24_host::path::{ +use ibc_core_channel_types::channel::{Counterparty, Order, State as ChannelState}; +use ibc_core_channel_types::commitment::{compute_ack_commitment, compute_packet_commitment}; +use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::events::{ReceivePacket, WriteAcknowledgement}; +use ibc_core_channel_types::msgs::MsgRecvPacket; +use ibc_core_channel_types::packet::Receipt; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection::delay::verify_conn_delay_passed; +use ibc_core_connection::types::State as ConnectionState; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, SeqRecvPath, }; -use crate::core::router::Module; -use crate::core::timestamp::Expiry; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; +use ibc_primitives::prelude::*; +use ibc_primitives::Expiry; -pub(crate) fn recv_packet_validate( - ctx_b: &ValCtx, - msg: MsgRecvPacket, -) -> Result<(), ContextError> +pub fn recv_packet_validate(ctx_b: &ValCtx, msg: MsgRecvPacket) -> Result<(), ContextError> where ValCtx: ValidationContext, { @@ -33,7 +31,7 @@ where // If any error occurs, then an "error acknowledgement" must be returned. } -pub(crate) fn recv_packet_execute( +pub fn recv_packet_execute( ctx_b: &mut ExecCtx, module: &mut dyn Module, msg: MsgRecvPacket, @@ -193,8 +191,12 @@ where } client_state_of_a_on_b.validate_proof_height(msg.proof_height_on_a)?; - let client_cons_state_path_on_b = - ClientConsensusStatePath::new(client_id_on_b, &msg.proof_height_on_a); + let client_cons_state_path_on_b = ClientConsensusStatePath::new( + client_id_on_b.clone(), + msg.proof_height_on_a.revision_number(), + msg.proof_height_on_a.revision_height(), + ); + let consensus_state_of_a_on_b = ctx_b.consensus_state(&client_cons_state_path_on_b)?; let expected_commitment_on_a = compute_packet_commitment( diff --git a/crates/ibc/src/core/ics04_channel/handler/send_packet.rs b/crates/ibc-core/ics04-channel/src/handler/send_packet.rs similarity index 81% rename from crates/ibc/src/core/ics04_channel/handler/send_packet.rs rename to crates/ibc-core/ics04-channel/src/handler/send_packet.rs index 4a9134f57..da97c51c2 100644 --- a/crates/ibc/src/core/ics04_channel/handler/send_packet.rs +++ b/crates/ibc-core/ics04-channel/src/handler/send_packet.rs @@ -1,21 +1,20 @@ -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics04_channel::channel::Counterparty; -use crate::core::ics04_channel::commitment::compute_packet_commitment; -use crate::core::ics04_channel::context::{ - SendPacketExecutionContext, SendPacketValidationContext, -}; -use crate::core::ics04_channel::error::PacketError; -use crate::core::ics04_channel::events::SendPacket; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics24_host::path::{ +use ibc_core_channel_types::channel::Counterparty; +use ibc_core_channel_types::commitment::compute_packet_commitment; +use ibc_core_channel_types::error::PacketError; +use ibc_core_channel_types::events::SendPacket; +use ibc_core_channel_types::packet::Packet; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath, }; -use crate::core::timestamp::Expiry; -use crate::core::ContextError; -use crate::prelude::*; +use ibc_primitives::prelude::*; +use ibc_primitives::Expiry; + +use crate::context::{SendPacketExecutionContext, SendPacketValidationContext}; /// Send the given packet, including all necessary validation. /// @@ -73,8 +72,11 @@ pub fn send_packet_validate( .into()); } - let client_cons_state_path_on_a = - ClientConsensusStatePath::new(client_id_on_a, &latest_height_on_a); + let client_cons_state_path_on_a = ClientConsensusStatePath::new( + client_id_on_a.clone(), + latest_height_on_a.revision_number(), + latest_height_on_a.revision_height(), + ); let consensus_state_of_b_on_a = ctx_a.client_consensus_state(&client_cons_state_path_on_a)?; let latest_timestamp = consensus_state_of_b_on_a.timestamp(); let packet_timestamp = packet.timeout_timestamp_on_b; diff --git a/crates/ibc/src/core/ics04_channel/handler/timeout.rs b/crates/ibc-core/ics04-channel/src/handler/timeout.rs similarity index 87% rename from crates/ibc/src/core/ics04_channel/handler/timeout.rs rename to crates/ibc-core/ics04-channel/src/handler/timeout.rs index 5235f9a8c..28cfd6587 100644 --- a/crates/ibc/src/core/ics04_channel/handler/timeout.rs +++ b/crates/ibc-core/ics04-channel/src/handler/timeout.rs @@ -1,30 +1,30 @@ -use prost::Message; - -use crate::core::events::{IbcEvent, MessageEvent}; -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::delay::verify_conn_delay_passed; -use crate::core::ics04_channel::channel::{Counterparty, Order, State}; -use crate::core::ics04_channel::commitment::compute_packet_commitment; -use crate::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::core::ics04_channel::events::{ChannelClosed, TimeoutPacket}; -use crate::core::ics04_channel::handler::timeout_on_close; -use crate::core::ics04_channel::msgs::timeout::MsgTimeout; -use crate::core::ics04_channel::msgs::timeout_on_close::MsgTimeoutOnClose; -use crate::core::ics24_host::path::{ +use ibc_core_channel_types::channel::{Counterparty, Order, State}; +use ibc_core_channel_types::commitment::compute_packet_commitment; +use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::events::{ChannelClosed, TimeoutPacket}; +use ibc_core_channel_types::msgs::{MsgTimeout, MsgTimeoutOnClose}; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection::delay::verify_conn_delay_passed; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::{IbcEvent, MessageEvent}; +use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, SeqRecvPath, }; -use crate::core::router::Module; -use crate::core::{ContextError, ExecutionContext, ValidationContext}; -use crate::prelude::*; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; +use ibc_primitives::prelude::*; +use prost::Message; + +use super::timeout_on_close; -pub(crate) enum TimeoutMsgType { +pub enum TimeoutMsgType { Timeout(MsgTimeout), TimeoutOnClose(MsgTimeoutOnClose), } -pub(crate) fn timeout_packet_validate( +pub fn timeout_packet_validate( ctx_a: &ValCtx, module: &dyn Module, timeout_msg_type: TimeoutMsgType, @@ -47,7 +47,7 @@ where .map_err(ContextError::PacketError) } -pub(crate) fn timeout_packet_execute( +pub fn timeout_packet_execute( ctx_a: &mut ExecCtx, module: &mut dyn Module, timeout_msg_type: TimeoutMsgType, @@ -200,8 +200,11 @@ where client_state_of_b_on_a.validate_proof_height(msg.proof_height_on_b)?; // check that timeout height or timeout timestamp has passed on the other end - let client_cons_state_path_on_a = - ClientConsensusStatePath::new(client_id_on_a, &msg.proof_height_on_b); + let client_cons_state_path_on_a = ClientConsensusStatePath::new( + client_id_on_a.clone(), + msg.proof_height_on_b.revision_number(), + msg.proof_height_on_b.revision_height(), + ); let consensus_state_of_b_on_a = ctx_a.consensus_state(&client_cons_state_path_on_a)?; let timestamp_of_b = consensus_state_of_b_on_a.timestamp(); diff --git a/crates/ibc/src/core/ics04_channel/handler/timeout_on_close.rs b/crates/ibc-core/ics04-channel/src/handler/timeout_on_close.rs similarity index 86% rename from crates/ibc/src/core/ics04_channel/handler/timeout_on_close.rs rename to crates/ibc-core/ics04-channel/src/handler/timeout_on_close.rs index cb0a9b40a..641f0483c 100644 --- a/crates/ibc/src/core/ics04_channel/handler/timeout_on_close.rs +++ b/crates/ibc-core/ics04-channel/src/handler/timeout_on_close.rs @@ -1,19 +1,19 @@ -use ibc_proto::Protobuf; -use prost::Message; - -use crate::core::ics02_client::client_state::{ClientStateCommon, ClientStateValidation}; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::delay::verify_conn_delay_passed; -use crate::core::ics04_channel::channel::{ChannelEnd, Counterparty, Order, State}; -use crate::core::ics04_channel::commitment::compute_packet_commitment; -use crate::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::core::ics04_channel::msgs::timeout_on_close::MsgTimeoutOnClose; -use crate::core::ics24_host::path::{ +use ibc_core_channel_types::channel::{ChannelEnd, Counterparty, Order, State}; +use ibc_core_channel_types::commitment::compute_packet_commitment; +use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::msgs::MsgTimeoutOnClose; +use ibc_core_client::context::client_state::{ClientStateCommon, ClientStateValidation}; +use ibc_core_client::context::consensus_state::ConsensusState; +use ibc_core_client::types::error::ClientError; +use ibc_core_connection::delay::verify_conn_delay_passed; +use ibc_core_handler_types::error::ContextError; +use ibc_core_host::types::path::{ ChannelEndPath, ClientConsensusStatePath, CommitmentPath, Path, ReceiptPath, SeqRecvPath, }; -use crate::core::{ContextError, ValidationContext}; -use crate::prelude::*; +use ibc_core_host::ValidationContext; +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Protobuf; +use prost::Message; pub fn validate(ctx_a: &Ctx, msg: &MsgTimeoutOnClose) -> Result<(), ContextError> where @@ -78,8 +78,11 @@ where } client_state_of_b_on_a.validate_proof_height(msg.proof_height_on_b)?; - let client_cons_state_path_on_a = - ClientConsensusStatePath::new(client_id_on_a, &msg.proof_height_on_b); + let client_cons_state_path_on_a = ClientConsensusStatePath::new( + client_id_on_a.clone(), + msg.proof_height_on_b.revision_number(), + msg.proof_height_on_b.revision_height(), + ); let consensus_state_of_b_on_a = ctx_a.consensus_state(&client_cons_state_path_on_a)?; let prefix_on_b = conn_end_on_a.counterparty().prefix(); let port_id_on_b = chan_end_on_a.counterparty().port_id.clone(); diff --git a/crates/ibc-core/ics04-channel/src/lib.rs b/crates/ibc-core/ics04-channel/src/lib.rs new file mode 100644 index 000000000..1ccb4f25c --- /dev/null +++ b/crates/ibc-core/ics04-channel/src/lib.rs @@ -0,0 +1,26 @@ +//! ICS-04: Channel and Packet Semantics implementation to process channel open +//! handshake and incoming data packets. Exports data structures and +//! implementations of IBC core channel module. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +pub mod context; +pub mod handler; + +/// Re-exports ICS-04 data structures from the `ibc-core-channel-types` crate. +pub mod types { + #[doc(inline)] + pub use ibc_core_channel_types::*; +} diff --git a/crates/ibc-core/ics04-channel/types/Cargo.toml b/crates/ibc-core/ics04-channel/types/Cargo.toml new file mode 100644 index 000000000..b19aa13df --- /dev/null +++ b/crates/ibc-core/ics04-channel/types/Cargo.toml @@ -0,0 +1,101 @@ +[package] +name = "ibc-core-channel-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "channel", "types"] +readme = "./../../README.md" +description = """ + Maintained by `ibc-rs`, encapsulates essential ICS-4 Channel Semantics data structures and domain types, + as specified in the Inter-Blockchain Communication (IBC) protocol. Designed for universal applicability + to facilitate development and integration across diverse IBC-enabled projects. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +sha2 = { workspace = true } +schemars = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-core-client-types = { workspace = true } +ibc-core-connection-types = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-primitives = { workspace = true } +ibc-proto = { workspace = true } + +# cosmos dependencies +tendermint = { workspace = true } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[dev-dependencies] +ibc-testkit = { workspace = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "sha2/std", + "serde/std", + "subtle-encoding/std", + "ibc-core-client-types/std", + "ibc-core-connection-types/std", + "ibc-core-host-types/std", + "ibc-core-commitment-types/std", + "ibc-primitives/std", + "ibc-proto/std", + "tendermint/std", +] +serde = [ + "dep:serde", + "ibc-core-client-types/serde", + "ibc-core-connection-types/serde", + "ibc-core-host-types/serde", + "ibc-core-commitment-types/serde", + "ibc-primitives/serde", + "ibc-proto/serde", +] +schema = [ + "dep:schemars", + "ibc-core-client-types/schema", + "ibc-core-connection-types/schema", + "ibc-core-host-types/schema", + "ibc-core-commitment-types/schema", + "ibc-primitives/schema", + "ibc-proto/json-schema", +] +borsh = [ + "dep:borsh", + "ibc-core-client-types/borsh", + "ibc-core-connection-types/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host-types/borsh", + "ibc-primitives/borsh", + "ibc-proto/borsh", +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-core-client-types/parity-scale-codec", + "ibc-core-connection-types/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", + "ibc-proto/parity-scale-codec", +] diff --git a/crates/ibc/src/core/ics04_channel/acknowledgement.rs b/crates/ibc-core/ics04-channel/types/src/acknowledgement.rs similarity index 99% rename from crates/ibc/src/core/ics04_channel/acknowledgement.rs rename to crates/ibc-core/ics04-channel/types/src/acknowledgement.rs index 732234103..b30f14454 100644 --- a/crates/ibc/src/core/ics04_channel/acknowledgement.rs +++ b/crates/ibc-core/ics04-channel/types/src/acknowledgement.rs @@ -3,9 +3,9 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use derive_more::Into; +use ibc_primitives::prelude::*; use super::error::PacketError; -use crate::prelude::*; /// A generic Acknowledgement type that modules may interpret as they like. /// diff --git a/crates/ibc/src/core/ics04_channel/channel.rs b/crates/ibc-core/ics04-channel/types/src/channel.rs similarity index 98% rename from crates/ibc/src/core/ics04_channel/channel.rs rename to crates/ibc-core/ics04-channel/types/src/channel.rs index 43eceacb5..eed651870 100644 --- a/crates/ibc/src/core/ics04_channel/channel.rs +++ b/crates/ibc-core/ics04-channel/types/src/channel.rs @@ -1,19 +1,19 @@ -//! Implementation of IBC channels, as described in ICS 4. +//! Implementation of IBC channels, as described in ICS-04. use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; +use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId}; +use ibc_primitives::prelude::*; +use ibc_primitives::utils::PrettySlice; use ibc_proto::ibc::core::channel::v1::{ Channel as RawChannel, Counterparty as RawCounterparty, IdentifiedChannel as RawIdentifiedChannel, }; use ibc_proto::Protobuf; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::prelude::*; -use crate::utils::pretty::PrettySlice; +use crate::error::ChannelError; +use crate::Version; /// A [`ChannelEnd`] along with its ID and the port it is bound to #[cfg_attr( @@ -570,12 +570,11 @@ impl Display for State { mod tests { use core::str::FromStr; + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::Channel as RawChannel; use ibc_testkit::utils::core::channel::dummy_raw_channel_end; - use test_log::test; - use crate::core::ics04_channel::channel::ChannelEnd; - use crate::prelude::*; + use crate::channel::ChannelEnd; #[test] fn channel_end_try_from_raw() { diff --git a/crates/ibc/src/core/ics04_channel/commitment.rs b/crates/ibc-core/ics04-channel/types/src/commitment.rs similarity index 95% rename from crates/ibc/src/core/ics04_channel/commitment.rs rename to crates/ibc-core/ics04-channel/types/src/commitment.rs index 67f8fbae6..ba5da70c5 100644 --- a/crates/ibc/src/core/ics04_channel/commitment.rs +++ b/crates/ibc-core/ics04-channel/types/src/commitment.rs @@ -1,9 +1,10 @@ //! Types and utilities related to packet commitments. +use ibc_primitives::prelude::*; +use ibc_primitives::Timestamp; + use super::acknowledgement::Acknowledgement; -use crate::core::ics04_channel::timeout::TimeoutHeight; -use crate::core::timestamp::Timestamp; -use crate::prelude::*; +use crate::timeout::TimeoutHeight; /// Packet commitment #[cfg_attr( @@ -124,7 +125,7 @@ mod test { ]; let actual = compute_packet_commitment( "packet data".as_bytes(), - &TimeoutHeight::At(crate::Height::new(42, 24).unwrap()), + &TimeoutHeight::At(ibc_core_client_types::Height::new(42, 24).unwrap()), &Timestamp::from_nanoseconds(0x42).unwrap(), ); assert_eq!(&expected[..], actual.as_ref()); diff --git a/crates/ibc/src/core/ics04_channel/error.rs b/crates/ibc-core/ics04-channel/types/src/error.rs similarity index 94% rename from crates/ibc/src/core/ics04_channel/error.rs rename to crates/ibc-core/ics04-channel/types/src/error.rs index 88a8abcb0..13e33db9c 100644 --- a/crates/ibc/src/core/ics04_channel/error.rs +++ b/crates/ibc-core/ics04-channel/types/src/error.rs @@ -1,18 +1,17 @@ //! Defines the main channel, port and packet error types use displaydoc::Display; +use ibc_core_client_types::{error as client_error, Height}; +use ibc_core_connection_types::error as connection_error; +use ibc_core_host_types::error::IdentifierError; +use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId, Sequence}; +use ibc_primitives::prelude::*; +use ibc_primitives::{ParseTimestampError, Timestamp}; use super::channel::Counterparty; -use super::packet::Sequence; use super::timeout::TimeoutHeight; -use crate::core::ics02_client::error as client_error; -use crate::core::ics03_connection::error as connection_error; -use crate::core::ics04_channel::channel::State; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, IdentifierError, PortId}; -use crate::core::timestamp::{ParseTimestampError, Timestamp}; -use crate::prelude::*; -use crate::Height; +use crate::channel::State; +use crate::Version; #[derive(Debug, Display)] pub enum ChannelError { diff --git a/crates/ibc/src/core/ics04_channel/events.rs b/crates/ibc-core/ics04-channel/types/src/events.rs similarity index 99% rename from crates/ibc/src/core/ics04_channel/events.rs rename to crates/ibc-core/ics04-channel/types/src/events.rs index 58baab970..606d248db 100644 --- a/crates/ibc/src/core/ics04_channel/events.rs +++ b/crates/ibc-core/ics04-channel/types/src/events.rs @@ -3,6 +3,9 @@ mod channel_attributes; mod packet_attributes; +use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId, Sequence}; +use ibc_primitives::prelude::*; +use ibc_primitives::Timestamp; use tendermint::abci; use self::channel_attributes::{ @@ -17,14 +20,10 @@ use self::packet_attributes::{ }; use super::acknowledgement::Acknowledgement; use super::channel::Order; -use super::packet::Sequence; use super::timeout::TimeoutHeight; use super::Version; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::core::timestamp::Timestamp; -use crate::prelude::*; +use crate::error::ChannelError; +use crate::packet::Packet; /// Channel event types const CHANNEL_OPEN_INIT_EVENT: &str = "channel_open_init"; diff --git a/crates/ibc/src/core/ics04_channel/events/channel_attributes.rs b/crates/ibc-core/ics04-channel/types/src/events/channel_attributes.rs similarity index 97% rename from crates/ibc/src/core/ics04_channel/events/channel_attributes.rs rename to crates/ibc-core/ics04-channel/types/src/events/channel_attributes.rs index d802a50b0..8032fb44d 100644 --- a/crates/ibc/src/core/ics04_channel/events/channel_attributes.rs +++ b/crates/ibc-core/ics04-channel/types/src/events/channel_attributes.rs @@ -1,10 +1,10 @@ //! This module holds all the abci event attributes for IBC events emitted //! during the channel handshake. use derive_more::From; +use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId}; use tendermint::abci; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; +use crate::Version; const CONNECTION_ID_ATTRIBUTE_KEY: &str = "connection_id"; const CHANNEL_ID_ATTRIBUTE_KEY: &str = "channel_id"; diff --git a/crates/ibc/src/core/ics04_channel/events/packet_attributes.rs b/crates/ibc-core/ics04-channel/types/src/events/packet_attributes.rs similarity index 95% rename from crates/ibc/src/core/ics04_channel/events/packet_attributes.rs rename to crates/ibc-core/ics04-channel/types/src/events/packet_attributes.rs index 58d820635..44a7970a8 100644 --- a/crates/ibc/src/core/ics04_channel/events/packet_attributes.rs +++ b/crates/ibc-core/ics04-channel/types/src/events/packet_attributes.rs @@ -4,17 +4,16 @@ use core::str; use derive_more::From; +use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId, Sequence}; +use ibc_primitives::prelude::*; +use ibc_primitives::Timestamp; use subtle_encoding::hex; use tendermint::abci; -use crate::core::ics04_channel::acknowledgement::Acknowledgement; -use crate::core::ics04_channel::channel::Order; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::packet::Sequence; -use crate::core::ics04_channel::timeout::TimeoutHeight; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::core::timestamp::Timestamp; -use crate::prelude::*; +use crate::acknowledgement::Acknowledgement; +use crate::channel::Order; +use crate::error::ChannelError; +use crate::timeout::TimeoutHeight; const PKT_SEQ_ATTRIBUTE_KEY: &str = "packet_sequence"; const PKT_DATA_ATTRIBUTE_KEY: &str = "packet_data"; diff --git a/crates/ibc-core/ics04-channel/types/src/lib.rs b/crates/ibc-core/ics04-channel/types/src/lib.rs new file mode 100644 index 000000000..6e7a0b3c6 --- /dev/null +++ b/crates/ibc-core/ics04-channel/types/src/lib.rs @@ -0,0 +1,35 @@ +//! Implementation of the Channel and Packet Semantics (ICS-04) data structures. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +pub mod channel; +pub mod error; +pub mod events; + +pub mod msgs; +pub mod packet; +pub mod timeout; + +pub mod acknowledgement; +pub mod commitment; +mod version; +pub use version::Version; + +/// Re-exports ICS-04 proto types from the `ibc-proto` crate +pub mod proto { + pub use ibc_proto::ibc::core::channel::*; +} diff --git a/crates/ibc/src/core/ics04_channel/msgs/acknowledgement.rs b/crates/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs similarity index 87% rename from crates/ibc/src/core/ics04_channel/msgs/acknowledgement.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs index 7195be630..0b5be9ea8 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/acknowledgement.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/acknowledgement.rs @@ -1,16 +1,15 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgement; use ibc_proto::Protobuf; -use crate::core::ics04_channel::acknowledgement::Acknowledgement; -use crate::core::ics04_channel::error::PacketError; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::acknowledgement::Acknowledgement; +use crate::error::PacketError; +use crate::packet::Packet; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgAcknowledgement"; +pub const ACKNOWLEDGEMENT_TYPE_URL: &str = "/ibc.core.channel.v1.MsgAcknowledgement"; /// /// Message definition for packet acknowledgements. @@ -35,7 +34,7 @@ impl Msg for MsgAcknowledgement { type Raw = RawMsgAcknowledgement; fn type_url(&self) -> String { - TYPE_URL.to_string() + ACKNOWLEDGEMENT_TYPE_URL.to_string() } } @@ -78,14 +77,13 @@ impl From for RawMsgAcknowledgement { #[cfg(test)] mod test { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgAcknowledgement as RawMsgAcknowledgement; use ibc_testkit::utils::core::channel::dummy_raw_msg_acknowledgement; use ibc_testkit::utils::core::signer::dummy_bech32_account; - use test_log::test; - use crate::core::ics04_channel::error::PacketError; - use crate::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement; - use crate::prelude::*; + use crate::error::PacketError; + use crate::msgs::acknowledgement::MsgAcknowledgement; #[test] fn msg_acknowledgment_try_from_raw() { diff --git a/crates/ibc/src/core/ics04_channel/msgs/chan_close_confirm.rs b/crates/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs similarity index 92% rename from crates/ibc/src/core/ics04_channel/msgs/chan_close_confirm.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs index d9c9867c1..8c028cf11 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/chan_close_confirm.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/chan_close_confirm.rs @@ -1,15 +1,14 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::identifiers::{ChannelId, PortId}; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; use ibc_proto::Protobuf; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::error::ChannelError; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelCloseConfirm"; +pub const CHAN_CLOSE_CONFIRM_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelCloseConfirm"; /// /// Message definition for the second step in the channel close handshake (the `ChanCloseConfirm` @@ -34,7 +33,7 @@ impl Msg for MsgChannelCloseConfirm { type Raw = RawMsgChannelCloseConfirm; fn type_url(&self) -> String { - TYPE_URL.to_string() + CHAN_CLOSE_CONFIRM_TYPE_URL.to_string() } } @@ -74,12 +73,12 @@ impl From for RawMsgChannelCloseConfirm { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseConfirm as RawMsgChannelCloseConfirm; use ibc_proto::ibc::core::client::v1::Height; use ibc_testkit::utils::core::channel::dummy_raw_msg_chan_close_confirm; - use crate::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm; - use crate::prelude::*; + use crate::msgs::chan_close_confirm::MsgChannelCloseConfirm; #[test] fn parse_channel_close_confirm_msg() { diff --git a/crates/ibc/src/core/ics04_channel/msgs/chan_close_init.rs b/crates/ibc-core/ics04-channel/types/src/msgs/chan_close_init.rs similarity index 92% rename from crates/ibc/src/core/ics04_channel/msgs/chan_close_init.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/chan_close_init.rs index dbbea054b..dafc18dcb 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/chan_close_init.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/chan_close_init.rs @@ -1,13 +1,12 @@ +use ibc_core_host_types::identifiers::{ChannelId, PortId}; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseInit as RawMsgChannelCloseInit; use ibc_proto::Protobuf; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; +use crate::error::ChannelError; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelCloseInit"; +pub const CHAN_CLOSE_INIT_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelCloseInit"; /// /// Message definition for the first step in the channel close handshake (`ChanCloseInit` datagram). @@ -29,7 +28,7 @@ impl Msg for MsgChannelCloseInit { type Raw = RawMsgChannelCloseInit; fn type_url(&self) -> String { - TYPE_URL.to_string() + CHAN_CLOSE_INIT_TYPE_URL.to_string() } } @@ -59,12 +58,11 @@ impl From for RawMsgChannelCloseInit { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelCloseInit as RawMsgChannelCloseInit; use ibc_testkit::utils::core::channel::dummy_raw_msg_chan_close_init; - use test_log::test; - use crate::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit; - use crate::prelude::*; + use crate::msgs::chan_close_init::MsgChannelCloseInit; #[test] fn parse_channel_close_init_msg() { diff --git a/crates/ibc/src/core/ics04_channel/msgs/chan_open_ack.rs b/crates/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs similarity index 93% rename from crates/ibc/src/core/ics04_channel/msgs/chan_open_ack.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs index 65bbb1f4b..c2f962d64 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/chan_open_ack.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/chan_open_ack.rs @@ -1,16 +1,15 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::identifiers::{ChannelId, PortId}; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenAck as RawMsgChannelOpenAck; use ibc_proto::Protobuf; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::Version; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::error::ChannelError; +use crate::Version; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenAck"; +pub const CHAN_OPEN_ACK_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenAck"; /// Message definition for the third step in the channel open handshake (`ChanOpenAck` datagram). /// @@ -35,7 +34,7 @@ impl Msg for MsgChannelOpenAck { type Raw = RawMsgChannelOpenAck; fn type_url(&self) -> String { - TYPE_URL.to_string() + CHAN_OPEN_ACK_TYPE_URL.to_string() } } @@ -79,13 +78,12 @@ impl From for RawMsgChannelOpenAck { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenAck as RawMsgChannelOpenAck; use ibc_proto::ibc::core::client::v1::Height; use ibc_testkit::utils::core::channel::dummy_raw_msg_chan_open_ack; - use test_log::test; - use crate::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; - use crate::prelude::*; + use crate::msgs::chan_open_ack::MsgChannelOpenAck; #[test] fn parse_channel_open_ack_msg() { diff --git a/crates/ibc/src/core/ics04_channel/msgs/chan_open_confirm.rs b/crates/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs similarity index 92% rename from crates/ibc/src/core/ics04_channel/msgs/chan_open_confirm.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs index 01a03e16e..8ff31e03a 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/chan_open_confirm.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/chan_open_confirm.rs @@ -1,15 +1,14 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::identifiers::{ChannelId, PortId}; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenConfirm as RawMsgChannelOpenConfirm; use ibc_proto::Protobuf; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::error::ChannelError; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenConfirm"; +pub const CHAN_OPEN_CONFIRM_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenConfirm"; /// /// Message definition for the fourth step in the channel open handshake (`ChanOpenConfirm` @@ -34,7 +33,7 @@ impl Msg for MsgChannelOpenConfirm { type Raw = RawMsgChannelOpenConfirm; fn type_url(&self) -> String { - TYPE_URL.to_string() + CHAN_OPEN_CONFIRM_TYPE_URL.to_string() } } @@ -74,13 +73,12 @@ impl From for RawMsgChannelOpenConfirm { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenConfirm as RawMsgChannelOpenConfirm; use ibc_proto::ibc::core::client::v1::Height; use ibc_testkit::utils::core::channel::dummy_raw_msg_chan_open_confirm; - use test_log::test; - use crate::core::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; - use crate::prelude::*; + use crate::msgs::chan_open_confirm::MsgChannelOpenConfirm; #[test] fn parse_channel_open_confirm_msg() { diff --git a/crates/ibc/src/core/ics04_channel/msgs/chan_open_init.rs b/crates/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs similarity index 89% rename from crates/ibc/src/core/ics04_channel/msgs/chan_open_init.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs index 9f68c475e..2a11c07b9 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/chan_open_init.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/chan_open_init.rs @@ -1,17 +1,14 @@ +use ibc_core_host_types::identifiers::{ConnectionId, PortId}; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenInit as RawMsgChannelOpenInit; use ibc_proto::Protobuf; -use crate::core::ics04_channel::channel::{ - verify_connection_hops_length, ChannelEnd, Counterparty, Order, State, -}; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::identifier::{ConnectionId, PortId}; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; +use crate::channel::{verify_connection_hops_length, ChannelEnd, Counterparty, Order, State}; +use crate::error::ChannelError; +use crate::Version; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenInit"; +pub const CHAN_OPEN_INIT_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenInit"; /// /// Message definition for the first step in the channel open handshake (`ChanOpenInit` datagram). @@ -37,7 +34,7 @@ impl MsgChannelOpenInit { /// Checks if the `connection_hops` has a length of `expected`. /// /// Note: Current IBC version only supports one connection hop. - pub(crate) fn verify_connection_hops_length(&self) -> Result<(), ChannelError> { + pub fn verify_connection_hops_length(&self) -> Result<(), ChannelError> { verify_connection_hops_length(&self.connection_hops_on_a, 1) } } @@ -46,7 +43,7 @@ impl Msg for MsgChannelOpenInit { type Raw = RawMsgChannelOpenInit; fn type_url(&self) -> String { - TYPE_URL.to_string() + CHAN_OPEN_INIT_TYPE_URL.to_string() } } @@ -93,12 +90,11 @@ impl From for RawMsgChannelOpenInit { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenInit as RawMsgChannelOpenInit; use ibc_testkit::utils::core::channel::dummy_raw_msg_chan_open_init; - use test_log::test; - use crate::core::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; - use crate::prelude::*; + use crate::msgs::chan_open_init::MsgChannelOpenInit; #[test] fn channel_open_init_from_raw() { diff --git a/crates/ibc/src/core/ics04_channel/msgs/chan_open_try.rs b/crates/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs similarity index 91% rename from crates/ibc/src/core/ics04_channel/msgs/chan_open_try.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs index ae9c60fc2..a671a5352 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/chan_open_try.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/chan_open_try.rs @@ -1,19 +1,16 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId}; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenTry as RawMsgChannelOpenTry; use ibc_proto::Protobuf; -use crate::core::ics04_channel::channel::{ - verify_connection_hops_length, ChannelEnd, Counterparty, Order, State, -}; -use crate::core::ics04_channel::error::ChannelError; -use crate::core::ics04_channel::Version; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::channel::{verify_connection_hops_length, ChannelEnd, Counterparty, Order, State}; +use crate::error::ChannelError; +use crate::Version; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenTry"; +pub const CHAN_OPEN_TRY_TYPE_URL: &str = "/ibc.core.channel.v1.MsgChannelOpenTry"; /// /// Message definition for the second step in the channel open handshake (`ChanOpenTry` datagram). @@ -45,7 +42,7 @@ impl MsgChannelOpenTry { /// Checks if the `connection_hops` has a length of `expected`. /// /// Note: Current IBC version only supports one connection hop. - pub(crate) fn verify_connection_hops_length(&self) -> Result<(), ChannelError> { + pub fn verify_connection_hops_length(&self) -> Result<(), ChannelError> { verify_connection_hops_length(&self.connection_hops_on_b, 1) } } @@ -54,7 +51,7 @@ impl Msg for MsgChannelOpenTry { type Raw = RawMsgChannelOpenTry; fn type_url(&self) -> String { - TYPE_URL.to_string() + CHAN_OPEN_TRY_TYPE_URL.to_string() } } @@ -130,13 +127,12 @@ impl From for RawMsgChannelOpenTry { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgChannelOpenTry as RawMsgChannelOpenTry; use ibc_proto::ibc::core::client::v1::Height; use ibc_testkit::utils::core::channel::dummy_raw_msg_chan_open_try; - use test_log::test; - use crate::core::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; - use crate::prelude::*; + use crate::msgs::chan_open_try::MsgChannelOpenTry; #[test] fn channel_open_try_from_raw() { diff --git a/crates/ibc/src/core/ics04_channel/msgs.rs b/crates/ibc-core/ics04-channel/types/src/msgs/mod.rs similarity index 66% rename from crates/ibc/src/core/ics04_channel/msgs.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/mod.rs index 4b8c39bda..8e518591c 100644 --- a/crates/ibc/src/core/ics04_channel/msgs.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/mod.rs @@ -1,34 +1,32 @@ //! Message definitions for all ICS4 domain types: channel open & close handshake datagrams, as well //! as packets. -use crate::prelude::*; - -pub mod acknowledgement; -pub mod chan_close_confirm; -pub mod chan_close_init; -pub mod chan_open_ack; -pub mod chan_open_confirm; -pub mod chan_open_init; -pub mod chan_open_try; -pub mod recv_packet; -pub mod timeout; -pub mod timeout_on_close; +mod acknowledgement; +mod chan_close_confirm; +mod chan_close_init; +mod chan_open_ack; +mod chan_open_confirm; +mod chan_open_init; +mod chan_open_try; +mod recv_packet; +mod timeout; +mod timeout_on_close; // Opening handshake messages. // Packet specific messages. -pub use acknowledgement::MsgAcknowledgement; +pub use acknowledgement::*; // Closing handshake messages. -pub use chan_close_confirm::MsgChannelCloseConfirm; -pub use chan_close_init::MsgChannelCloseInit; -pub use chan_open_ack::MsgChannelOpenAck; -pub use chan_open_confirm::MsgChannelOpenConfirm; -pub use chan_open_init::MsgChannelOpenInit; -pub use chan_open_try::MsgChannelOpenTry; -pub use recv_packet::MsgRecvPacket; -pub use timeout::MsgTimeout; -pub use timeout_on_close::MsgTimeoutOnClose; - -use crate::core::ics24_host::identifier::PortId; +pub use chan_close_confirm::*; +pub use chan_close_init::*; +pub use chan_open_ack::*; +pub use chan_open_confirm::*; +pub use chan_open_init::*; +pub use chan_open_try::*; +use ibc_core_host_types::identifiers::*; +use ibc_primitives::prelude::*; +pub use recv_packet::*; +pub use timeout::*; +pub use timeout_on_close::*; /// All channel messages #[cfg_attr( @@ -60,7 +58,7 @@ pub enum PacketMsg { TimeoutOnClose(MsgTimeoutOnClose), } -pub(crate) fn channel_msg_to_port_id(msg: &ChannelMsg) -> &PortId { +pub fn channel_msg_to_port_id(msg: &ChannelMsg) -> &PortId { match msg { ChannelMsg::OpenInit(msg) => &msg.port_id_on_a, ChannelMsg::OpenTry(msg) => &msg.port_id_on_b, @@ -71,7 +69,7 @@ pub(crate) fn channel_msg_to_port_id(msg: &ChannelMsg) -> &PortId { } } -pub(crate) fn packet_msg_to_port_id(msg: &PacketMsg) -> &PortId { +pub fn packet_msg_to_port_id(msg: &PacketMsg) -> &PortId { match msg { PacketMsg::Recv(msg) => &msg.packet.port_id_on_b, PacketMsg::Ack(msg) => &msg.packet.port_id_on_a, diff --git a/crates/ibc/src/core/ics04_channel/msgs/recv_packet.rs b/crates/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs similarity index 88% rename from crates/ibc/src/core/ics04_channel/msgs/recv_packet.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs index 91bebda00..da5367036 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/recv_packet.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/recv_packet.rs @@ -1,15 +1,14 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; use ibc_proto::Protobuf; -use crate::core::ics04_channel::error::PacketError; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::error::PacketError; +use crate::packet::Packet; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgRecvPacket"; +pub const RECV_PACKET_TYPE_URL: &str = "/ibc.core.channel.v1.MsgRecvPacket"; /// /// Message definition for the "packet receiving" datagram. @@ -35,7 +34,7 @@ impl Msg for MsgRecvPacket { type Raw = RawMsgRecvPacket; fn type_url(&self) -> String { - TYPE_URL.to_string() + RECV_PACKET_TYPE_URL.to_string() } } @@ -76,14 +75,13 @@ impl From for RawMsgRecvPacket { #[cfg(test)] mod test { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgRecvPacket as RawMsgRecvPacket; use ibc_testkit::utils::core::channel::dummy_raw_msg_recv_packet; use ibc_testkit::utils::core::signer::dummy_bech32_account; - use test_log::test; - use crate::core::ics04_channel::error::PacketError; - use crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket; - use crate::prelude::*; + use crate::error::PacketError; + use crate::msgs::recv_packet::MsgRecvPacket; #[test] fn msg_recv_packet_try_from_raw() { diff --git a/crates/ibc/src/core/ics04_channel/msgs/timeout.rs b/crates/ibc-core/ics04-channel/types/src/msgs/timeout.rs similarity index 90% rename from crates/ibc/src/core/ics04_channel/msgs/timeout.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/timeout.rs index 55dd4bc62..3ae4ba4ce 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/timeout.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/timeout.rs @@ -1,15 +1,15 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::identifiers::Sequence; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgTimeout as RawMsgTimeout; use ibc_proto::Protobuf; -use crate::core::ics04_channel::error::PacketError; -use crate::core::ics04_channel::packet::{Packet, Sequence}; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::error::PacketError; +use crate::packet::Packet; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgTimeout"; +pub const TIMEOUT_TYPE_URL: &str = "/ibc.core.channel.v1.MsgTimeout"; /// /// Message definition for packet timeout domain type, @@ -33,7 +33,7 @@ impl Msg for MsgTimeout { type Raw = RawMsgTimeout; fn type_url(&self) -> String { - TYPE_URL.to_string() + TIMEOUT_TYPE_URL.to_string() } } @@ -79,14 +79,13 @@ impl From for RawMsgTimeout { #[cfg(test)] mod test { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgTimeout as RawMsgTimeout; use ibc_testkit::utils::core::channel::dummy_raw_msg_timeout; use ibc_testkit::utils::core::signer::dummy_bech32_account; - use test_log::test; - use crate::core::ics04_channel::error::PacketError; - use crate::core::ics04_channel::msgs::timeout::MsgTimeout; - use crate::prelude::*; + use crate::error::PacketError; + use crate::msgs::timeout::MsgTimeout; #[test] fn msg_timeout_try_from_raw() { diff --git a/crates/ibc/src/core/ics04_channel/msgs/timeout_on_close.rs b/crates/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs similarity index 90% rename from crates/ibc/src/core/ics04_channel/msgs/timeout_on_close.rs rename to crates/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs index c590e2bf2..e05cf240d 100644 --- a/crates/ibc/src/core/ics04_channel/msgs/timeout_on_close.rs +++ b/crates/ibc-core/ics04-channel/types/src/msgs/timeout_on_close.rs @@ -1,15 +1,15 @@ +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentProofBytes; +use ibc_core_host_types::identifiers::Sequence; +use ibc_primitives::prelude::*; +use ibc_primitives::{Msg, Signer}; use ibc_proto::ibc::core::channel::v1::MsgTimeoutOnClose as RawMsgTimeoutOnClose; use ibc_proto::Protobuf; -use crate::core::ics04_channel::error::PacketError; -use crate::core::ics04_channel::packet::{Packet, Sequence}; -use crate::core::ics23_commitment::commitment::CommitmentProofBytes; -use crate::core::Msg; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; +use crate::error::PacketError; +use crate::packet::Packet; -pub(crate) const TYPE_URL: &str = "/ibc.core.channel.v1.MsgTimeoutOnClose"; +pub const TIMEOUT_ON_CLOSE_TYPE_URL: &str = "/ibc.core.channel.v1.MsgTimeoutOnClose"; /// /// Message definition for packet timeout domain type. @@ -33,7 +33,7 @@ impl Msg for MsgTimeoutOnClose { type Raw = RawMsgTimeoutOnClose; fn type_url(&self) -> String { - TYPE_URL.to_string() + TIMEOUT_ON_CLOSE_TYPE_URL.to_string() } } @@ -85,12 +85,11 @@ impl From for RawMsgTimeoutOnClose { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::MsgTimeoutOnClose as RawMsgTimeoutOnClose; use ibc_testkit::utils::core::channel::dummy_raw_msg_timeout_on_close; - use test_log::test; - use crate::core::ics04_channel::msgs::timeout_on_close::MsgTimeoutOnClose; - use crate::prelude::*; + use crate::msgs::timeout_on_close::MsgTimeoutOnClose; #[test] fn msg_timeout_on_close_try_from_raw() { diff --git a/crates/ibc/src/core/ics04_channel/packet.rs b/crates/ibc-core/ics04-channel/types/src/packet.rs similarity index 88% rename from crates/ibc/src/core/ics04_channel/packet.rs rename to crates/ibc-core/ics04-channel/types/src/packet.rs index eba1ca8e9..8c09af4c9 100644 --- a/crates/ibc/src/core/ics04_channel/packet.rs +++ b/crates/ibc-core/ics04-channel/types/src/packet.rs @@ -1,16 +1,13 @@ //! Defines the packet type - -use core::str::FromStr; - +use ibc_core_client_types::Height; +use ibc_core_host_types::identifiers::{ChannelId, PortId, Sequence}; +use ibc_primitives::prelude::*; +use ibc_primitives::Expiry::Expired; +use ibc_primitives::Timestamp; use ibc_proto::ibc::core::channel::v1::{Packet as RawPacket, PacketState as RawPacketState}; use super::timeout::TimeoutHeight; -use crate::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::core::timestamp::Expiry::Expired; -use crate::core::timestamp::Timestamp; -use crate::prelude::*; -use crate::Height; +use crate::error::PacketError; /// Enumeration of proof carrying ICS4 message, helper for relayer. #[derive(Clone, Debug, PartialEq, Eq)] @@ -53,65 +50,6 @@ impl core::fmt::Display for PacketMsgType { } } -#[cfg_attr( - feature = "parity-scale-codec", - derive( - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_info::TypeInfo - ) -)] -#[cfg_attr( - feature = "borsh", - derive(borsh::BorshSerialize, borsh::BorshDeserialize) -)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] -/// The sequence number of a packet enforces ordering among packets from the same source. -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Sequence(u64); - -impl FromStr for Sequence { - type Err = ChannelError; - - fn from_str(s: &str) -> Result { - Ok(Self::from(s.parse::().map_err(|e| { - ChannelError::InvalidStringAsSequence { - value: s.to_string(), - error: e, - } - })?)) - } -} - -impl Sequence { - pub fn is_zero(&self) -> bool { - self.0 == 0 - } - - pub fn increment(&self) -> Sequence { - Sequence(self.0 + 1) - } -} - -impl From for Sequence { - fn from(seq: u64) -> Self { - Sequence(seq) - } -} - -impl From for u64 { - fn from(s: Sequence) -> u64 { - s.0 - } -} - -impl core::fmt::Display for Sequence { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!(f, "{}", self.0) - } -} - /// The packet type; this is what applications send to one another. /// /// Each application defines the structure of the `data` field. @@ -138,7 +76,7 @@ pub struct Packet { pub chan_id_on_b: ChannelId, #[cfg_attr( feature = "serde", - serde(serialize_with = "crate::serializers::ser_hex_upper") + serde(serialize_with = "ibc_core_commitment_types::serializer::ser_hex_upper") )] pub data: Vec, pub timeout_height_on_b: TimeoutHeight, @@ -187,7 +125,7 @@ impl core::fmt::Debug for Packet { impl Packet { /// Checks whether a packet from a - /// [`SendPacket`](crate::core::ics04_channel::events::SendPacket) + /// [`SendPacket`](crate::events::SendPacket) /// event is timed-out relative to the current state of the /// destination chain. /// @@ -196,9 +134,9 @@ impl Packet { /// the height `dst_chain_height`. /// /// Note: a timed-out packet should result in a - /// [`MsgTimeout`](crate::core::ics04_channel::msgs::timeout::MsgTimeout), + /// [`MsgTimeout`](crate::msgs::MsgTimeout), /// instead of the common-case where it results in - /// [`MsgRecvPacket`](crate::core::ics04_channel::msgs::recv_packet::MsgRecvPacket). + /// [`MsgRecvPacket`](crate::msgs::MsgRecvPacket). pub fn timed_out(&self, dst_chain_ts: &Timestamp, dst_chain_height: Height) -> bool { let height_timed_out = self.timeout_height_on_b.has_expired(dst_chain_height); @@ -275,7 +213,7 @@ impl TryFrom for Packet { impl From for RawPacket { fn from(packet: Packet) -> Self { RawPacket { - sequence: packet.seq_on_a.0, + sequence: packet.seq_on_a.value(), source_port: packet.port_id_on_a.to_string(), source_channel: packet.chan_id_on_a.to_string(), destination_port: packet.port_id_on_b.to_string(), @@ -311,7 +249,7 @@ pub struct PacketState { pub seq: Sequence, #[cfg_attr( feature = "serde", - serde(serialize_with = "crate::serializers::ser_hex_upper") + serde(serialize_with = "ibc_core_commitment_types::serializer::ser_hex_upper") )] pub data: Vec, } @@ -364,7 +302,7 @@ impl TryFrom for PacketState { impl From for RawPacketState { fn from(packet: PacketState) -> Self { Self { - sequence: packet.seq.0, + sequence: packet.seq.value(), port_id: packet.port_id.to_string(), channel_id: packet.chan_id.to_string(), data: packet.data, @@ -374,13 +312,12 @@ impl From for RawPacketState { #[cfg(test)] mod tests { + use ibc_primitives::prelude::*; use ibc_proto::ibc::core::channel::v1::Packet as RawPacket; use ibc_proto::ibc::core::client::v1::Height as RawHeight; use ibc_testkit::utils::core::channel::dummy_raw_packet; - use test_log::test; - use crate::core::ics04_channel::packet::Packet; - use crate::prelude::*; + use crate::packet::Packet; #[test] fn packet_try_from_raw() { diff --git a/crates/ibc/src/core/ics04_channel/timeout.rs b/crates/ibc-core/ics04-channel/types/src/timeout.rs similarity index 97% rename from crates/ibc/src/core/ics04_channel/timeout.rs rename to crates/ibc-core/ics04-channel/types/src/timeout.rs index e70a1efd7..3a7e825ce 100644 --- a/crates/ibc/src/core/ics04_channel/timeout.rs +++ b/crates/ibc-core/ics04-channel/types/src/timeout.rs @@ -2,12 +2,11 @@ use core::fmt::{Display, Error as FmtError, Formatter}; +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::Height; +use ibc_primitives::prelude::*; use ibc_proto::ibc::core::client::v1::Height as RawHeight; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics02_client::height::Height; -use crate::prelude::*; - /// Indicates a consensus height on the destination chain after which the packet /// will no longer be processed, and will instead count as having timed-out. /// @@ -190,7 +189,7 @@ mod tests { where D: serde::Deserializer<'de>, { - use crate::core::ics02_client::height::Height as Ics02Height; + use ibc_core_client_types::Height as Ics02Height; // Here we have to use a bespoke struct as well in order to deserialize // a height which may have a revision height equal to zero. diff --git a/crates/ibc/src/core/ics04_channel/version.rs b/crates/ibc-core/ics04-channel/types/src/version.rs similarity index 98% rename from crates/ibc/src/core/ics04_channel/version.rs rename to crates/ibc-core/ics04-channel/types/src/version.rs index 9e07bfe21..bf41109da 100644 --- a/crates/ibc/src/core/ics04_channel/version.rs +++ b/crates/ibc-core/ics04-channel/types/src/version.rs @@ -6,8 +6,9 @@ use core::convert::Infallible; use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; +use ibc_primitives::prelude::*; + use super::error::ChannelError; -use crate::prelude::*; /// The version field for a `ChannelEnd`. /// diff --git a/crates/ibc-core/ics23-commitment/types/Cargo.toml b/crates/ibc-core/ics23-commitment/types/Cargo.toml new file mode 100644 index 000000000..f29aff6c0 --- /dev/null +++ b/crates/ibc-core/ics23-commitment/types/Cargo.toml @@ -0,0 +1,74 @@ +[package] +name = "ibc-core-commitment-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "commitment", "types"] +readme = "./../../README.md" +description = """ + Maintained by `ibc-rs`, encapsulates essential ICS-23 Vector Commitments data structures and domain types, + as specified in the Inter-Blockchain Communication (IBC) protocol. Designed for universal applicability + to facilitate development and integration across diverse IBC-enabled projects. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +schemars = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-proto = { workspace = true } +ibc-primitives = {workspace = true } +ics23 = { workspace = true, features = ["host-functions"] } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "serde/std", + "subtle-encoding/std", + "ibc-primitives/std", + "ibc-proto/std", + "ics23/std", +] +serde = [ + "dep:serde", + "ibc-primitives/serde", + "ibc-proto/serde", + "ics23/serde", +] +schema = [ + "dep:schemars", + "ibc-proto/json-schema", + "ibc-primitives/schema", + "serde", + "std" +] +borsh = [ + "dep:borsh", + "ibc-proto/borsh", + "ibc-primitives/borsh", +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-primitives/parity-scale-codec", + "ibc-proto/parity-scale-codec", +] + diff --git a/crates/ibc/src/core/ics23_commitment/commitment.rs b/crates/ibc-core/ics23-commitment/types/src/commitment.rs similarity index 96% rename from crates/ibc/src/core/ics23_commitment/commitment.rs rename to crates/ibc-core/ics23-commitment/types/src/commitment.rs index 556f58458..0969c565c 100644 --- a/crates/ibc/src/core/ics23_commitment/commitment.rs +++ b/crates/ibc-core/ics23-commitment/types/src/commitment.rs @@ -3,12 +3,12 @@ use core::convert::TryFrom; use core::fmt; +use ibc_primitives::prelude::*; use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; use subtle_encoding::{Encoding, Hex}; use super::merkle::MerkleProof; -use crate::core::ics23_commitment::error::CommitmentError; -use crate::prelude::*; +use crate::error::CommitmentError; /// Encodes a commitment root; most often a Merkle tree root hash. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -17,7 +17,7 @@ use crate::prelude::*; pub struct CommitmentRoot { #[cfg_attr( feature = "serde", - serde(serialize_with = "crate::serializers::ser_hex_upper") + serde(serialize_with = "crate::serializer::ser_hex_upper") )] bytes: Vec, } @@ -73,7 +73,7 @@ impl From> for CommitmentRoot { pub struct CommitmentProofBytes { #[cfg_attr( feature = "serde", - serde(serialize_with = "crate::serializers::ser_hex_upper") + serde(serialize_with = "crate::serializer::ser_hex_upper") )] bytes: Vec, } diff --git a/crates/ibc/src/core/ics23_commitment/error.rs b/crates/ibc-core/ics23-commitment/types/src/error.rs similarity index 97% rename from crates/ibc/src/core/ics23_commitment/error.rs rename to crates/ibc-core/ics23-commitment/types/src/error.rs index 1a4bcaaeb..3b7b17575 100644 --- a/crates/ibc/src/core/ics23_commitment/error.rs +++ b/crates/ibc-core/ics23-commitment/types/src/error.rs @@ -1,8 +1,7 @@ //! Defines the commitment error type -use alloc::string::String; - use displaydoc::Display; +use ibc_primitives::prelude::*; use prost::DecodeError; #[derive(Debug, Display)] diff --git a/crates/ibc-core/ics23-commitment/types/src/lib.rs b/crates/ibc-core/ics23-commitment/types/src/lib.rs new file mode 100644 index 000000000..a4cb15890 --- /dev/null +++ b/crates/ibc-core/ics23-commitment/types/src/lib.rs @@ -0,0 +1,31 @@ +//! ICS-23: Commitment implementation of a cryptographic scheme that verifies +//! state transitions between chains. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +pub mod commitment; +pub mod error; +pub mod merkle; +pub mod specs; + +#[cfg(feature = "serde")] +pub mod serializer; + +/// Re-exports ICS-23 proto types from the `ibc-proto` crate, which are +/// used in the implementation of dependent IBC crates. +pub mod proto { + pub use ibc_proto::ibc::core::commitment::*; + pub use ibc_proto::ics23; +} diff --git a/crates/ibc/src/core/ics23_commitment/merkle.rs b/crates/ibc-core/ics23-commitment/types/src/merkle.rs similarity index 96% rename from crates/ibc/src/core/ics23_commitment/merkle.rs rename to crates/ibc-core/ics23-commitment/types/src/merkle.rs index 26908e6f0..50e711c1d 100644 --- a/crates/ibc/src/core/ics23_commitment/merkle.rs +++ b/crates/ibc-core/ics23-commitment/types/src/merkle.rs @@ -1,5 +1,6 @@ //! Merkle proof utilities +use ibc_primitives::prelude::*; use ibc_proto::ibc::core::commitment::v1::{MerklePath, MerkleProof as RawMerkleProof, MerkleRoot}; use ibc_proto::ics23::commitment_proof::Proof; use ibc_proto::ics23::{ @@ -7,10 +8,9 @@ use ibc_proto::ics23::{ NonExistenceProof, }; -use crate::core::ics23_commitment::commitment::{CommitmentPrefix, CommitmentRoot}; -use crate::core::ics23_commitment::error::CommitmentError; -use crate::core::ics23_commitment::specs::ProofSpecs; -use crate::prelude::*; +use crate::commitment::{CommitmentPrefix, 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:?}")]; diff --git a/crates/ibc-core/ics23-commitment/types/src/serializer.rs b/crates/ibc-core/ics23-commitment/types/src/serializer.rs new file mode 100644 index 000000000..b3950b218 --- /dev/null +++ b/crates/ibc-core/ics23-commitment/types/src/serializer.rs @@ -0,0 +1,14 @@ +use ibc_primitives::prelude::*; +use serde::ser::{Serialize, Serializer}; +use subtle_encoding::{Encoding, Hex}; + +pub fn ser_hex_upper(data: T, serializer: S) -> Result +where + S: Serializer, + T: AsRef<[u8]>, +{ + let hex = Hex::upper_case() + .encode_to_string(data) + .map_err(|e| serde::ser::Error::custom(format!("failed to serialize hex: {}", e)))?; + hex.serialize(serializer) +} diff --git a/crates/ibc/src/core/ics23_commitment/specs.rs b/crates/ibc-core/ics23-commitment/types/src/specs.rs similarity index 99% rename from crates/ibc/src/core/ics23_commitment/specs.rs rename to crates/ibc-core/ics23-commitment/types/src/specs.rs index ae7787a39..3c2b1df75 100644 --- a/crates/ibc/src/core/ics23_commitment/specs.rs +++ b/crates/ibc-core/ics23-commitment/types/src/specs.rs @@ -1,8 +1,7 @@ //! Defines proof specs, which encode the structure of proofs +use ibc_primitives::prelude::*; use ibc_proto::ics23::{InnerSpec as RawInnerSpec, LeafOp as RawLeafOp, ProofSpec as RawProofSpec}; - -use crate::prelude::*; /// An array of proof specifications. /// /// This type encapsulates different types of proof specifications, mostly predefined, e.g., for diff --git a/crates/ibc-core/ics24-host/Cargo.toml b/crates/ibc-core/ics24-host/Cargo.toml new file mode 100644 index 000000000..dc28e951f --- /dev/null +++ b/crates/ibc-core/ics24-host/Cargo.toml @@ -0,0 +1,90 @@ +[package] +name = "ibc-core-host" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "host"] +readme = "./../README.md" +description = """ + Maintained by `ibc-rs`, contains essential top-level traits designed for the seamless integration + of host chains, facilitating access to the host's storage, the efficient retrieval of states and + metadata crucial for the execution of any IBC datagrams. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-core-client-types = { workspace = true } +ibc-core-client-context = { workspace = true } +ibc-core-connection-types = { workspace = true } +ibc-core-channel-types = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-primitives = { workspace = true } + +[dev-dependencies] +rstest = { workspace = true } + +[features] +default = ["std"] +std = [ + "ibc-core-client-types/std", + "ibc-core-client-context/std", + "ibc-core-connection-types/std", + "ibc-core-channel-types/std", + "ibc-core-commitment-types/std", + "ibc-core-host-types/std", + "ibc-core-handler-types/std", + "ibc-primitives/std", +] +serde = [ + "ibc-core-client-types/serde", + "ibc-core-client-context/serde", + "ibc-core-connection-types/serde", + "ibc-core-channel-types/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host-types/serde", + "ibc-core-handler-types/serde", + "ibc-primitives/serde", +] +schema = [ + "ibc-core-client-types/schema", + "ibc-core-connection-types/schema", + "ibc-core-channel-types/schema", + "ibc-core-commitment-types/schema", + "ibc-core-host-types/schema", + "ibc-core-handler-types/schema", + "ibc-primitives/schema", + "serde", + "std" +] +borsh = [ + "ibc-core-client-types/borsh", + "ibc-core-connection-types/borsh", + "ibc-core-channel-types/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host-types/borsh", + "ibc-core-handler-types/borsh", + "ibc-primitives/borsh", +] +parity-scale-codec = [ + "ibc-core-client-types/parity-scale-codec", + "ibc-core-connection-types/parity-scale-codec", + "ibc-core-channel-types/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] \ No newline at end of file diff --git a/crates/ibc/src/core/context.rs b/crates/ibc-core/ics24-host/src/context.rs similarity index 75% rename from crates/ibc/src/core/context.rs rename to crates/ibc-core/ics24-host/src/context.rs index 288717f4b..b2525b3cb 100644 --- a/crates/ibc/src/core/context.rs +++ b/crates/ibc-core/ics24-host/src/context.rs @@ -1,97 +1,33 @@ -use alloc::string::String; use core::time::Duration; -use derive_more::From; -use displaydoc::Display; -use ibc_proto::google::protobuf::Any; - -use super::ics02_client::client_state::ClientState; -use super::ics02_client::consensus_state::ConsensusState; -use super::ics02_client::{ClientExecutionContext, ClientValidationContext}; -use super::ics24_host::identifier::PortId; -use crate::core::events::IbcEvent; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::connection::ConnectionEnd; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics03_connection::version::{ +use ibc_core_channel_types::channel::ChannelEnd; +use ibc_core_channel_types::commitment::{AcknowledgementCommitment, PacketCommitment}; +use ibc_core_channel_types::packet::Receipt; +use ibc_core_client_context::client_state::ClientState; +use ibc_core_client_context::consensus_state::ConsensusState; +use ibc_core_client_context::{ClientExecutionContext, ClientValidationContext}; +use ibc_core_client_types::Height; +use ibc_core_commitment_types::commitment::CommitmentPrefix; +use ibc_core_connection_types::version::{ get_compatible_versions, pick_version, Version as ConnectionVersion, }; -use crate::core::ics04_channel::channel::ChannelEnd; -use crate::core::ics04_channel::commitment::{AcknowledgementCommitment, PacketCommitment}; -use crate::core::ics04_channel::context::calculate_block_delay; -use crate::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::core::ics04_channel::packet::{Receipt, Sequence}; -use crate::core::ics23_commitment::commitment::CommitmentPrefix; -use crate::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::core::ics24_host::path::{ +use ibc_core_connection_types::ConnectionEnd; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::events::IbcEvent; +use ibc_core_host_types::identifiers::{ClientId, ConnectionId, Sequence}; +use ibc_core_host_types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, CommitmentPath, ConnectionPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use crate::core::timestamp::Timestamp; -use crate::prelude::*; -use crate::signer::Signer; -use crate::Height; - -/// Top-level error -#[derive(Debug, Display, From)] -pub enum ContextError { - /// ICS02 Client error: {0} - ClientError(ClientError), - /// ICS03 Connection error: {0} - ConnectionError(ConnectionError), - /// ICS04 Channel error: {0} - ChannelError(ChannelError), - /// ICS04 Packet error: {0} - PacketError(PacketError), -} - -#[cfg(feature = "std")] -impl std::error::Error for ContextError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match &self { - Self::ClientError(e) => Some(e), - Self::ConnectionError(e) => Some(e), - Self::ChannelError(e) => Some(e), - Self::PacketError(e) => Some(e), - } - } -} - -/// Error returned from entrypoint functions [`dispatch`][super::dispatch], [`validate`][super::validate] and -/// [`execute`][super::execute]. -#[derive(Debug, Display)] -pub enum RouterError { - /// context error: `{0}` - ContextError(ContextError), - /// unknown type URL `{url}` - UnknownMessageTypeUrl { url: String }, - /// the message is malformed and cannot be decoded error: `{reason}` - MalformedMessageBytes { reason: String }, - /// port `{port_id}` is unknown - UnknownPort { port_id: PortId }, - /// module not found - ModuleNotFound, -} +use ibc_primitives::prelude::*; +use ibc_primitives::proto::Any; +use ibc_primitives::{Signer, Timestamp}; -impl From for RouterError { - fn from(error: ContextError) -> Self { - Self::ContextError(error) - } -} - -#[cfg(feature = "std")] -impl std::error::Error for RouterError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match &self { - Self::ContextError(e) => Some(e), - _ => None, - } - } -} +use crate::utils::calculate_block_delay; /// Context to be implemented by the host that provides all "read-only" methods. /// -/// Trait used for the top-level [`validate`](crate::core::validate) +/// Trait used for the top-level `validate` entrypoint in the `ibc-core` crate. pub trait ValidationContext { type V: ClientValidationContext; type E: ClientExecutionContext; @@ -147,7 +83,7 @@ pub trait ValidationContext { /// requirements](https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements#client-state-validation) /// /// Additionally, implementations specific to individual chains can be found - /// in the [hosts](crate::hosts) module. + /// in the `ibc-core-hostkit` crate. fn validate_self_client( &self, client_state_of_host_on_counterparty: Any, @@ -159,13 +95,13 @@ pub trait ValidationContext { /// Returns a counter on how many connections have been created thus far. fn connection_counter(&self) -> Result; - /// Function required by ICS 03. Returns the list of all possible versions that the connection + /// Function required by ICS-03. Returns the list of all possible versions that the connection /// handshake protocol supports. fn get_compatible_versions(&self) -> Vec { get_compatible_versions() } - /// Function required by ICS 03. Returns one version out of the supplied list of versions, which the + /// Function required by ICS-03. Returns one version out of the supplied list of versions, which the /// connection handshake protocol prefers. fn pick_version( &self, @@ -228,7 +164,7 @@ pub trait ValidationContext { /// Context to be implemented by the host that provides all "write-only" methods. /// -/// Trait used for the top-level [`execute`](crate::core::execute) and [`dispatch`](crate::core::dispatch) +/// Trait used for the top-level `execute` and `dispatch` entrypoints in the `ibc-core` crate. pub trait ExecutionContext: ValidationContext { /// Retrieve the context that implements all clients' `ExecutionContext`. fn get_client_execution_context(&mut self) -> &mut Self::E; diff --git a/crates/ibc-core/ics24-host/src/lib.rs b/crates/ibc-core/ics24-host/src/lib.rs new file mode 100644 index 000000000..7d64b4e38 --- /dev/null +++ b/crates/ibc-core/ics24-host/src/lib.rs @@ -0,0 +1,29 @@ +//! Provides essential top-level traits designed for the seamless integration of +//! host chains with ibc-rs. It streamlines access to the host's storage, +//! facilitating the efficient retrieval of states and metadata crucial for the +//! execution of IBC logics. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(any(test, feature = "std"))] +extern crate std; + +pub(crate) mod utils; + +mod context; +pub use context::*; + +/// Re-exports ICS-24 data structures from `ibc-core-host-types` crate. +pub mod types { + #[doc(inline)] + pub use ibc_core_host_types::*; +} diff --git a/crates/ibc-core/ics24-host/src/utils.rs b/crates/ibc-core/ics24-host/src/utils.rs new file mode 100644 index 000000000..9ba2cbe08 --- /dev/null +++ b/crates/ibc-core/ics24-host/src/utils.rs @@ -0,0 +1,47 @@ +use core::time::Duration; + +pub fn calculate_block_delay( + delay_period_time: &Duration, + max_expected_time_per_block: &Duration, +) -> u64 { + let delay_period_time = delay_period_time.as_secs(); + let max_expected_time_per_block = max_expected_time_per_block.as_secs(); + if max_expected_time_per_block == 0 { + return 0; + } + if delay_period_time % max_expected_time_per_block == 0 { + return delay_period_time / max_expected_time_per_block; + } + + // TODO: Use `u64::div_ceil` here instead + (delay_period_time / max_expected_time_per_block) + 1 +} + +#[cfg(test)] +mod tests { + + use rstest::rstest; + + use super::*; + + #[rstest] + #[case::remainder_zero(10, 2, 5)] + #[case::remainder_not_zero(10, 3, 4)] + #[case::max_expected_zero(10, 0, 0)] + #[case::delay_period_zero(0, 2, 0)] + #[case::both_zero(0, 0, 0)] + #[case::delay_less_than_max(10, 11, 1)] + fn test_calculate_block_delay_zero( + #[case] delay_period_time: u64, + #[case] max_expected_time_per_block: u64, + #[case] expected: u64, + ) { + assert_eq!( + calculate_block_delay( + &Duration::from_secs(delay_period_time), + &Duration::from_secs(max_expected_time_per_block) + ), + expected + ); + } +} diff --git a/crates/ibc-core/ics24-host/tendermint/Cargo.toml b/crates/ibc-core/ics24-host/tendermint/Cargo.toml new file mode 100644 index 000000000..94f31a815 --- /dev/null +++ b/crates/ibc-core/ics24-host/tendermint/Cargo.toml @@ -0,0 +1,100 @@ +[package] +name = "ibc-core-host-tendermint" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "tendermint"] +readme = "./../README.md" +description = """ + Maintained by `ibc-rs`, contains Tendermint-specific helper traits and implementations + to facilitate IBC integration, ensuring proper interaction with modules/components + beyond the IBC modules on host chains. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true} +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +serde = { workspace = true, optional = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-client-tendermint = { workspace = true } +ibc-core-client-types = { workspace = true } +ibc-core-client-context = { workspace = true } +ibc-core-connection-types = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-primitives = { workspace = true } +ibc-proto = { workspace = true } + +# cosmos dependencies +tendermint = { workspace = true } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[dev-dependencies] +ibc-testkit = { workspace = true } +rstest = { workspace = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "serde/std", + "subtle-encoding/std", + "ibc-core-client-types/std", + "ibc-core-client-context/std", + "ibc-core-connection-types/std", + "ibc-core-commitment-types/std", + "ibc-core-host-types/std", + "ibc-core-handler-types/std", + "ibc-primitives/std", + "ibc-proto/std", +] +serde = [ + "dep:serde", + "ibc-client-tendermint/serde", + "ibc-core-client-types/serde", + "ibc-core-client-context/serde", + "ibc-core-connection-types/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host-types/serde", + "ibc-core-handler-types/serde", + "ibc-primitives/serde", + "ibc-proto/serde", +] +borsh = [ + "dep:borsh", + "ibc-client-tendermint/borsh", + "ibc-core-client-types/borsh", + "ibc-core-connection-types/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host-types/borsh", + "ibc-primitives/borsh", + "ibc-proto/borsh", +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-client-tendermint/parity-scale-codec", + "ibc-core-client-types/parity-scale-codec", + "ibc-core-connection-types/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", + "ibc-proto/parity-scale-codec", +] diff --git a/crates/ibc-core/ics24-host/tendermint/src/lib.rs b/crates/ibc-core/ics24-host/tendermint/src/lib.rs new file mode 100644 index 000000000..27bce7e66 --- /dev/null +++ b/crates/ibc-core/ics24-host/tendermint/src/lib.rs @@ -0,0 +1,28 @@ +//! Provides convenience traits and implementations for Tendermint-based hosts +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] +pub mod upgrade_proposal; + +mod validate_self_client; +pub use validate_self_client::ValidateSelfClientContext; + +/// Re-exports necessary proto types for implementing the tendermint client +/// upgradeability feature. +pub mod proto { + pub use ibc_proto::cosmos::upgrade::*; +} + +/// ABCI store/query path for the IBC sub-store +pub const IBC_QUERY_PATH: &str = "store/ibc/key"; + +/// ABCI store/query path for the upgrade sub-store +pub const SDK_UPGRADE_QUERY_PATH: &str = "store/upgrade/key"; diff --git a/crates/ibc/src/hosts/tendermint/upgrade_proposal/context.rs b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/context.rs similarity index 88% rename from crates/ibc/src/hosts/tendermint/upgrade_proposal/context.rs rename to crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/context.rs index 29428a2be..eaa9313a8 100644 --- a/crates/ibc/src/hosts/tendermint/upgrade_proposal/context.rs +++ b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/context.rs @@ -5,12 +5,13 @@ //! [Basecoin-rs](https://github.com/informalsystems/basecoin-rs) repository. //! If it proves to be generic enough, we may move it to the ICS02 section. +use ibc_core_client_context::client_state::ClientState; +use ibc_core_client_context::consensus_state::ConsensusState; +use ibc_core_client_context::{ClientExecutionContext, ClientValidationContext}; +use ibc_core_client_types::error::UpgradeClientError; +use ibc_core_host_types::path::UpgradeClientPath; + use super::Plan; -use crate::core::ics02_client::client_state::ClientState; -use crate::core::ics02_client::consensus_state::ConsensusState; -use crate::core::ics02_client::error::UpgradeClientError; -use crate::core::ics02_client::{ClientExecutionContext, ClientValidationContext}; -use crate::core::ics24_host::path::UpgradeClientPath; /// Helper context to validate client upgrades, providing methods to retrieve /// an upgrade plan and related upgraded client and consensus states. diff --git a/crates/ibc/src/hosts/tendermint/upgrade_proposal/events.rs b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/events.rs similarity index 98% rename from crates/ibc/src/hosts/tendermint/upgrade_proposal/events.rs rename to crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/events.rs index 0cb380d18..b4e3550c9 100644 --- a/crates/ibc/src/hosts/tendermint/upgrade_proposal/events.rs +++ b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/events.rs @@ -1,10 +1,7 @@ //! Definitions of events emitted when an upgrade client is proposed or executed. -use alloc::borrow::ToOwned; -use alloc::string::{String, ToString}; -use alloc::vec; - use derive_more::From; +use ibc_primitives::prelude::*; use tendermint::abci; const UPGRADE_CHAIN_EVENT: &str = "upgrade_chain"; diff --git a/crates/ibc/src/hosts/tendermint/upgrade_proposal/handler.rs b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/handler.rs similarity index 77% rename from crates/ibc/src/hosts/tendermint/upgrade_proposal/handler.rs rename to crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/handler.rs index 0680854ca..31f187175 100644 --- a/crates/ibc/src/hosts/tendermint/upgrade_proposal/handler.rs +++ b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/handler.rs @@ -1,13 +1,10 @@ -use alloc::string::ToString; - +use ibc_client_tendermint::types::ClientState as TmClientState; +use ibc_core_client_types::error::UpgradeClientError; +use ibc_core_host_types::path::UpgradeClientPath; +use ibc_primitives::prelude::*; use tendermint::abci::Event as TmEvent; -use crate::clients::ics07_tendermint::client_state::ClientState as TmClientState; -use crate::core::ics02_client::error::UpgradeClientError; -use crate::core::ics24_host::path::UpgradeClientPath; -use crate::hosts::tendermint::upgrade_proposal::{ - UpgradeClientProposal, UpgradeExecutionContext, UpgradeProposal, -}; +use crate::upgrade_proposal::{UpgradeClientProposal, UpgradeExecutionContext, UpgradeProposal}; /// Handles an upgrade client proposal /// diff --git a/crates/ibc/src/hosts/tendermint/upgrade_proposal/mod.rs b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/mod.rs similarity index 100% rename from crates/ibc/src/hosts/tendermint/upgrade_proposal/mod.rs rename to crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/mod.rs diff --git a/crates/ibc/src/hosts/tendermint/upgrade_proposal/plan.rs b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/plan.rs similarity index 94% rename from crates/ibc/src/hosts/tendermint/upgrade_proposal/plan.rs rename to crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/plan.rs index 075e0b692..d1a25adcc 100644 --- a/crates/ibc/src/hosts/tendermint/upgrade_proposal/plan.rs +++ b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/plan.rs @@ -1,15 +1,12 @@ //! Definition of domain `Plan` type. -use alloc::format; -use alloc::string::{String, ToString}; - +use ibc_core_client_types::error::UpgradeClientError; +use ibc_primitives::prelude::*; use ibc_proto::cosmos::upgrade::v1beta1::Plan as RawPlan; use ibc_proto::google::protobuf::Any; use ibc_proto::Protobuf; -use crate::core::ics02_client::error::UpgradeClientError; - -pub(crate) const TYPE_URL: &str = "/cosmos.upgrade.v1beta1.Plan"; +pub const TYPE_URL: &str = "/cosmos.upgrade.v1beta1.Plan"; /// Specifies information about a planned upgrade and at which height it should /// be performed. diff --git a/crates/ibc/src/hosts/tendermint/upgrade_proposal/proposal.rs b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/proposal.rs similarity index 96% rename from crates/ibc/src/hosts/tendermint/upgrade_proposal/proposal.rs rename to crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/proposal.rs index 46deaeda2..5f24c9523 100644 --- a/crates/ibc/src/hosts/tendermint/upgrade_proposal/proposal.rs +++ b/crates/ibc-core/ics24-host/tendermint/src/upgrade_proposal/proposal.rs @@ -1,13 +1,12 @@ //! Definition of domain `UpgradeProposal` type for handling upgrade client proposal -use alloc::string::{String, ToString}; - +use ibc_core_client_types::error::UpgradeClientError; +use ibc_primitives::prelude::*; use ibc_proto::google::protobuf::Any; use ibc_proto::ibc::core::client::v1::UpgradeProposal as RawUpgradeProposal; use ibc_proto::Protobuf; use super::Plan; -use crate::core::ics02_client::error::UpgradeClientError; /// Defines a governance proposal of type `Content` that enables the initiation /// of an IBC breaking upgrade and specifies the new client state that should be diff --git a/crates/ibc/src/hosts/tendermint/validate_self_client.rs b/crates/ibc-core/ics24-host/tendermint/src/validate_self_client.rs similarity index 72% rename from crates/ibc/src/hosts/tendermint/validate_self_client.rs rename to crates/ibc-core/ics24-host/tendermint/src/validate_self_client.rs index 6b7762114..13a762a3b 100644 --- a/crates/ibc/src/hosts/tendermint/validate_self_client.rs +++ b/crates/ibc-core/ics24-host/tendermint/src/validate_self_client.rs @@ -1,19 +1,17 @@ -use alloc::format; -use alloc::string::{String, ToString}; use core::time::Duration; +use ibc_client_tendermint::client_state::ClientStateWrapper; +use ibc_core_client_context::client_state::ClientStateCommon; +use ibc_core_client_types::error::ClientError; +use ibc_core_client_types::Height; +use ibc_core_commitment_types::specs::ProofSpecs; +use ibc_core_connection_types::error::ConnectionError; +use ibc_core_handler_types::error::ContextError; +use ibc_core_host_types::identifiers::ChainId; +use ibc_primitives::prelude::*; use ibc_proto::google::protobuf::Any; use tendermint::trust_threshold::TrustThresholdFraction as TendermintTrustThresholdFraction; -use crate::clients::ics07_tendermint::client_state::ClientState as TmClientState; -use crate::core::ics02_client::client_state::ClientStateCommon; -use crate::core::ics02_client::error::ClientError; -use crate::core::ics03_connection::error::ConnectionError; -use crate::core::ics23_commitment::specs::ProofSpecs; -use crate::core::ics24_host::identifier::ChainId; -use crate::core::ContextError; -use crate::Height; - /// Provides an implementation of `ValidationContext::validate_self_client` for /// Tendermint-based hosts. pub trait ValidateSelfClientContext { @@ -21,15 +19,19 @@ pub trait ValidateSelfClientContext { &self, client_state_of_host_on_counterparty: Any, ) -> Result<(), ContextError> { - let tm_client_state = TmClientState::try_from(client_state_of_host_on_counterparty) + let tm_client_state = ClientStateWrapper::try_from(client_state_of_host_on_counterparty) .map_err(|_| ConnectionError::InvalidClientState { reason: "client must be a tendermint client".to_string(), }) .map_err(ContextError::ConnectionError)?; - tm_client_state.validate().map_err(ClientError::from)?; + let tm_client_state_inner = tm_client_state.inner(); + + tm_client_state_inner + .validate() + .map_err(ClientError::from)?; - if tm_client_state.is_frozen() { + if tm_client_state_inner.is_frozen() { return Err(ClientError::ClientFrozen { description: String::new(), } @@ -37,12 +39,12 @@ pub trait ValidateSelfClientContext { } let self_chain_id = self.chain_id(); - if self_chain_id != &tm_client_state.chain_id { + if self_chain_id != &tm_client_state_inner.chain_id { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { reason: format!( "invalid chain-id. expected: {}, got: {}", - self_chain_id, tm_client_state.chain_id + self_chain_id, tm_client_state_inner.chain_id ), }, )); @@ -73,20 +75,20 @@ pub trait ValidateSelfClientContext { )); } - if self.proof_specs() != &tm_client_state.proof_specs { + if self.proof_specs() != &tm_client_state_inner.proof_specs { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { reason: format!( "client has invalid proof specs. expected: {:?}, got: {:?}", self.proof_specs(), - tm_client_state.proof_specs + tm_client_state_inner.proof_specs ), }, )); } let _ = { - let trust_level = tm_client_state.trust_level; + let trust_level = tm_client_state_inner.trust_level; TendermintTrustThresholdFraction::new( trust_level.numerator(), @@ -97,35 +99,35 @@ pub trait ValidateSelfClientContext { })? }; - if self.unbonding_period() != tm_client_state.unbonding_period { + if self.unbonding_period() != tm_client_state_inner.unbonding_period { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { reason: format!( "invalid unbonding period. expected: {:?}, got: {:?}", self.unbonding_period(), - tm_client_state.unbonding_period, + tm_client_state_inner.unbonding_period, ), }, )); } - if tm_client_state.unbonding_period < tm_client_state.trusting_period { + if tm_client_state_inner.unbonding_period < tm_client_state_inner.trusting_period { return Err(ContextError::ConnectionError(ConnectionError::InvalidClientState{ reason: format!( "unbonding period must be greater than trusting period. unbonding period ({:?}) < trusting period ({:?})", - tm_client_state.unbonding_period, - tm_client_state.trusting_period + tm_client_state_inner.unbonding_period, + tm_client_state_inner.trusting_period )})); } - if !tm_client_state.upgrade_path.is_empty() - && self.upgrade_path() != tm_client_state.upgrade_path + if !tm_client_state_inner.upgrade_path.is_empty() + && self.upgrade_path() != tm_client_state_inner.upgrade_path { return Err(ContextError::ConnectionError( ConnectionError::InvalidClientState { reason: format!( "invalid upgrade path. expected: {:?}, got: {:?}", self.upgrade_path(), - tm_client_state.upgrade_path + tm_client_state_inner.upgrade_path ), }, )); diff --git a/crates/ibc-core/ics24-host/types/Cargo.toml b/crates/ibc-core/ics24-host/types/Cargo.toml new file mode 100644 index 000000000..f47a7e0c1 --- /dev/null +++ b/crates/ibc-core/ics24-host/types/Cargo.toml @@ -0,0 +1,62 @@ +[package] +name = "ibc-core-host-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "host", "types"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, encapsulates essential ICS-24 Host Requirements data structures and domain types, + as specified in the Inter-Blockchain Communication (IBC) protocol. Designed for universal applicability + to facilitate development and integration across diverse IBC-enabled projects. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } +schemars = { workspace = true, optional = true } +serde = { workspace = true, optional = true } + +# ibc dependencies +ibc-primitives = { workspace = true } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[dev-dependencies] +rstest = { workspace = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "ibc-primitives/std", +] +serde = [ + "dep:serde", + "ibc-primitives/serde", +] +schema = [ + "dep:schemars", + "ibc-primitives/schema", + "serde", + "std" +] +borsh = [ + "dep:borsh", + "ibc-primitives/borsh", +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-primitives/parity-scale-codec", +] diff --git a/crates/ibc-core/ics24-host/types/src/error.rs b/crates/ibc-core/ics24-host/types/src/error.rs new file mode 100644 index 000000000..980a3a1c4 --- /dev/null +++ b/crates/ibc-core/ics24-host/types/src/error.rs @@ -0,0 +1,31 @@ +use displaydoc::Display; +use ibc_primitives::prelude::*; + +#[cfg_attr(feature = "serde", derive(serde::Serialize))] +#[derive(Debug, Display)] +pub enum IdentifierError { + /// identifier `{id}` cannot contain separator '/' + ContainSeparator { id: String }, + /// identifier `{id}` has invalid length `{length}` must be between `{min}`-`{max}` characters + InvalidLength { + id: String, + length: u64, + min: u64, + max: u64, + }, + /// identifier `{id}` must only contain alphanumeric characters or `.`, `_`, `+`, `-`, `#`, - `[`, `]`, `<`, `>` + InvalidCharacter { id: String }, + /// identifier prefix `{prefix}` is invalid + InvalidPrefix { prefix: String }, + /// chain identifier is not formatted with revision number + UnformattedRevisionNumber { chain_id: String }, + /// revision number overflowed + RevisionNumberOverflow, + /// String `{value}` cannot be converted to packet sequence, error: `{reason}` + InvalidStringAsSequence { value: String, reason: String }, + /// identifier cannot be empty + Empty, +} + +#[cfg(feature = "std")] +impl std::error::Error for IdentifierError {} diff --git a/crates/ibc-core/ics24-host/types/src/identifiers/chain_id.rs b/crates/ibc-core/ics24-host/types/src/identifiers/chain_id.rs new file mode 100644 index 000000000..5b532aeef --- /dev/null +++ b/crates/ibc-core/ics24-host/types/src/identifiers/chain_id.rs @@ -0,0 +1,272 @@ +use core::fmt::{Debug, Display, Error as FmtError, Formatter}; +use core::str::FromStr; + +use ibc_primitives::prelude::*; + +use crate::error::IdentifierError; +use crate::validate::{ + validate_identifier_chars, validate_identifier_length, validate_prefix_length, +}; + +/// Defines the domain type for chain identifiers. +/// +/// A valid `ChainId` follows the format {chain name}-{revision number} where +/// the revision number indicates how many times the chain has been upgraded. +/// Creating `ChainId`s not in this format will result in an error. +/// +/// It should be noted this format is not standardized yet, though it is widely +/// accepted and compatible with Cosmos SDK driven chains. +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ChainId { + id: String, + revision_number: u64, +} + +impl ChainId { + /// Creates a new `ChainId` with the given chain identifier. + /// + /// It checks the identifier for valid characters according to `ICS-24` + /// specification and returns a `ChainId` successfully. + /// Stricter checks beyond `ICS-24` rests with the users, + /// based on their requirements. + /// + /// If the chain identifier is in the {chain name}-{revision number} format, + /// the revision number is parsed. Otherwise, revision number is set to 0. + /// + /// ``` + /// use ibc_core_host_types::identifiers::ChainId; + /// + /// let chain_id = "chainA"; + /// let id = ChainId::new(chain_id).unwrap(); + /// assert_eq!(id.revision_number(), 0); + /// assert_eq!(id.as_str(), chain_id); + /// + /// let chain_id = "chainA-12"; + /// let id = ChainId::new(chain_id).unwrap(); + /// assert_eq!(id.revision_number(), 12); + /// assert_eq!(id.as_str(), chain_id); + /// ``` + pub fn new(chain_id: &str) -> Result { + Self::from_str(chain_id) + } + + /// Get a reference to the underlying string. + pub fn as_str(&self) -> &str { + &self.id + } + + pub fn split_chain_id(&self) -> Result<(&str, u64), IdentifierError> { + parse_chain_id_string(self.as_str()) + } + + /// Extract the revision number from the chain identifier + pub fn revision_number(&self) -> u64 { + self.revision_number + } + + /// Increases `ChainId`s revision number by one. + /// Fails if the chain identifier is not in + /// `{chain_name}-{revision_number}` format or + /// the revision number overflows. + /// + /// ``` + /// use ibc_core_host_types::identifiers::ChainId; + /// + /// let mut chain_id = ChainId::new("chainA-1").unwrap(); + /// assert!(chain_id.increment_revision_number().is_ok()); + /// assert_eq!(chain_id.revision_number(), 2); + /// + /// let mut chain_id = ChainId::new(&format!("chainA-{}", u64::MAX)).unwrap(); + /// assert!(chain_id.increment_revision_number().is_err()); + /// assert_eq!(chain_id.revision_number(), u64::MAX); + /// ``` + pub fn increment_revision_number(&mut self) -> Result<(), IdentifierError> { + let (chain_name, _) = self.split_chain_id()?; + let inc_revision_number = self + .revision_number + .checked_add(1) + .ok_or(IdentifierError::RevisionNumberOverflow)?; + self.id = format!("{}-{}", chain_name, inc_revision_number); + self.revision_number = inc_revision_number; + Ok(()) + } + + /// A convenient method to check if the `ChainId` forms a valid identifier + /// with the desired min/max length. However, ICS-24 does not specify a + /// certain min or max lengths for chain identifiers. + pub fn validate_length(&self, min_length: u64, max_length: u64) -> Result<(), IdentifierError> { + match self.split_chain_id() { + Ok((chain_name, _)) => validate_prefix_length(chain_name, min_length, max_length), + _ => validate_identifier_length(&self.id, min_length, max_length), + } + } +} + +/// Construct a `ChainId` from a string literal only if it forms a valid +/// identifier. +impl FromStr for ChainId { + type Err = IdentifierError; + + fn from_str(id: &str) -> Result { + // Identifier string must have a maximum length of 64 characters. + + // Validates the chain name for allowed characters according to ICS-24. + validate_identifier_chars(id)?; + match parse_chain_id_string(id) { + Ok((chain_name, revision_number)) => { + // Validate if the chain name with revision number has a valid length. + validate_prefix_length(chain_name, 1, 64)?; + Ok(Self { + id: id.into(), + revision_number, + }) + } + + _ => { + // Validate if the identifier has a valid length. + validate_identifier_length(id, 1, 64)?; + Ok(Self { + id: id.into(), + revision_number: 0, + }) + } + } + } +} + +impl Display for ChainId { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!(f, "{}", self.id) + } +} + +/// Parses a string intended to represent a `ChainId` and, if successful, +/// returns a tuple containing the chain name and revision number. +fn parse_chain_id_string(chain_id_str: &str) -> Result<(&str, u64), IdentifierError> { + chain_id_str + .rsplit_once('-') + .filter(|(_, rev_number_str)| { + // Validates the revision number not to start with leading zeros, like "01". + // Zero is the only allowed revision number with leading zero. + rev_number_str.as_bytes().first() != Some(&b'0') || rev_number_str.len() == 1 + }) + .and_then(|(chain_name, rev_number_str)| { + // Parses the revision number string into a `u64` and checks its validity. + rev_number_str + .parse() + .ok() + .map(|revision_number| (chain_name, revision_number)) + }) + .ok_or(IdentifierError::UnformattedRevisionNumber { + chain_id: chain_id_str.to_string(), + }) +} + +#[cfg(test)] +mod tests { + use rstest::rstest; + + use super::*; + + #[rstest] + #[case("chainA-0", "chainA", 0)] + #[case("chainA-1", "chainA", 1)] + #[case("chainA--1", "chainA-", 1)] + #[case("chainA-1-2", "chainA-1", 2)] + #[case("111-2", "111", 2)] + #[case("----1", "---", 1)] + #[case("._+-1", "._+", 1)] + #[case(&("A".repeat(43) + "-3"), &("A".repeat(43)), 3)] + fn test_valid_chain_id_with_rev( + #[case] raw_chain_id: &str, + #[case] chain_name: &str, + #[case] revision_number: u64, + ) { + let chain_id = ChainId::new(raw_chain_id).unwrap(); + assert!(chain_id.validate_length(1, 64).is_ok()); + assert_eq!( + chain_id, + ChainId { + id: format!("{chain_name}-{revision_number}"), + revision_number + } + ); + } + + #[rstest] + #[case("chainA")] + #[case("chainA.2")] + #[case("123")] + #[case("._+")] + #[case("chainA-")] + #[case("chainA-a")] + #[case("chainA-01")] + #[case("chainA-1-")] + #[case(&"A".repeat(64))] + #[case::special_case("chainA-0")] + fn test_valid_chain_id_without_rev(#[case] chain_name: &str) { + let chain_id = ChainId::new(chain_name).unwrap(); + assert!(chain_id.validate_length(1, 64).is_ok()); + assert_eq!( + chain_id, + ChainId { + id: chain_name.into(), + revision_number: 0 + } + ); + } + + #[rstest] + #[case(&"A".repeat(65))] + #[case(&("A".repeat(44) + "-123"))] + #[case("-1")] + #[case(" ----1")] + #[case(" ")] + #[case(" chainA")] + #[case("chain A")] + #[case(" chainA.2")] + #[case(" chainA.2-1")] + #[case(" 1")] + #[case(" -")] + #[case(" -1")] + #[case("/chainA-1")] + fn test_invalid_chain_id(#[case] chain_id_str: &str) { + assert!(ChainId::new(chain_id_str).is_err()); + } + + #[test] + fn test_inc_revision_number() { + let mut chain_id = ChainId::new("chainA-1").unwrap(); + + assert!(chain_id.increment_revision_number().is_ok()); + assert_eq!(chain_id.revision_number(), 2); + assert_eq!(chain_id.as_str(), "chainA-2"); + + assert!(chain_id.increment_revision_number().is_ok()); + assert_eq!(chain_id.revision_number(), 3); + assert_eq!(chain_id.as_str(), "chainA-3"); + } + + #[test] + fn test_failed_inc_revision_number() { + let mut chain_id = ChainId::new("chainA").unwrap(); + + assert!(chain_id.increment_revision_number().is_err()); + assert_eq!(chain_id.revision_number(), 0); + assert_eq!(chain_id.as_str(), "chainA"); + } +} diff --git a/crates/ibc-core/ics24-host/types/src/identifiers/channel_id.rs b/crates/ibc-core/ics24-host/types/src/identifiers/channel_id.rs new file mode 100644 index 000000000..f4dc7e2fa --- /dev/null +++ b/crates/ibc-core/ics24-host/types/src/identifiers/channel_id.rs @@ -0,0 +1,100 @@ +use core::fmt::{Debug, Display, Error as FmtError, Formatter}; +use core::str::FromStr; + +use ibc_primitives::prelude::*; + +use crate::error::IdentifierError; +use crate::validate::validate_channel_identifier; + +const CHANNEL_ID_PREFIX: &str = "channel"; + +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ChannelId(String); + +impl ChannelId { + /// Builds a new channel identifier. Like client and connection identifiers, channel ids are + /// deterministically formed from two elements: a prefix `prefix`, and a monotonically + /// increasing `counter`, separated by a dash "-". + /// The prefix is currently determined statically (see `ChannelId::prefix()`) so this method + /// accepts a single argument, the `counter`. + /// + /// ``` + /// # use ibc_core_host_types::identifiers::ChannelId; + /// let chan_id = ChannelId::new(27); + /// assert_eq!(chan_id.to_string(), "channel-27"); + /// ``` + pub fn new(identifier: u64) -> Self { + let id = format!("{}-{}", Self::prefix(), identifier); + Self(id) + } + + /// Returns the static prefix to be used across all channel identifiers. + pub fn prefix() -> &'static str { + CHANNEL_ID_PREFIX + } + + /// Get this identifier as a borrowed `&str` + pub fn as_str(&self) -> &str { + &self.0 + } + + /// Get this identifier as a borrowed byte slice + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } +} + +/// This implementation provides a `to_string` method. +impl Display for ChannelId { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!(f, "{}", self.0) + } +} + +impl FromStr for ChannelId { + type Err = IdentifierError; + + fn from_str(s: &str) -> Result { + validate_channel_identifier(s).map(|_| Self(s.to_string())) + } +} + +impl AsRef for ChannelId { + fn as_ref(&self) -> &str { + &self.0 + } +} + +impl Default for ChannelId { + fn default() -> Self { + Self::new(0) + } +} + +/// Equality check against string literal (satisfies &ChannelId == &str). +/// ``` +/// use core::str::FromStr; +/// use ibc_core_host_types::identifiers::ChannelId; +/// let channel_id = ChannelId::from_str("channelId-0"); +/// assert!(channel_id.is_ok()); +/// channel_id.map(|id| {assert_eq!(&id, "channelId-0")}); +/// ``` +impl PartialEq for ChannelId { + fn eq(&self, other: &str) -> bool { + self.as_str().eq(other) + } +} diff --git a/crates/ibc-core/ics24-host/types/src/identifiers/client_id.rs b/crates/ibc-core/ics24-host/types/src/identifiers/client_id.rs new file mode 100644 index 000000000..2adc04d9d --- /dev/null +++ b/crates/ibc-core/ics24-host/types/src/identifiers/client_id.rs @@ -0,0 +1,94 @@ +use core::fmt::{Debug, Display, Error as FmtError, Formatter}; +use core::str::FromStr; + +use derive_more::Into; +use ibc_primitives::prelude::*; + +use super::ClientType; +use crate::error::IdentifierError; +use crate::validate::{validate_client_identifier, validate_client_type}; + +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Into)] +pub struct ClientId(String); + +impl ClientId { + /// Builds a new client identifier. Client identifiers are deterministically formed from two + /// elements: a prefix derived from the client type `ctype`, and a monotonically increasing + /// `counter`; these are separated by a dash "-". + /// + /// ``` + /// # use ibc_core_host_types::identifiers::ClientId; + /// # use ibc_core_host_types::identifiers::ClientType; + /// # use std::str::FromStr; + /// let tm_client_id = ClientId::new(ClientType::from_str("07-tendermint").unwrap(), 0); + /// assert!(tm_client_id.is_ok()); + /// tm_client_id.map(|id| { assert_eq!(&id, "07-tendermint-0") }); + /// ``` + pub fn new(client_type: ClientType, counter: u64) -> Result { + let prefix = client_type.as_str().trim(); + validate_client_type(prefix)?; + let id = format!("{prefix}-{counter}"); + Self::from_str(id.as_str()) + } + + /// Get this identifier as a borrowed `&str` + pub fn as_str(&self) -> &str { + &self.0 + } + + /// Get this identifier as a borrowed byte slice + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } +} + +/// This implementation provides a `to_string` method. +impl Display for ClientId { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!(f, "{}", self.0) + } +} + +impl FromStr for ClientId { + type Err = IdentifierError; + + fn from_str(s: &str) -> Result { + validate_client_identifier(s).map(|_| Self(s.to_string())) + } +} + +impl Default for ClientId { + fn default() -> Self { + let client_type = + ClientType::from_str("07-tendermint").expect("Never fails because it's valid"); + Self::new(client_type, 0).expect("Never fails because we use a valid client type") + } +} + +/// Equality check against string literal (satisfies &ClientId == &str). +/// ``` +/// use core::str::FromStr; +/// use ibc_core_host_types::identifiers::ClientId; +/// let client_id = ClientId::from_str("clientidtwo"); +/// assert!(client_id.is_ok()); +/// client_id.map(|id| {assert_eq!(&id, "clientidtwo")}); +/// ``` +impl PartialEq for ClientId { + fn eq(&self, other: &str) -> bool { + self.as_str().eq(other) + } +} diff --git a/crates/ibc/src/core/ics02_client/client_type.rs b/crates/ibc-core/ics24-host/types/src/identifiers/client_type.rs similarity index 89% rename from crates/ibc/src/core/ics02_client/client_type.rs rename to crates/ibc-core/ics24-host/types/src/identifiers/client_type.rs index b223fbdae..ff1968ebb 100644 --- a/crates/ibc/src/core/ics02_client/client_type.rs +++ b/crates/ibc-core/ics24-host/types/src/identifiers/client_type.rs @@ -3,9 +3,10 @@ use core::fmt::{Display, Error as FmtError, Formatter}; use core::str::FromStr; -use crate::core::ics24_host::identifier::validate::validate_client_type; -use crate::core::ics24_host::identifier::IdentifierError; -use crate::prelude::*; +use ibc_primitives::prelude::*; + +use crate::error::IdentifierError; +use crate::validate::validate_client_type; #[cfg_attr( feature = "parity-scale-codec", diff --git a/crates/ibc-core/ics24-host/types/src/identifiers/connection_id.rs b/crates/ibc-core/ics24-host/types/src/identifiers/connection_id.rs new file mode 100644 index 000000000..10a2c8857 --- /dev/null +++ b/crates/ibc-core/ics24-host/types/src/identifiers/connection_id.rs @@ -0,0 +1,93 @@ +use core::fmt::{Display, Error as FmtError, Formatter}; +use core::str::FromStr; + +use ibc_primitives::prelude::*; + +use crate::error::IdentifierError; +use crate::validate::validate_connection_identifier; + +const CONNECTION_ID_PREFIX: &str = "connection"; + +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ConnectionId(String); + +impl ConnectionId { + /// Builds a new connection identifier. Connection identifiers are deterministically formed from + /// two elements: a prefix `prefix`, and a monotonically increasing `counter`; these are + /// separated by a dash "-". The prefix is currently determined statically (see + /// `ConnectionId::prefix()`) so this method accepts a single argument, the `counter`. + /// + /// ``` + /// # use ibc_core_host_types::identifiers::ConnectionId; + /// let conn_id = ConnectionId::new(11); + /// assert_eq!(&conn_id, "connection-11"); + /// ``` + pub fn new(identifier: u64) -> Self { + let id = format!("{}-{}", Self::prefix(), identifier); + Self(id) + } + + /// Returns the static prefix to be used across all connection identifiers. + pub fn prefix() -> &'static str { + CONNECTION_ID_PREFIX + } + + /// Get this identifier as a borrowed `&str` + pub fn as_str(&self) -> &str { + &self.0 + } + + /// Get this identifier as a borrowed byte slice + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } +} + +/// This implementation provides a `to_string` method. +impl Display for ConnectionId { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!(f, "{}", self.0) + } +} + +impl FromStr for ConnectionId { + type Err = IdentifierError; + + fn from_str(s: &str) -> Result { + validate_connection_identifier(s).map(|_| Self(s.to_string())) + } +} + +impl Default for ConnectionId { + fn default() -> Self { + Self::new(0) + } +} + +/// Equality check against string literal (satisfies &ConnectionId == &str). +/// ``` +/// use core::str::FromStr; +/// use ibc_core_host_types::identifiers::ConnectionId; +/// let conn_id = ConnectionId::from_str("connectionId-0"); +/// assert!(conn_id.is_ok()); +/// conn_id.map(|id| {assert_eq!(&id, "connectionId-0")}); +/// ``` +impl PartialEq for ConnectionId { + fn eq(&self, other: &str) -> bool { + self.as_str().eq(other) + } +} diff --git a/crates/ibc-core/ics24-host/types/src/identifiers/mod.rs b/crates/ibc-core/ics24-host/types/src/identifiers/mod.rs new file mode 100644 index 000000000..9ae79f673 --- /dev/null +++ b/crates/ibc-core/ics24-host/types/src/identifiers/mod.rs @@ -0,0 +1,17 @@ +//! Defines identifier types + +mod chain_id; +mod channel_id; +mod client_id; +mod client_type; +mod connection_id; +mod port_id; +mod sequence; + +pub use chain_id::ChainId; +pub use channel_id::ChannelId; +pub use client_id::ClientId; +pub use client_type::ClientType; +pub use connection_id::ConnectionId; +pub use port_id::PortId; +pub use sequence::Sequence; diff --git a/crates/ibc-core/ics24-host/types/src/identifiers/port_id.rs b/crates/ibc-core/ics24-host/types/src/identifiers/port_id.rs new file mode 100644 index 000000000..d1b640757 --- /dev/null +++ b/crates/ibc-core/ics24-host/types/src/identifiers/port_id.rs @@ -0,0 +1,72 @@ +use core::fmt::{Display, Error as FmtError, Formatter}; +use core::str::FromStr; + +use ibc_primitives::prelude::*; + +use crate::error::IdentifierError; +use crate::validate::validate_port_identifier; + +const TRANSFER_PORT_ID: &str = "transfer"; + +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct PortId(String); + +impl PortId { + pub fn new(id: String) -> Result { + Self::from_str(&id) + } + + /// Infallible creation of the well-known transfer port + pub fn transfer() -> Self { + Self(TRANSFER_PORT_ID.to_string()) + } + + /// Get this identifier as a borrowed `&str` + pub fn as_str(&self) -> &str { + &self.0 + } + + /// Get this identifier as a borrowed byte slice + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } + + pub fn validate(&self) -> Result<(), IdentifierError> { + validate_port_identifier(self.as_str()) + } +} + +/// This implementation provides a `to_string` method. +impl Display for PortId { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!(f, "{}", self.0) + } +} + +impl FromStr for PortId { + type Err = IdentifierError; + + fn from_str(s: &str) -> Result { + validate_port_identifier(s).map(|_| Self(s.to_string())) + } +} + +impl AsRef for PortId { + fn as_ref(&self) -> &str { + self.0.as_str() + } +} diff --git a/crates/ibc-core/ics24-host/types/src/identifiers/sequence.rs b/crates/ibc-core/ics24-host/types/src/identifiers/sequence.rs new file mode 100644 index 000000000..db6d9c560 --- /dev/null +++ b/crates/ibc-core/ics24-host/types/src/identifiers/sequence.rs @@ -0,0 +1,65 @@ +use ibc_primitives::prelude::*; + +use crate::error::IdentifierError; + +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +/// The sequence number of a packet enforces ordering among packets from the same source. +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Sequence(u64); + +impl core::str::FromStr for Sequence { + type Err = IdentifierError; + + fn from_str(s: &str) -> Result { + Ok(Self::from(s.parse::().map_err(|e| { + IdentifierError::InvalidStringAsSequence { + value: s.to_string(), + reason: e.to_string(), + } + })?)) + } +} + +impl Sequence { + pub fn value(&self) -> u64 { + self.0 + } + pub fn is_zero(&self) -> bool { + self.0 == 0 + } + + pub fn increment(&self) -> Sequence { + Sequence(self.0 + 1) + } +} + +impl From for Sequence { + fn from(seq: u64) -> Self { + Sequence(seq) + } +} + +impl From for u64 { + fn from(s: Sequence) -> u64 { + s.0 + } +} + +impl core::fmt::Display for Sequence { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!(f, "{}", self.0) + } +} diff --git a/crates/ibc-core/ics24-host/types/src/lib.rs b/crates/ibc-core/ics24-host/types/src/lib.rs new file mode 100644 index 000000000..f466de4c2 --- /dev/null +++ b/crates/ibc-core/ics24-host/types/src/lib.rs @@ -0,0 +1,21 @@ +//! ICS-24: Host defines the minimal set of interfaces that a state machine +//! hosting an IBC-enabled chain must implement. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +pub mod error; +pub mod identifiers; +pub mod path; +pub(crate) mod validate; diff --git a/crates/ibc/src/core/ics24_host/path.rs b/crates/ibc-core/ics24-host/types/src/path.rs similarity index 97% rename from crates/ibc/src/core/ics24_host/path.rs rename to crates/ibc-core/ics24-host/types/src/path.rs index 6630abbf0..ede974372 100644 --- a/crates/ibc/src/core/ics24_host/path.rs +++ b/crates/ibc-core/ics24-host/types/src/path.rs @@ -7,11 +7,9 @@ use core::str::FromStr; use derive_more::{Display, From}; +use ibc_primitives::prelude::*; -use crate::core::ics04_channel::packet::Sequence; -use crate::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; -use crate::prelude::*; -use crate::Height; +use crate::identifiers::{ChannelId, ClientId, ConnectionId, PortId, Sequence}; /// ABCI client upgrade keys /// - The key identifying the upgraded IBC state within the upgrade sub-store @@ -76,19 +74,23 @@ impl ClientStatePath { )] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)] -#[display(fmt = "clients/{client_id}/consensusStates/{epoch}-{height}")] +#[display(fmt = "clients/{client_id}/consensusStates/{revision_number}-{revision_height}")] pub struct ClientConsensusStatePath { pub client_id: ClientId, - pub epoch: u64, - pub height: u64, + pub revision_number: u64, + pub revision_height: u64, } impl ClientConsensusStatePath { - pub fn new(client_id: &ClientId, height: &Height) -> ClientConsensusStatePath { + pub fn new( + client_id: ClientId, + revision_number: u64, + revision_height: u64, + ) -> ClientConsensusStatePath { ClientConsensusStatePath { - client_id: client_id.clone(), - epoch: height.revision_number(), - height: height.revision_height(), + client_id, + revision_number, + revision_height, } } } @@ -464,15 +466,15 @@ fn parse_client_paths(components: &[&str]) -> Option { return None; } - let epoch = epoch_height[0]; - let height = epoch_height[1]; + let revision_number = epoch_height[0]; + let revision_height = epoch_height[1]; - let epoch = match epoch.parse::() { + let revision_number = match revision_number.parse::() { Ok(ep) => ep, Err(_) => return None, }; - let height = match height.parse::() { + let revision_height = match revision_height.parse::() { Ok(h) => h, Err(_) => return None, }; @@ -480,8 +482,8 @@ fn parse_client_paths(components: &[&str]) -> Option { Some( ClientConsensusStatePath { client_id, - epoch, - height, + revision_number, + revision_height, } .into(), ) @@ -862,8 +864,8 @@ mod tests { parse_client_paths(&components), Some(Path::ClientConsensusState(ClientConsensusStatePath { client_id: ClientId::default(), - epoch: 15, - height: 31, + revision_number: 15, + revision_height: 31, })) ); } @@ -890,8 +892,8 @@ mod tests { path.unwrap(), Path::ClientConsensusState(ClientConsensusStatePath { client_id: ClientId::default(), - epoch: 15, - height: 31, + revision_number: 15, + revision_height: 31, }) ); } diff --git a/crates/ibc/src/core/ics24_host/identifier/validate.rs b/crates/ibc-core/ics24-host/types/src/validate.rs similarity index 98% rename from crates/ibc/src/core/ics24_host/identifier/validate.rs rename to crates/ibc-core/ics24-host/types/src/validate.rs index c16fcdf12..5fb164020 100644 --- a/crates/ibc/src/core/ics24_host/identifier/validate.rs +++ b/crates/ibc-core/ics24-host/types/src/validate.rs @@ -1,5 +1,6 @@ -use super::IdentifierError as Error; -use crate::prelude::*; +use ibc_primitives::prelude::*; + +use crate::error::IdentifierError as Error; /// Path separator (ie. forward slash '/') const PATH_SEPARATOR: char = '/'; @@ -113,7 +114,6 @@ pub fn validate_channel_identifier(id: &str) -> Result<(), Error> { #[cfg(test)] mod tests { use rstest::rstest; - use test_log::test; use super::*; @@ -241,7 +241,6 @@ mod tests { #[case::u64_min_max_boundary("a", 3, 22, true)] #[case("chainA", 1, 32, true)] #[case("chainA", 1, 64, true)] - #[test_log::test] fn test_prefix_length_validation( #[case] prefix: &str, #[case] min: u64, diff --git a/crates/ibc-core/ics25-handler/Cargo.toml b/crates/ibc-core/ics25-handler/Cargo.toml new file mode 100644 index 000000000..ec7e9614f --- /dev/null +++ b/crates/ibc-core/ics25-handler/Cargo.toml @@ -0,0 +1,76 @@ +[package] +name = "ibc-core-handler" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "handler"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, exposes IBC handler entry points for an integrated IBC core modules. + These entry points are responsible for processing incoming IBC messages, performing validation, + and execution logic by invoking the appropriate module handler. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +ibc-core-client = { workspace = true } +ibc-core-connection = { workspace = true } +ibc-core-channel = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-router = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-core-host = { workspace = true } +ibc-primitives = { workspace = true } + +[features] +default = ["std"] +std = [ + "ibc-core-client/std", + "ibc-core-connection/std", + "ibc-core-channel/std", + "ibc-core-commitment-types/std", + "ibc-core-host/std", + "ibc-core-router/std", + "ibc-core-handler-types/std", +] +serde = [ + "ibc-core-client/serde", + "ibc-core-connection/serde", + "ibc-core-channel/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host/serde", + "ibc-core-router/serde", + "ibc-core-handler-types/serde", +] +borsh = [ + "ibc-core-client/borsh", + "ibc-core-connection/borsh", + "ibc-core-channel/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host/borsh", + "ibc-core-router/borsh", + "ibc-core-handler-types/borsh", +] +schema = [ + "ibc-core-client/schema", + "ibc-core-connection/schema", + "ibc-core-channel/schema", + "ibc-core-commitment-types/schema", + "ibc-core-host/schema", + "ibc-core-router/schema", + "ibc-core-handler-types/schema", +] +parity-scale-codec = [ + "ibc-core-client/parity-scale-codec", + "ibc-core-connection/parity-scale-codec", + "ibc-core-channel/parity-scale-codec", + "ibc-core-host/parity-scale-codec", + "ibc-core-router/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] diff --git a/crates/ibc/src/core/handler.rs b/crates/ibc-core/ics25-handler/src/entrypoint.rs similarity index 79% rename from crates/ibc/src/core/handler.rs rename to crates/ibc-core/ics25-handler/src/entrypoint.rs index 7c766a0dd..957e147c0 100644 --- a/crates/ibc/src/core/handler.rs +++ b/crates/ibc-core/ics25-handler/src/entrypoint.rs @@ -1,44 +1,32 @@ -use super::context::RouterError; -use super::ics02_client::handler::{create_client, update_client, upgrade_client}; -use super::ics02_client::msgs::{ClientMsg, MsgUpdateOrMisbehaviour}; -use super::ics03_connection::handler::{ - conn_open_ack, conn_open_confirm, conn_open_init, conn_open_try, -}; -use super::ics03_connection::msgs::ConnectionMsg; -use super::ics04_channel::handler::acknowledgement::{ - acknowledgement_packet_execute, acknowledgement_packet_validate, -}; -use super::ics04_channel::handler::chan_close_confirm::{ - chan_close_confirm_execute, chan_close_confirm_validate, -}; -use super::ics04_channel::handler::chan_close_init::{ - chan_close_init_execute, chan_close_init_validate, -}; -use super::ics04_channel::handler::chan_open_ack::{chan_open_ack_execute, chan_open_ack_validate}; -use super::ics04_channel::handler::chan_open_confirm::{ - chan_open_confirm_execute, chan_open_confirm_validate, -}; -use super::ics04_channel::handler::chan_open_init::{ - chan_open_init_execute, chan_open_init_validate, -}; -use super::ics04_channel::handler::chan_open_try::{chan_open_try_execute, chan_open_try_validate}; -use super::ics04_channel::handler::recv_packet::{recv_packet_execute, recv_packet_validate}; -use super::ics04_channel::handler::timeout::{ +use ibc_core_channel::handler::{ + acknowledgement_packet_execute, acknowledgement_packet_validate, chan_close_confirm_execute, + chan_close_confirm_validate, chan_close_init_execute, chan_close_init_validate, + chan_open_ack_execute, chan_open_ack_validate, chan_open_confirm_execute, + chan_open_confirm_validate, chan_open_init_execute, chan_open_init_validate, + chan_open_try_execute, chan_open_try_validate, recv_packet_execute, recv_packet_validate, timeout_packet_execute, timeout_packet_validate, TimeoutMsgType, }; -use super::ics04_channel::msgs::{ +use ibc_core_channel::types::msgs::{ channel_msg_to_port_id, packet_msg_to_port_id, ChannelMsg, PacketMsg, }; -use super::msgs::MsgEnvelope; -use super::router::Router; -use super::{ExecutionContext, ValidationContext}; +use ibc_core_client::handler::{create_client, update_client, upgrade_client}; +use ibc_core_client::types::msgs::{ClientMsg, MsgUpdateOrMisbehaviour}; +use ibc_core_connection::handler::{ + conn_open_ack, conn_open_confirm, conn_open_init, conn_open_try, +}; +use ibc_core_connection::types::msgs::ConnectionMsg; +use ibc_core_handler_types::error::ContextError; +use ibc_core_handler_types::msgs::MsgEnvelope; +use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::router::Router; +use ibc_core_router::types::error::RouterError; /// Entrypoint which performs both validation and message execution pub fn dispatch( ctx: &mut impl ExecutionContext, router: &mut impl Router, msg: MsgEnvelope, -) -> Result<(), RouterError> { +) -> Result<(), ContextError> { validate(ctx, router, msg.clone())?; execute(ctx, router, msg) } @@ -51,7 +39,7 @@ pub fn dispatch( /// That is, the state transition of message `i` must be applied before /// message `i+1` is validated. This is equivalent to calling /// `dispatch()` on each successively. -pub fn validate(ctx: &Ctx, router: &impl Router, msg: MsgEnvelope) -> Result<(), RouterError> +pub fn validate(ctx: &Ctx, router: &impl Router, msg: MsgEnvelope) -> Result<(), ContextError> where Ctx: ValidationContext, { @@ -65,15 +53,13 @@ where update_client::validate(ctx, MsgUpdateOrMisbehaviour::Misbehaviour(msg)) } ClientMsg::UpgradeClient(msg) => upgrade_client::validate(ctx, msg), - } - .map_err(RouterError::ContextError), + }, MsgEnvelope::Connection(msg) => match msg { ConnectionMsg::OpenInit(msg) => conn_open_init::validate(ctx, msg), ConnectionMsg::OpenTry(msg) => conn_open_try::validate(ctx, msg), ConnectionMsg::OpenAck(msg) => conn_open_ack::validate(ctx, msg), ConnectionMsg::OpenConfirm(ref msg) => conn_open_confirm::validate(ctx, msg), - } - .map_err(RouterError::ContextError), + }, MsgEnvelope::Channel(msg) => { let port_id = channel_msg_to_port_id(&msg); let module_id = router @@ -93,7 +79,6 @@ where ChannelMsg::CloseInit(msg) => chan_close_init_validate(ctx, module, msg), ChannelMsg::CloseConfirm(msg) => chan_close_confirm_validate(ctx, module, msg), } - .map_err(RouterError::ContextError) } MsgEnvelope::Packet(msg) => { let port_id = packet_msg_to_port_id(&msg); @@ -116,7 +101,6 @@ where timeout_packet_validate(ctx, module, TimeoutMsgType::TimeoutOnClose(msg)) } } - .map_err(RouterError::ContextError) } } } @@ -126,7 +110,7 @@ pub fn execute( ctx: &mut Ctx, router: &mut impl Router, msg: MsgEnvelope, -) -> Result<(), RouterError> +) -> Result<(), ContextError> where Ctx: ExecutionContext, { @@ -140,15 +124,13 @@ where update_client::execute(ctx, MsgUpdateOrMisbehaviour::Misbehaviour(msg)) } ClientMsg::UpgradeClient(msg) => upgrade_client::execute(ctx, msg), - } - .map_err(RouterError::ContextError), + }, MsgEnvelope::Connection(msg) => match msg { ConnectionMsg::OpenInit(msg) => conn_open_init::execute(ctx, msg), ConnectionMsg::OpenTry(msg) => conn_open_try::execute(ctx, msg), ConnectionMsg::OpenAck(msg) => conn_open_ack::execute(ctx, msg), ConnectionMsg::OpenConfirm(ref msg) => conn_open_confirm::execute(ctx, msg), - } - .map_err(RouterError::ContextError), + }, MsgEnvelope::Channel(msg) => { let port_id = channel_msg_to_port_id(&msg); let module_id = router @@ -168,7 +150,6 @@ where ChannelMsg::CloseInit(msg) => chan_close_init_execute(ctx, module, msg), ChannelMsg::CloseConfirm(msg) => chan_close_confirm_execute(ctx, module, msg), } - .map_err(RouterError::ContextError) } MsgEnvelope::Packet(msg) => { let port_id = packet_msg_to_port_id(&msg); @@ -191,7 +172,6 @@ where timeout_packet_execute(ctx, module, TimeoutMsgType::TimeoutOnClose(msg)) } } - .map_err(RouterError::ContextError) } } } diff --git a/crates/ibc-core/ics25-handler/src/lib.rs b/crates/ibc-core/ics25-handler/src/lib.rs new file mode 100644 index 000000000..a9505d9aa --- /dev/null +++ b/crates/ibc-core/ics25-handler/src/lib.rs @@ -0,0 +1,26 @@ +//! Exposes IBC handler entry points for an integrated IBC core modules. These +//! entry points are responsible for processing incoming IBC messages, +//! performing validation, and execution logics by invoking the appropriate +//! module handler. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(any(test, feature = "std"))] +extern crate std; + +pub mod entrypoint; + +/// Re-export IBC handler types from `ibc-core-handler-types` crate. +pub mod types { + #[doc(inline)] + pub use ibc_core_handler_types::*; +} diff --git a/crates/ibc-core/ics25-handler/types/Cargo.toml b/crates/ibc-core/ics25-handler/types/Cargo.toml new file mode 100644 index 000000000..53eff8b37 --- /dev/null +++ b/crates/ibc-core/ics25-handler/types/Cargo.toml @@ -0,0 +1,115 @@ +[package] +name = "ibc-core-handler-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "handler", "types"] +readme = "./../../README.md" +description = """ + Maintained by `ibc-rs`, encapsulates essential ICS-25 Handler Interface data structures and domain types, + as specified in the Inter-Blockchain Communication (IBC) protocol. Designed for universal applicability + to facilitate development and integration across diverse IBC-enabled projects. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +serde = { workspace = true, optional = true } +schemars = { workspace = true, optional = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-core-client-types = { workspace = true } +ibc-core-connection-types = { workspace = true } +ibc-core-channel-types = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-core-router-types = { workspace = true } +ibc-primitives = { workspace = true } +ibc-proto = { workspace = true } + +# cosmos dependencies +tendermint = { workspace = true } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[dev-dependencies] +ibc-testkit = { workspace = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "serde/std", + "subtle-encoding/std", + "ibc-core-client-types/std", + "ibc-core-connection-types/std", + "ibc-core-channel-types/std", + "ibc-core-commitment-types/std", + "ibc-core-host-types/std", + "ibc-core-router-types/std", + "ibc-primitives/std", + "ibc-proto/std", + "tendermint/std", + "ibc-testkit/std", +] +serde = [ + "dep:serde", + "ibc-core-client-types/serde", + "ibc-core-connection-types/serde", + "ibc-core-channel-types/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host-types/serde", + "ibc-core-router-types/serde", + "ibc-primitives/serde", + "ibc-proto/serde", + "ibc-testkit/serde", +] +schema = [ + "dep:schemars", + "ibc-core-client-types/schema", + "ibc-core-connection-types/schema", + "ibc-core-channel-types/schema", + "ibc-core-commitment-types/schema", + "ibc-core-host-types/schema", + "ibc-core-router-types/schema", + "ibc-primitives/schema", + "ibc-proto/json-schema", + "serde", + "std" +] +borsh = [ + "dep:borsh", + "ibc-core-client-types/borsh", + "ibc-core-connection-types/borsh", + "ibc-core-channel-types/borsh", + "ibc-core-commitment-types/borsh", + "ibc-core-host-types/borsh", + "ibc-core-router-types/borsh", + "ibc-primitives/borsh", + "ibc-proto/borsh", +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-core-client-types/parity-scale-codec", + "ibc-core-connection-types/parity-scale-codec", + "ibc-core-channel-types/parity-scale-codec", + "ibc-core-commitment-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-core-router-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", + "ibc-proto/parity-scale-codec", +] diff --git a/crates/ibc-core/ics25-handler/types/src/error.rs b/crates/ibc-core/ics25-handler/types/src/error.rs new file mode 100644 index 000000000..5bea4b54d --- /dev/null +++ b/crates/ibc-core/ics25-handler/types/src/error.rs @@ -0,0 +1,48 @@ +//! Defines the context error type + +use derive_more::From; +use displaydoc::Display; +use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_client_types::error::ClientError; +use ibc_core_connection_types::error::ConnectionError; +use ibc_core_router_types::error::RouterError; +use ibc_primitives::prelude::*; + +/// Top-level error +#[derive(Debug, Display, From)] +pub enum ContextError { + /// ICS02 Client error: {0} + ClientError(ClientError), + /// ICS03 Connection error: {0} + ConnectionError(ConnectionError), + /// ICS04 Channel error: {0} + ChannelError(ChannelError), + /// ICS04 Packet error: {0} + PacketError(PacketError), + /// ICS26 Routing error: {0} + RouterError(RouterError), +} + +impl From for ClientError { + fn from(context_error: ContextError) -> Self { + match context_error { + ContextError::ClientError(e) => e, + _ => ClientError::Other { + description: context_error.to_string(), + }, + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ContextError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::ClientError(e) => Some(e), + Self::ConnectionError(e) => Some(e), + Self::ChannelError(e) => Some(e), + Self::PacketError(e) => Some(e), + Self::RouterError(e) => Some(e), + } + } +} diff --git a/crates/ibc/src/core/events.rs b/crates/ibc-core/ics25-handler/types/src/events.rs similarity index 76% rename from crates/ibc/src/core/events.rs rename to crates/ibc-core/ics25-handler/types/src/events.rs index b4a2b5292..56c236e91 100644 --- a/crates/ibc/src/core/events.rs +++ b/crates/ibc-core/ics25-handler/types/src/events.rs @@ -1,18 +1,18 @@ -//! Events emitted during message handling +//! Defines events emitted during handling of IBC messages use core::convert::{TryFrom, TryInto}; use displaydoc::Display; +use ibc_core_channel_types::{error as channel_error, events as ChannelEvents}; +use ibc_core_client_types::error as client_error; +use ibc_core_client_types::events::{self as ClientEvents}; +use ibc_core_connection_types::{error as connection_error, events as ConnectionEvents}; +use ibc_core_host_types::error::IdentifierError; +use ibc_core_router_types::event::ModuleEvent; +use ibc_primitives::prelude::*; +use ibc_primitives::ParseTimestampError; use tendermint::abci; -use super::ics24_host::identifier::IdentifierError; -use crate::core::ics02_client::error as client_error; -use crate::core::ics02_client::events::{self as ClientEvents}; -use crate::core::ics03_connection::{error as connection_error, events as ConnectionEvents}; -use crate::core::ics04_channel::{error as channel_error, events as ChannelEvents}; -use crate::core::timestamp::ParseTimestampError; -use crate::prelude::*; - /// All error variants related to IBC events #[derive(Debug, Display)] pub enum Error { @@ -122,7 +122,7 @@ impl TryFrom for abci::Event { IbcEvent::AcknowledgePacket(event) => event.try_into().map_err(Error::Channel)?, IbcEvent::TimeoutPacket(event) => event.try_into().map_err(Error::Channel)?, IbcEvent::ChannelClosed(event) => event.into(), - IbcEvent::Module(event) => event.try_into()?, + IbcEvent::Module(event) => event.into(), IbcEvent::Message(event) => abci::Event { kind: MESSAGE_EVENT.to_string(), attributes: vec![("module", event.module_attribute(), true).into()], @@ -160,79 +160,6 @@ impl IbcEvent { } } -/// The event type emitted by IBC applications -#[cfg_attr( - feature = "parity-scale-codec", - derive( - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_info::TypeInfo - ) -)] -#[cfg_attr( - feature = "borsh", - derive(borsh::BorshSerialize, borsh::BorshDeserialize) -)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ModuleEvent { - pub kind: String, - pub attributes: Vec, -} - -impl TryFrom for abci::Event { - type Error = Error; - - fn try_from(event: ModuleEvent) -> Result { - let attributes = event.attributes.into_iter().map(Into::into).collect(); - Ok(abci::Event { - kind: event.kind, - attributes, - }) - } -} - -impl From for IbcEvent { - fn from(e: ModuleEvent) -> Self { - IbcEvent::Module(e) - } -} - -/// A single key/value pair in a [`ModuleEvent`] -#[cfg_attr( - feature = "parity-scale-codec", - derive( - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_info::TypeInfo - ) -)] -#[cfg_attr( - feature = "borsh", - derive(borsh::BorshSerialize, borsh::BorshDeserialize) -)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ModuleEventAttribute { - pub key: String, - pub value: String, -} - -impl From<(K, V)> for ModuleEventAttribute { - fn from((k, v): (K, V)) -> Self { - Self { - key: k.to_string(), - value: v.to_string(), - } - } -} - -impl From for abci::EventAttribute { - fn from(attr: ModuleEventAttribute) -> Self { - (attr.key, attr.value).into() - } -} - /// An event type that is emitted by the Cosmos SDK. /// /// We need to emit it as well, as currently [hermes] relies on it. @@ -279,17 +206,22 @@ impl From for IbcEvent { } } +impl From for IbcEvent { + fn from(e: ModuleEvent) -> Self { + IbcEvent::Module(e) + } +} + #[cfg(test)] pub mod tests { - use alloc::vec; + use ibc_core_channel_types::channel::Order; + use ibc_core_channel_types::events::SendPacket; + use ibc_core_channel_types::packet::Packet; + use ibc_core_host_types::identifiers::ConnectionId; use ibc_testkit::utils::core::channel::dummy_raw_packet; use super::*; - use crate::core::ics04_channel::channel::Order; - use crate::core::ics04_channel::events::SendPacket; - use crate::core::ics04_channel::packet::Packet; - use crate::core::ics24_host::identifier::ConnectionId; #[test] /// Ensures that we don't panic when packet data is not valid UTF-8. diff --git a/crates/ibc-core/ics25-handler/types/src/lib.rs b/crates/ibc-core/ics25-handler/types/src/lib.rs new file mode 100644 index 000000000..60d03ad14 --- /dev/null +++ b/crates/ibc-core/ics25-handler/types/src/lib.rs @@ -0,0 +1,21 @@ +//! Encapsulates essential data structures facilitating the seamless +//! interaction between an implemented IBC module using ibc-rs and the +//! underlying host blockchain. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +pub mod error; +pub mod events; +pub mod msgs; diff --git a/crates/ibc-core/ics25-handler/types/src/msgs.rs b/crates/ibc-core/ics25-handler/types/src/msgs.rs new file mode 100644 index 000000000..849bcaaf6 --- /dev/null +++ b/crates/ibc-core/ics25-handler/types/src/msgs.rs @@ -0,0 +1,206 @@ +use ibc_core_channel_types::msgs::{ + ChannelMsg, MsgAcknowledgement, MsgChannelCloseConfirm, MsgChannelCloseInit, MsgChannelOpenAck, + MsgChannelOpenConfirm, MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket, MsgTimeout, + MsgTimeoutOnClose, PacketMsg, ACKNOWLEDGEMENT_TYPE_URL, CHAN_CLOSE_CONFIRM_TYPE_URL, + CHAN_CLOSE_INIT_TYPE_URL, CHAN_OPEN_ACK_TYPE_URL, CHAN_OPEN_CONFIRM_TYPE_URL, + CHAN_OPEN_INIT_TYPE_URL, CHAN_OPEN_TRY_TYPE_URL, RECV_PACKET_TYPE_URL, + TIMEOUT_ON_CLOSE_TYPE_URL, TIMEOUT_TYPE_URL, +}; +use ibc_core_client_types::msgs::{ + ClientMsg, MsgCreateClient, MsgSubmitMisbehaviour, MsgUpdateClient, MsgUpgradeClient, + CREATE_CLIENT_TYPE_URL, SUBMIT_MISBEHAVIOUR_TYPE_URL, UPDATE_CLIENT_TYPE_URL, + UPGRADE_CLIENT_TYPE_URL, +}; +use ibc_core_connection_types::msgs::{ + ConnectionMsg, MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenInit, + MsgConnectionOpenTry, CONN_OPEN_ACK_TYPE_URL, CONN_OPEN_CONFIRM_TYPE_URL, + CONN_OPEN_INIT_TYPE_URL, CONN_OPEN_TRY_TYPE_URL, +}; +use ibc_core_router_types::error::RouterError; +use ibc_primitives::prelude::*; +use ibc_proto::google::protobuf::Any; +use ibc_proto::Protobuf; + +/// Enumeration of all messages that the local ICS26 module is capable of routing. +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[derive(Clone, Debug, PartialEq, Eq, derive_more::From)] +pub enum MsgEnvelope { + Client(ClientMsg), + Connection(ConnectionMsg), + Channel(ChannelMsg), + Packet(PacketMsg), +} + +impl TryFrom for MsgEnvelope { + type Error = RouterError; + + fn try_from(any_msg: Any) -> Result { + match any_msg.type_url.as_str() { + // ICS2 messages + CREATE_CLIENT_TYPE_URL => { + // Pop out the message and then wrap it in the corresponding type. + let domain_msg = MsgCreateClient::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Client(ClientMsg::CreateClient(domain_msg))) + } + UPDATE_CLIENT_TYPE_URL => { + let domain_msg = MsgUpdateClient::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Client(ClientMsg::UpdateClient(domain_msg))) + } + UPGRADE_CLIENT_TYPE_URL => { + let domain_msg = MsgUpgradeClient::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Client(ClientMsg::UpgradeClient(domain_msg))) + } + SUBMIT_MISBEHAVIOUR_TYPE_URL => { + let domain_msg = + MsgSubmitMisbehaviour::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Client(ClientMsg::Misbehaviour(domain_msg))) + } + + // ICS03 + CONN_OPEN_INIT_TYPE_URL => { + let domain_msg = + MsgConnectionOpenInit::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Connection(ConnectionMsg::OpenInit(domain_msg))) + } + CONN_OPEN_TRY_TYPE_URL => { + let domain_msg = MsgConnectionOpenTry::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Connection(ConnectionMsg::OpenTry(domain_msg))) + } + CONN_OPEN_ACK_TYPE_URL => { + let domain_msg = MsgConnectionOpenAck::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Connection(ConnectionMsg::OpenAck(domain_msg))) + } + CONN_OPEN_CONFIRM_TYPE_URL => { + let domain_msg = + MsgConnectionOpenConfirm::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Connection(ConnectionMsg::OpenConfirm( + domain_msg, + ))) + } + + // ICS04 channel messages + CHAN_OPEN_INIT_TYPE_URL => { + let domain_msg = MsgChannelOpenInit::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Channel(ChannelMsg::OpenInit(domain_msg))) + } + CHAN_OPEN_TRY_TYPE_URL => { + let domain_msg = MsgChannelOpenTry::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Channel(ChannelMsg::OpenTry(domain_msg))) + } + CHAN_OPEN_ACK_TYPE_URL => { + let domain_msg = MsgChannelOpenAck::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Channel(ChannelMsg::OpenAck(domain_msg))) + } + CHAN_OPEN_CONFIRM_TYPE_URL => { + let domain_msg = + MsgChannelOpenConfirm::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Channel(ChannelMsg::OpenConfirm(domain_msg))) + } + CHAN_CLOSE_INIT_TYPE_URL => { + let domain_msg = MsgChannelCloseInit::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Channel(ChannelMsg::CloseInit(domain_msg))) + } + CHAN_CLOSE_CONFIRM_TYPE_URL => { + let domain_msg = + MsgChannelCloseConfirm::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Channel(ChannelMsg::CloseConfirm(domain_msg))) + } + // ICS04 packet messages + RECV_PACKET_TYPE_URL => { + let domain_msg = MsgRecvPacket::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Packet(PacketMsg::Recv(domain_msg))) + } + ACKNOWLEDGEMENT_TYPE_URL => { + let domain_msg = MsgAcknowledgement::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Packet(PacketMsg::Ack(domain_msg))) + } + TIMEOUT_TYPE_URL => { + let domain_msg = MsgTimeout::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Packet(PacketMsg::Timeout(domain_msg))) + } + TIMEOUT_ON_CLOSE_TYPE_URL => { + let domain_msg = MsgTimeoutOnClose::decode_vec(&any_msg.value).map_err(|e| { + RouterError::MalformedMessageBytes { + reason: e.to_string(), + } + })?; + Ok(MsgEnvelope::Packet(PacketMsg::TimeoutOnClose(domain_msg))) + } + _ => Err(RouterError::UnknownMessageTypeUrl { + url: any_msg.type_url, + }), + } + } +} diff --git a/crates/ibc-core/ics26-routing/Cargo.toml b/crates/ibc-core/ics26-routing/Cargo.toml new file mode 100644 index 000000000..a363eb0a1 --- /dev/null +++ b/crates/ibc-core/ics26-routing/Cargo.toml @@ -0,0 +1,66 @@ +[package] +name = "ibc-core-router" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "routing"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, contains necessary traits to implement the routing and callback functionality + (IBC router module) used for connecting the application layer to the transport layer of an IBC enabled chain. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-primitives = { workspace = true } +ibc-core-channel-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-core-router-types = { workspace = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "subtle-encoding/std", + "ibc-primitives/std", + "ibc-core-channel-types/std", + "ibc-core-host-types/std", + "ibc-core-router-types/std", +] +serde = [ + "ibc-primitives/serde", + "ibc-core-channel-types/serde", + "ibc-core-host-types/serde", + "ibc-core-router-types/serde", +] +borsh = [ + "ibc-primitives/borsh", + "ibc-core-channel-types/borsh", + "ibc-core-host-types/borsh", + "ibc-core-router-types/borsh", +] +schema = [ + "ibc-core-channel-types/schema", + "ibc-core-host-types/schema", + "ibc-core-router-types/schema", + "ibc-primitives/schema", +] +parity-scale-codec = [ + "ibc-core-channel-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-core-router-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] diff --git a/crates/ibc-core/ics26-routing/src/lib.rs b/crates/ibc-core/ics26-routing/src/lib.rs new file mode 100644 index 000000000..b5b585ee5 --- /dev/null +++ b/crates/ibc-core/ics26-routing/src/lib.rs @@ -0,0 +1,24 @@ +//! This library contains necessary traits to implement an IBC router module when integrating with `ibc-rs`. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +#[cfg(feature = "std")] +extern crate std; + +pub mod module; +pub mod router; + +/// Re-exports router data structures from the `ibc-core-router-types` crate +pub mod types { + #[doc(inline)] + pub use ibc_core_router_types::*; +} diff --git a/crates/ibc/src/core/router.rs b/crates/ibc-core/ics26-routing/src/module.rs similarity index 58% rename from crates/ibc/src/core/router.rs rename to crates/ibc-core/ics26-routing/src/module.rs index 4cdb66524..26b296713 100644 --- a/crates/ibc/src/core/router.rs +++ b/crates/ibc-core/ics26-routing/src/module.rs @@ -1,99 +1,16 @@ -//! Defines the `Router`, which binds modules to ports - -use alloc::borrow::Borrow; -use core::fmt::{Debug, Display, Error as FmtError, Formatter}; - -use crate::core::events::ModuleEvent; -use crate::core::ics04_channel::acknowledgement::Acknowledgement; -use crate::core::ics04_channel::channel::{Counterparty, Order}; -use crate::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::core::ics04_channel::packet::Packet; -use crate::core::ics04_channel::Version; -use crate::core::ics24_host::identifier::{ChannelId, ConnectionId, PortId}; -use crate::prelude::*; -use crate::signer::Signer; - -/// Router as defined in ICS-26, which binds modules to ports. -pub trait Router { - /// Returns a reference to a `Module` registered against the specified `ModuleId` - fn get_route(&self, module_id: &ModuleId) -> Option<&dyn Module>; - - /// Returns a mutable reference to a `Module` registered against the specified `ModuleId` - fn get_route_mut(&mut self, module_id: &ModuleId) -> Option<&mut dyn Module>; - - /// Return the module_id associated with a given port_id - fn lookup_module(&self, port_id: &PortId) -> Option; -} - -/// Module name, internal to the chain. -/// -/// That is, the IBC protocol never exposes this name. Note that this is -/// different from IBC host [identifiers][crate::core::ics24_host::identifier], -/// which are exposed to other chains by the protocol. -#[cfg_attr( - feature = "parity-scale-codec", - derive( - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_info::TypeInfo - ) -)] -#[cfg_attr( - feature = "borsh", - derive(borsh::BorshSerialize, borsh::BorshDeserialize) -)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ModuleId(String); - -impl ModuleId { - pub fn new(s: String) -> Self { - Self(s) - } -} - -impl Display for ModuleId { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!(f, "{}", self.0) - } -} - -impl Borrow for ModuleId { - fn borrow(&self) -> &str { - self.0.as_str() - } -} - -/// Logs and events produced during module callbacks -#[cfg_attr( - feature = "parity-scale-codec", - derive( - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_info::TypeInfo - ) -)] -#[cfg_attr( - feature = "borsh", - derive(borsh::BorshSerialize, borsh::BorshDeserialize) -)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Debug)] -pub struct ModuleExtras { - pub events: Vec, - pub log: Vec, -} - -impl ModuleExtras { - pub fn empty() -> Self { - ModuleExtras { - events: Vec::new(), - log: Vec::new(), - } - } -} - /// The trait that defines an IBC application +use core::fmt::Debug; + +use ibc_core_channel_types::acknowledgement::Acknowledgement; +use ibc_core_channel_types::channel::{Counterparty, Order}; +use ibc_core_channel_types::error::{ChannelError, PacketError}; +use ibc_core_channel_types::packet::Packet; +use ibc_core_channel_types::Version; +use ibc_core_host_types::identifiers::{ChannelId, ConnectionId, PortId}; +use ibc_core_router_types::module::ModuleExtras; +use ibc_primitives::prelude::*; +use ibc_primitives::Signer; + pub trait Module: Debug { fn on_chan_open_init_validate( &self, diff --git a/crates/ibc-core/ics26-routing/src/router.rs b/crates/ibc-core/ics26-routing/src/router.rs new file mode 100644 index 000000000..b73d16d5c --- /dev/null +++ b/crates/ibc-core/ics26-routing/src/router.rs @@ -0,0 +1,18 @@ +//! Defines the `Router`, which binds modules to ports + +use ibc_core_host_types::identifiers::PortId; +use ibc_core_router_types::module::ModuleId; + +use crate::module::Module; + +/// Router as defined in ICS-26, which binds modules to ports. +pub trait Router { + /// Returns a reference to a `Module` registered against the specified `ModuleId` + fn get_route(&self, module_id: &ModuleId) -> Option<&dyn Module>; + + /// Returns a mutable reference to a `Module` registered against the specified `ModuleId` + fn get_route_mut(&mut self, module_id: &ModuleId) -> Option<&mut dyn Module>; + + /// Return the module_id associated with a given port_id + fn lookup_module(&self, port_id: &PortId) -> Option; +} diff --git a/crates/ibc-core/ics26-routing/types/Cargo.toml b/crates/ibc-core/ics26-routing/types/Cargo.toml new file mode 100644 index 000000000..a20fb8f0f --- /dev/null +++ b/crates/ibc-core/ics26-routing/types/Cargo.toml @@ -0,0 +1,84 @@ +[package] +name = "ibc-core-router-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc", "routing", "types"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, encapsulates essential ICS-26 Routing Module data structures and domain types, + as specified in the Inter-Blockchain Communication (IBC) protocol. Designed for universal applicability + to facilitate development and integration across diverse IBC-enabled projects. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +schemars = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +subtle-encoding = { workspace = true } + +# ibc dependencies +ibc-core-host-types = { workspace = true } +ibc-primitives = { workspace = true } +ibc-proto = {workspace = true } +ics23 = { workspace = true } + +# cosmos dependencies +tendermint = { workspace = true } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "serde/std", + "subtle-encoding/std", + "ibc-primitives/std", + "ibc-core-host-types/std", + "ibc-proto/std", + "ics23/std", + "tendermint/std", +] +serde = [ + "dep:serde", + "ibc-primitives/serde", + "ibc-core-host-types/serde", + "ibc-primitives/serde", + "ibc-proto/serde", + "ics23/serde", +] +borsh = [ + "dep:borsh", + "ibc-core-host-types/borsh", + "ibc-primitives/borsh", + "ibc-proto/borsh", +] +schema = [ + "dep:schemars", + "ibc-core-host-types/schema", + "ibc-primitives/schema", + "ibc-proto/json-schema", + "serde", + "std" +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-core-host-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", + "ibc-proto/parity-scale-codec", +] diff --git a/crates/ibc-core/ics26-routing/types/src/error.rs b/crates/ibc-core/ics26-routing/types/src/error.rs new file mode 100644 index 000000000..01fb3c6c6 --- /dev/null +++ b/crates/ibc-core/ics26-routing/types/src/error.rs @@ -0,0 +1,19 @@ +use displaydoc::Display; +use ibc_core_host_types::identifiers::PortId; +use ibc_primitives::prelude::*; + +/// Error type for the router module. +#[derive(Debug, Display)] +pub enum RouterError { + /// unknown type URL `{url}` + UnknownMessageTypeUrl { url: String }, + /// the message is malformed and cannot be decoded error: `{reason}` + MalformedMessageBytes { reason: String }, + /// port `{port_id}` is unknown + UnknownPort { port_id: PortId }, + /// module not found + ModuleNotFound, +} + +#[cfg(feature = "std")] +impl std::error::Error for RouterError {} diff --git a/crates/ibc-core/ics26-routing/types/src/event.rs b/crates/ibc-core/ics26-routing/types/src/event.rs new file mode 100644 index 000000000..b3754b2d7 --- /dev/null +++ b/crates/ibc-core/ics26-routing/types/src/event.rs @@ -0,0 +1,67 @@ +use ibc_primitives::prelude::*; +use tendermint::abci; + +/// The event type emitted by IBC applications +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ModuleEvent { + pub kind: String, + pub attributes: Vec, +} + +impl From for abci::Event { + fn from(event: ModuleEvent) -> Self { + let attributes = event.attributes.into_iter().map(Into::into).collect(); + abci::Event { + kind: event.kind, + attributes, + } + } +} + +/// A single key/value pair in a [`ModuleEvent`] +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ModuleEventAttribute { + pub key: String, + pub value: String, +} + +impl From<(K, V)> for ModuleEventAttribute { + fn from((k, v): (K, V)) -> Self { + Self { + key: k.to_string(), + value: v.to_string(), + } + } +} + +impl From for abci::EventAttribute { + fn from(attr: ModuleEventAttribute) -> Self { + (attr.key, attr.value).into() + } +} diff --git a/crates/ibc-core/ics26-routing/types/src/lib.rs b/crates/ibc-core/ics26-routing/types/src/lib.rs new file mode 100644 index 000000000..6ca759f79 --- /dev/null +++ b/crates/ibc-core/ics26-routing/types/src/lib.rs @@ -0,0 +1,24 @@ +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +pub mod error; +pub mod event; +pub mod module; + +pub mod primitives { + pub use ibc_primitives::*; +} diff --git a/crates/ibc-core/ics26-routing/types/src/module.rs b/crates/ibc-core/ics26-routing/types/src/module.rs new file mode 100644 index 000000000..82867fde0 --- /dev/null +++ b/crates/ibc-core/ics26-routing/types/src/module.rs @@ -0,0 +1,74 @@ +use alloc::borrow::Borrow; +use core::fmt::{Debug, Display, Error as FmtError, Formatter}; + +use ibc_primitives::prelude::*; + +use crate::event::ModuleEvent; + +/// Module name, internal to the chain. +/// +/// That is, the IBC protocol never exposes this name. Note that this is +/// different from IBC host [identifiers][ibc_core_host_types::identifiers], +/// which are exposed to other chains by the protocol. +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct ModuleId(String); + +impl ModuleId { + pub fn new(s: String) -> Self { + Self(s) + } +} + +impl Display for ModuleId { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { + write!(f, "{}", self.0) + } +} + +impl Borrow for ModuleId { + fn borrow(&self) -> &str { + self.0.as_str() + } +} + +/// Logs and events produced during module callbacks +#[cfg_attr( + feature = "parity-scale-codec", + derive( + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_info::TypeInfo + ) +)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshSerialize, borsh::BorshDeserialize) +)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug)] +pub struct ModuleExtras { + pub events: Vec, + pub log: Vec, +} + +impl ModuleExtras { + pub fn empty() -> Self { + ModuleExtras { + events: Vec::new(), + log: Vec::new(), + } + } +} diff --git a/crates/ibc-core/src/lib.rs b/crates/ibc-core/src/lib.rs new file mode 100644 index 000000000..444129f02 --- /dev/null +++ b/crates/ibc-core/src/lib.rs @@ -0,0 +1,67 @@ +//! Re-exports data structures and implementations of all the IBC core (TAO) modules/components. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +/// Re-exports IBC handler entrypoints from the `ibc-core-handler` crate for +/// added convenience. +pub mod entrypoint { + #[doc(inline)] + pub use ibc_core_handler::entrypoint::*; +} + +/// Re-exports IBC primitive types from the `ibc-primitives` crate +pub mod primitives { + #[doc(inline)] + pub use ibc_primitives::*; +} + +/// Re-exports ICS-02 implementation from the `ibc-core-client` crate +pub mod client { + #[doc(inline)] + pub use ibc_core_client::*; +} + +/// Re-exports ICS-03 implementation from the `ibc-core-connection` crate +pub mod connection { + #[doc(inline)] + pub use ibc_core_connection::*; +} + +/// Re-exports ICS-04 implementation from the `ibc-core-channel` crate +pub mod channel { + #[doc(inline)] + pub use ibc_core_channel::*; +} + +/// Re-exports ICS-23 data structures from the `ibc-core-commitment-types` crate +pub mod commitment_types { + #[doc(inline)] + pub use ibc_core_commitment_types::*; +} + +/// Re-exports ICS-24 implementation from the `ibc-core-host` crate +pub mod host { + #[doc(inline)] + pub use ibc_core_host::*; +} + +/// Re-exports ICS-25 implementation from the `ibc-core-handler` crate +pub mod handler { + #[doc(inline)] + pub use ibc_core_handler::*; +} + +/// Re-exports ICS-26 implementation from the `ibc-core-router` crate +pub mod router { + #[doc(inline)] + pub use ibc_core_router::*; +} diff --git a/crates/ibc-data-types/Cargo.toml b/crates/ibc-data-types/Cargo.toml new file mode 100644 index 000000000..d47bd254e --- /dev/null +++ b/crates/ibc-data-types/Cargo.toml @@ -0,0 +1,83 @@ +[package] +name = "ibc-data-types" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, delineates standard data structures and domain types of the Inter-Blockchain Communication (IBC) protocol. + Designed for universal application, enabling diverse projects across IBC ecosystem to build using a shared language. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +ibc-app-transfer-types = { workspace = true } +ibc-core-client-types = { workspace = true } +ibc-core-connection-types = { workspace = true } +ibc-core-channel-types = { workspace = true } +ibc-core-commitment-types = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-core-router-types = { workspace = true } +ibc-core-handler-types = { workspace = true } +ibc-primitives = { workspace = true } + +[features] +default = ["std"] +std = [ + "ibc-app-transfer-types/std", + "ibc-core-client-types/std", + "ibc-core-connection-types/std", + "ibc-core-channel-types/std", + "ibc-core-commitment-types/std", + "ibc-core-host-types/std", + "ibc-core-router-types/std", + "ibc-core-handler-types/std", + "ibc-primitives/std", +] +serde = [ + "ibc-app-transfer-types/serde", + "ibc-core-client-types/serde", + "ibc-core-connection-types/serde", + "ibc-core-channel-types/serde", + "ibc-core-commitment-types/serde", + "ibc-core-host-types/serde", + "ibc-core-router-types/serde", + "ibc-core-handler-types/serde", + "ibc-primitives/serde", +] +borsh = [ + "ibc-app-transfer-types/borsh", + "ibc-core-client-types/borsh", + "ibc-core-connection-types/borsh", + "ibc-core-channel-types/borsh", + "ibc-core-host-types/borsh", + "ibc-core-router-types/borsh", + "ibc-core-handler-types/borsh", + "ibc-primitives/borsh", +] +schema = [ + "ibc-app-transfer-types/schema", + "ibc-core-client-types/schema", + "ibc-core-connection-types/schema", + "ibc-core-channel-types/schema", + "ibc-core-host-types/schema", + "ibc-core-router-types/schema", + "ibc-core-handler-types/schema", + "ibc-primitives/schema", +] +parity-scale-codec = [ + "ibc-app-transfer-types/parity-scale-codec", + "ibc-core-client-types/parity-scale-codec", + "ibc-core-connection-types/parity-scale-codec", + "ibc-core-channel-types/parity-scale-codec", + "ibc-core-host-types/parity-scale-codec", + "ibc-core-router-types/parity-scale-codec", + "ibc-core-handler-types/parity-scale-codec", + "ibc-primitives/parity-scale-codec", +] \ No newline at end of file diff --git a/crates/ibc-data-types/README.md b/crates/ibc-data-types/README.md new file mode 100644 index 000000000..d6d71f31c --- /dev/null +++ b/crates/ibc-data-types/README.md @@ -0,0 +1,50 @@ +# IBC Types + +This crate serves as a central hub for re-exporting the implemented +Inter-Blockchain Communication (IBC) data structures. It simplifies the +integration of various IBC domain types into your project. IBC is a distributed +protocol facilitating communication between independent sovereign blockchains +and The IBC data structures within this crate abstract various IBC +specifications, offering a convenient means to encode and decode IBC messages to +and from proto types exposed by +[`ibc-proto`](https://github.com/cosmos/ibc-proto-rs) crate. Additionally, it +supports parsing events to and from ABCI event types. + +## Sub-Crates + +This crate organizes data structures into three main modules: `core`, `clients`, +and `apps`. Each category further re-exports its respective sub data structures, +providing a clear and modular path for easy navigation and usage: + +### Core + +|
Specification
| Crate | +| ------------------------------------------- | ----- | +| ICS-02: Client Semantics | [ibc-core-client-types](./../ibc-apps/ics02-client/types) | +| ICS-03: Connection Semantics | [ibc-core-connection-types](./../ibc-core/ics03-connection/types) | +| ICS-04: Channel and Packet Semantics | [ibc-core-channel-types](./../ibc-core/ics04-channel/types) | +| ICS-24: Host Requirements | [ibc-core-host-types](./../ibc-core/ics24-host/types) | +| ICS-25: Handler Interface | [ibc-core-handler-types](./../ibc-core/ics25-handler/types) | +| ICS-26: Routing Module | [ibc-core-routing-types](./../ibc-core/ics26-routing/types) | + +### Clients + +|
Specification
| Crate | +| ------------------------------------------- | ----- | +| ICS-07: Tendermint Client | [ibc-client-tendermint-types](./../ibc-clients/ics07-tendermint/types) | + +### Apps + +|
Specification
| Crate | +| ------------------------------------------- | ----- | +| ICS-20: Fungible Token Transfer | [ibc-app-transfer-types](./../ibc-apps/ics20-transfer/types) | + +## Contributing + +IBC is specified in English in the [cosmos/ibc +repo](https://github.com/cosmos/ibc). Any protocol changes or clarifications +should be contributed there. + +If you're interested in contributing, please take a look at the +[CONTRIBUTING](./../../CONTRIBUTING.md) guidelines. We welcome and appreciate +community contributions! diff --git a/crates/ibc-data-types/src/lib.rs b/crates/ibc-data-types/src/lib.rs new file mode 100644 index 000000000..9e849a593 --- /dev/null +++ b/crates/ibc-data-types/src/lib.rs @@ -0,0 +1,77 @@ +//! Re-exports data structures of various specifications within the +//! Inter-Blockchain Communication (IBC) protocol. Designed for universal +//! application, enabling diverse projects across IBC ecosystem to build using a +//! shared language. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types,))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +/// Re-exports IBC primitive types from the `ibc-primitives` crate +pub mod primitives { + #[doc(inline)] + pub use ibc_primitives::*; +} + +/// Re-exports data structures of all IBC core specifications +pub mod core { + /// Re-exports ICS-02 client data structures from the + /// `ibc-core-client-types` crate + pub mod client { + #[doc(inline)] + pub use ibc_core_client_types::*; + } + /// Re-exports ICS-03 connection data structures from the + /// `ibc-core-connection-types` crate + pub mod connection { + #[doc(inline)] + pub use ibc_core_connection_types::*; + } + /// Re-exports ICS-04 channel data structures from the + /// `ibc-core-channel-types` crate + pub mod channel { + #[doc(inline)] + pub use ibc_core_channel_types::*; + } + /// Re-exports ICS-23 commitment data structures from the + /// `ibc-core-commitment-types` crate + pub mod commitment { + #[doc(inline)] + pub use ibc_core_commitment_types::*; + } + /// Re-exports ICS-24 host data structures from the `ibc-core-host-types` + /// crate + pub mod host { + #[doc(inline)] + pub use ibc_core_host_types::*; + } + /// Re-exports ICS-25 handler data structures from the + /// `ibc-core-handler-types` crate + pub mod handler { + #[doc(inline)] + pub use ibc_core_handler_types::*; + } + /// Re-exports ICS-26 routing data structures from the + /// `ibc-core-router-types` crate + pub mod router { + #[doc(inline)] + pub use ibc_core_router_types::*; + } +} + +/// Re-exports data structures of various IBC applications +pub mod apps { + /// Re-exports ICS-27 client update data structures from the + /// `ibc-core-client-types` crate + pub mod transfer { + #[doc(inline)] + pub use ibc_app_transfer_types::*; + } +} diff --git a/crates/ibc-derive/Cargo.toml b/crates/ibc-derive/Cargo.toml index e89af7e67..7fffe6302 100644 --- a/crates/ibc-derive/Cargo.toml +++ b/crates/ibc-derive/Cargo.toml @@ -3,7 +3,7 @@ name = "ibc-derive" version = "0.3.0" license = "Apache-2.0" readme = "README.md" -description = "Macros implementation of #[derive(ClientState)] and #[derive(ConsensusState)]" +description = "Maintained by `ibc-rs`, macros implementations of #[derive(ClientState)] and #[derive(ConsensusState)]" repository = "https://github.com/cosmos/ibc-rs" edition = "2021" diff --git a/crates/ibc-derive/README.md b/crates/ibc-derive/README.md index 06db5de09..66d35fd4c 100644 --- a/crates/ibc-derive/README.md +++ b/crates/ibc-derive/README.md @@ -1,83 +1,9 @@ -# IBC in Rust +# IBC Derive -[![Crate][crate-image]][crate-link] -[![Docs][docs-image]][docs-link] -[![Build Status][build-image]][build-link] -[![Apache 2.0 Licensed][license-image]][license-link] -![Rust Stable][rustc-image] -![Rust 1.60+][rustc-version] +This crate provides a set of procedural macros for deriving IBC-related traits +defined in the [`ibc-rs`](https://github.com/cosmos/ibc-rs) repository. reducing +the amount of boilerplate code required to implement them. It already contains +macro implementations for the following traits: -Implementation of the Inter-Blockchain Communication Protocol ([IBC]) in Rust. - -## Documentation - -See documentation on [docs.rs][docs-link]. - -## Third-party clients - -Here, we list IBC third-party clients that are compatible with ibc-rs. You should always audit the implementation of any third-party crate. If you have a client that you'd like to be added to this list, please open a PR! - -+ [ICS 6: Solomachine](https://github.com/octopus-network/ics06-solomachine) by Octopus Network - -## Divergence from the Interchain Standards (ICS) - -This crate diverges from the [ICS specification](https://github.com/cosmos/ibc) in a number of ways. See below for more details. - -### Module system: no support for untrusted modules - -ICS 24 (Host Requirements) gives the [following requirement](https://github.com/cosmos/ibc/blob/master/spec/core/ics-024-host-requirements/README.md#module-system) about the module system that the host state machine must support: - -> The host state machine must support a module system, whereby self-contained, potentially mutually distrusted packages of code can safely execute on the same ledger [...]. - -**This crate currently does not support mutually distrusted packages**. That is, modules on the host state machine are assumed to be fully trusted. In practice, this means that every module has either been written by the host state machine developers, or fully vetted by them. - -### Port system: No object capability system - -ICS 5 (Port Allocation) requires the host system to support either object-capability reference or source authentication for modules. - -> In the former object-capability case, the IBC handler must have the ability to generate object-capabilities, unique, opaque references which can be passed to a module and will not be duplicable by other modules. [...] -> In the latter source authentication case, the IBC handler must have the ability to securely read the source identifier of the calling module, a unique string for each module in the host state machine, which cannot be altered by the module or faked by another module. - -**This crate currently requires neither of the host system**. Since modules are assumed to be trusted, there is no need for this object capability system that protects resources for potentially malicious modules. - -For more background on this, see [this issue](https://github.com/informalsystems/ibc-rs/issues/2159). - -### Port system: transferring and releasing a port - -ICS 5 (Port Allocation) requires the IBC handler to permit [transferring ownership of a port](https://github.com/cosmos/ibc/tree/master/spec/core/ics-005-port-allocation#transferring-ownership-of-a-port) and [releasing a port](https://github.com/cosmos/ibc/tree/master/spec/core/ics-005-port-allocation#releasing-a-port). - -We currently support neither. - -### Asynchronous acknowledgements -The standard gives the ability for modules to [acknowledge packets asynchronously](https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics#writing-acknowledgements). This allows modules to receive the packet, but only applying the changes at a later time (after which they would write the acknowledgement). - -We currently force applications to process the packets as part of `onRecvPacket()`. If you need asynchronous acknowledgements for your application, please open an issue. - -Note that this still makes us 100% compatible with ibc-go. - -## License - -Copyright © 2021 Informal Systems Inc. and ibc-rs authors. - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use the files in this repository except in compliance with the License. You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - -[//]: # (badges) - -[crate-image]: https://img.shields.io/crates/v/ibc.svg -[crate-link]: https://crates.io/crates/ibc -[docs-image]: https://docs.rs/ibc/badge.svg -[docs-link]: https://docs.rs/ibc/ -[build-image]: https://github.com/cosmos/ibc-rs/workflows/Rust/badge.svg -[build-link]: https://github.com/cosmos/ibc-rs/actions?query=workflow%3ARust -[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg -[license-link]: https://github.com/cosmos/ibc-rs/blob/main/LICENSE -[rustc-image]: https://img.shields.io/badge/rustc-stable-blue.svg -[rustc-version]: https://img.shields.io/badge/rustc-1.60+-blue.svg - -[//]: # (general links) - -[IBC]: https://github.com/cosmos/ibc +- [ClientState](./../ibc-core/ics02-client/context/src/client_state.rs) +- [ConsensusState](./../ibc-core/ics02-client/context/src/consensus_state.rs) diff --git a/crates/ibc-derive/src/utils.rs b/crates/ibc-derive/src/utils.rs index 333c18da2..3a1ea8b66 100644 --- a/crates/ibc-derive/src/utils.rs +++ b/crates/ibc-derive/src/utils.rs @@ -10,67 +10,67 @@ pub struct Imports; impl Imports { pub fn CommitmentRoot() -> TokenStream { - quote! {ibc::core::ics23_commitment::commitment::CommitmentRoot} + quote! {ibc::core::commitment_types::commitment::CommitmentRoot} } pub fn CommitmentPrefix() -> TokenStream { - quote! {ibc::core::ics23_commitment::commitment::CommitmentPrefix} + quote! {ibc::core::commitment_types::commitment::CommitmentPrefix} } pub fn CommitmentProofBytes() -> TokenStream { - quote! {ibc::core::ics23_commitment::commitment::CommitmentProofBytes} + quote! {ibc::core::commitment_types::commitment::CommitmentProofBytes} } pub fn Path() -> TokenStream { - quote! {ibc::core::ics24_host::path::Path} + quote! {ibc::core::host::types::path::Path} } pub fn ConsensusState() -> TokenStream { - quote! {ibc::core::ics02_client::consensus_state::ConsensusState} + quote! {ibc::core::client::context::consensus_state::ConsensusState} } pub fn ClientStateCommon() -> TokenStream { - quote! {ibc::core::ics02_client::client_state::ClientStateCommon} + quote! {ibc::core::client::context::client_state::ClientStateCommon} } pub fn ClientStateValidation() -> TokenStream { - quote! {ibc::core::ics02_client::client_state::ClientStateValidation} + quote! {ibc::core::client::context::client_state::ClientStateValidation} } pub fn ClientStateExecution() -> TokenStream { - quote! {ibc::core::ics02_client::client_state::ClientStateExecution} + quote! {ibc::core::client::context::client_state::ClientStateExecution} } pub fn ClientId() -> TokenStream { - quote! {ibc::core::ics24_host::identifier::ClientId} + quote! {ibc::core::host::types::identifiers::ClientId} } pub fn ClientType() -> TokenStream { - quote! {ibc::core::ics02_client::client_type::ClientType} + quote! {ibc::core::host::types::identifiers::ClientType} } pub fn ClientError() -> TokenStream { - quote! {ibc::core::ics02_client::error::ClientError} + quote! {ibc::core::client::types::error::ClientError} } pub fn Height() -> TokenStream { - quote! {ibc::Height} + quote! {ibc::core::client::types::Height} } pub fn Any() -> TokenStream { - quote! {ibc::proto::Any} + quote! {ibc::primitives::proto::Any} } pub fn Timestamp() -> TokenStream { - quote! {ibc::core::timestamp::Timestamp} + quote! {ibc::core::primitives::Timestamp} } pub fn UpdateKind() -> TokenStream { - quote! {ibc::core::ics02_client::client_state::UpdateKind} + quote! {ibc::core::client::types::UpdateKind} } pub fn Status() -> TokenStream { - quote! {ibc::core::ics02_client::client_state::Status} + quote! {ibc::core::client::types::Status} } } diff --git a/crates/ibc-primitives/Cargo.toml b/crates/ibc-primitives/Cargo.toml new file mode 100644 index 000000000..74f685233 --- /dev/null +++ b/crates/ibc-primitives/Cargo.toml @@ -0,0 +1,68 @@ +[package] +name = "ibc-primitives" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +rust-version = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +keywords = ["blockchain", "cosmos", "ibc"] +readme = "README.md" +description = """ + Maintained by `ibc-rs`, furnishes essential types and traits universally + utilized in the implementation of diverse IBC modules, encompassing + core functionalities, clients, and applications. +""" + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +# external dependencies +borsh = { workspace = true, optional = true } +derive_more = { workspace = true } +displaydoc = { workspace = true } +prost = { workspace = true } +schemars = { workspace = true, optional = true } +serde = { workspace = true, optional = true } +time = { workspace = true } + +# ibc dependencies +ibc-proto = { workspace = true } + +# cosmos dependencies +tendermint = { workspace = true } + +# parity dependencies +parity-scale-codec = { workspace = true, optional = true } +scale-info = { workspace = true, optional = true } + +[features] +default = ["std"] +std = [ + "displaydoc/std", + "prost/std", + "serde/std", + "ibc-proto/std", + "tendermint/std", + "time/std", +] +serde = [ + "dep:serde", + "ibc-proto/serde", +] +schema = [ + "dep:schemars", + "ibc-proto/json-schema", + "serde", + "std" +] +borsh = [ + "dep:borsh", + "ibc-proto/borsh", +] +parity-scale-codec = [ + "dep:parity-scale-codec", + "dep:scale-info", + "ibc-proto/parity-scale-codec", +] diff --git a/crates/ibc-primitives/README.md b/crates/ibc-primitives/README.md new file mode 100644 index 000000000..3b4cc4ec8 --- /dev/null +++ b/crates/ibc-primitives/README.md @@ -0,0 +1,5 @@ +# `ibc-primitives` + +This library furnishes essential types, traits, and utilities universally utilized in the +implementation of diverse IBC modules, encompassing core functionalities, +clients, and applications. diff --git a/crates/ibc-primitives/src/lib.rs b/crates/ibc-primitives/src/lib.rs new file mode 100644 index 000000000..0e4d4bcac --- /dev/null +++ b/crates/ibc-primitives/src/lib.rs @@ -0,0 +1,32 @@ +//! Contains primitives types and traits common to various IBC components. +#![no_std] +#![forbid(unsafe_code)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] +#![cfg_attr(not(test), deny(clippy::disallowed_methods, clippy::disallowed_types))] +#![deny( + warnings, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications, + rust_2018_idioms +)] + +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +pub mod prelude; +pub mod utils; + +mod traits; +pub use traits::*; + +mod types; +pub use types::*; + +/// Re-export of common proto types from the `ibc-proto` crate. +pub mod proto { + pub use ibc_proto::google::protobuf::Any; + pub use ibc_proto::Protobuf; +} diff --git a/crates/ibc/src/prelude.rs b/crates/ibc-primitives/src/prelude.rs similarity index 100% rename from crates/ibc/src/prelude.rs rename to crates/ibc-primitives/src/prelude.rs diff --git a/crates/ibc-primitives/src/traits/mod.rs b/crates/ibc-primitives/src/traits/mod.rs new file mode 100644 index 000000000..9eccbc1ec --- /dev/null +++ b/crates/ibc-primitives/src/traits/mod.rs @@ -0,0 +1,3 @@ +mod msg; + +pub use msg::*; diff --git a/crates/ibc-primitives/src/traits/msg.rs b/crates/ibc-primitives/src/traits/msg.rs new file mode 100644 index 000000000..61eeb796a --- /dev/null +++ b/crates/ibc-primitives/src/traits/msg.rs @@ -0,0 +1,23 @@ +use ibc_proto::google::protobuf::Any; + +use crate::prelude::*; + +/// Trait to be implemented by all IBC messages +pub trait Msg: Clone { + type Raw: From + prost::Message; + + /// Unique type identifier for this message, to support encoding to/from `prost_types::Any`. + fn type_url(&self) -> String; + + fn get_sign_bytes(self) -> Vec { + let raw_msg: Self::Raw = self.into(); + prost::Message::encode_to_vec(&raw_msg) + } + + fn to_any(self) -> Any { + Any { + type_url: self.type_url(), + value: self.get_sign_bytes(), + } + } +} diff --git a/crates/ibc-primitives/src/types/mod.rs b/crates/ibc-primitives/src/types/mod.rs new file mode 100644 index 000000000..8df0d3c40 --- /dev/null +++ b/crates/ibc-primitives/src/types/mod.rs @@ -0,0 +1,5 @@ +mod signer; +mod timestamp; + +pub use signer::*; +pub use timestamp::*; diff --git a/crates/ibc/src/signer.rs b/crates/ibc-primitives/src/types/signer.rs similarity index 100% rename from crates/ibc/src/signer.rs rename to crates/ibc-primitives/src/types/signer.rs diff --git a/crates/ibc/src/core/timestamp.rs b/crates/ibc-primitives/src/types/timestamp.rs similarity index 98% rename from crates/ibc/src/core/timestamp.rs rename to crates/ibc-primitives/src/types/timestamp.rs index e7b22780d..ef54a4630 100644 --- a/crates/ibc/src/core/timestamp.rs +++ b/crates/ibc-primitives/src/types/timestamp.rs @@ -1,4 +1,4 @@ -//! Defines the representation of timestamps used in packet timeouts +//! Defines the representation of timestamps used in IBC. use core::fmt::{Display, Error as FmtError, Formatter}; use core::hash::{Hash, Hasher}; @@ -15,7 +15,7 @@ use crate::prelude::*; pub const ZERO_DURATION: Duration = Duration::from_secs(0); -/// A newtype wrapper over `Option