diff --git a/Cargo.lock b/Cargo.lock index 0a80d30..03864a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,7 +65,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -76,7 +76,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -265,7 +265,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", "syn_derive", ] @@ -410,7 +410,7 @@ checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -430,7 +430,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -461,7 +461,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1249,7 +1249,29 @@ source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=38489943c4e75206eaf dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", +] + +[[package]] +name = "ibc-middleware-module" +version = "0.1.0" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router", + "ibc-core-router-types", + "ibc-middleware-module-macros", + "ibc-primitives", + "ibc-testkit", +] + +[[package]] +name = "ibc-middleware-module-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -1636,7 +1658,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1722,9 +1744,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1749,7 +1771,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1956,7 +1978,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -1980,7 +2002,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2030,7 +2052,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2041,7 +2063,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2064,7 +2086,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2200,9 +2222,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -2218,7 +2240,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2395,7 +2417,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2534,7 +2556,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2569,7 +2591,7 @@ checksum = "f9534daa9fd3ed0bd911d462a37f172228077e7abf18c18a5f67199d959205f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2741,7 +2763,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] [[package]] @@ -2761,5 +2783,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.90", ] diff --git a/crates/module-macros/Cargo.toml b/crates/module-macros/Cargo.toml new file mode 100644 index 0000000..50535b7 --- /dev/null +++ b/crates/module-macros/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "ibc-middleware-module-macros" +version = "0.1.0" +description = "IBC module to facilitate middleware implementations - macros" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +license.workspace = true +readme.workspace = true +repository.workspace = true + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.92" +quote = "1.0.37" +syn = { version = "2.0.90", features = ["full"] } diff --git a/crates/module-macros/src/lib.rs b/crates/module-macros/src/lib.rs new file mode 100644 index 0000000..87b68b2 --- /dev/null +++ b/crates/module-macros/src/lib.rs @@ -0,0 +1,222 @@ +extern crate proc_macro; + +use quote::quote; + +#[proc_macro_derive(ModuleFromMiddleware)] +pub fn derive_module_from_middleware(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + derive_module_from_middleware_inner(input.into()).into() +} + +fn derive_module_from_middleware_inner( + input: proc_macro2::TokenStream, +) -> proc_macro2::TokenStream { + let _struct = syn::parse2::(input).expect("Expected struct definition"); + + let struct_name = &_struct.ident; + //let struct_generics = &_struct.generics; + + quote! { + impl Module for #struct_name { + #[inline(always)] + fn on_chan_open_init_validate( + &self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + version: &Version, + ) -> Result { + self.middleware_on_chan_open_init_validate( + order, + connection_hops, + port_id, + channel_id, + counterparty, + version, + ) + } + + #[inline(always)] + fn on_chan_open_init_execute( + &mut self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + version: &Version, + ) -> Result<(ModuleExtras, Version), ChannelError> { + self.middleware_on_chan_open_init_execute( + order, + connection_hops, + port_id, + channel_id, + counterparty, + version, + ) + } + + #[inline(always)] + fn on_chan_open_try_validate( + &self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + counterparty_version: &Version, + ) -> Result { + self.middleware_on_chan_open_try_validate( + order, + connection_hops, + port_id, + channel_id, + counterparty, + counterparty_version, + ) + } + + #[inline(always)] + fn on_chan_open_try_execute( + &mut self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + counterparty_version: &Version, + ) -> Result<(ModuleExtras, Version), ChannelError> { + self.middleware_on_chan_open_try_execute( + order, + connection_hops, + port_id, + channel_id, + counterparty, + counterparty_version, + ) + } + + #[inline(always)] + fn on_chan_open_ack_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + counterparty_version: &Version, + ) -> Result<(), ChannelError> { + self.middleware_on_chan_open_ack_validate(port_id, channel_id, counterparty_version) + } + + #[inline(always)] + fn on_chan_open_ack_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + counterparty_version: &Version, + ) -> Result { + self.middleware_on_chan_open_ack_execute(port_id, channel_id, counterparty_version) + } + + #[inline(always)] + fn on_chan_open_confirm_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result<(), ChannelError> { + self.middleware_on_chan_open_confirm_validate(port_id, channel_id) + } + + #[inline(always)] + fn on_chan_open_confirm_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + self.middleware_on_chan_open_confirm_execute(port_id, channel_id) + } + + #[inline(always)] + fn on_chan_close_init_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result<(), ChannelError> { + self.middleware_on_chan_close_init_validate(port_id, channel_id) + } + + #[inline(always)] + fn on_chan_close_init_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + self.middleware_on_chan_close_init_execute(port_id, channel_id) + } + + #[inline(always)] + fn on_chan_close_confirm_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result<(), ChannelError> { + self.middleware_on_chan_close_confirm_validate(port_id, channel_id) + } + + #[inline(always)] + fn on_chan_close_confirm_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + self.middleware_on_chan_close_confirm_execute(port_id, channel_id) + } + + #[inline(always)] + fn on_recv_packet_execute( + &mut self, + packet: &Packet, + relayer: &Signer, + ) -> (ModuleExtras, Option) { + self.middleware_on_recv_packet_execute(packet, relayer) + } + + #[inline(always)] + fn on_acknowledgement_packet_validate( + &self, + packet: &Packet, + acknowledgement: &Acknowledgement, + relayer: &Signer, + ) -> Result<(), PacketError> { + self.middleware_on_acknowledgement_packet_validate(packet, acknowledgement, relayer) + } + + #[inline(always)] + fn on_acknowledgement_packet_execute( + &mut self, + packet: &Packet, + acknowledgement: &Acknowledgement, + relayer: &Signer, + ) -> (ModuleExtras, Result<(), PacketError>) { + self.middleware_on_acknowledgement_packet_execute(packet, acknowledgement, relayer) + } + + #[inline(always)] + fn on_timeout_packet_validate( + &self, + packet: &Packet, + relayer: &Signer, + ) -> Result<(), PacketError> { + self.middleware_on_timeout_packet_validate(packet, relayer) + } + + #[inline(always)] + fn on_timeout_packet_execute( + &mut self, + packet: &Packet, + relayer: &Signer, + ) -> (ModuleExtras, Result<(), PacketError>) { + self.middleware_on_timeout_packet_execute(packet, relayer) + } + } + } +} diff --git a/crates/module/Cargo.toml b/crates/module/Cargo.toml new file mode 100644 index 0000000..442dac5 --- /dev/null +++ b/crates/module/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "ibc-middleware-module" +version = "0.1.0" +description = "IBC module to facilitate middleware implementations" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +license.workspace = true +readme.workspace = true +repository.workspace = true + +[dependencies] +ibc-core-channel-types.workspace = true +ibc-core-host-types.workspace = true +ibc-core-router-types.workspace = true +ibc-core-router.workspace = true +ibc-primitives.workspace = true + +[dev-dependencies] +ibc-middleware-module-macros = { path = "../module-macros" } + +ibc-testkit.workspace = true diff --git a/crates/module/src/lib.rs b/crates/module/src/lib.rs new file mode 100644 index 0000000..750f449 --- /dev/null +++ b/crates/module/src/lib.rs @@ -0,0 +1,283 @@ +//! IBC module to facilitate middleware implementations. + +#![no_std] + +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::module::Module; +use ibc_core_router_types::module::ModuleExtras; +use ibc_primitives::Signer; + +pub trait MiddlewareModule { + type NextMiddleware: Module; + + fn next_middleware(&self) -> &Self::NextMiddleware; + + fn next_middleware_mut(&mut self) -> &mut Self::NextMiddleware; + + #[inline(always)] + fn middleware_on_chan_open_init_validate( + &self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + version: &Version, + ) -> Result { + self.next_middleware().on_chan_open_init_validate( + order, + connection_hops, + port_id, + channel_id, + counterparty, + version, + ) + } + + #[inline(always)] + fn middleware_on_chan_open_init_execute( + &mut self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + version: &Version, + ) -> Result<(ModuleExtras, Version), ChannelError> { + self.next_middleware_mut().on_chan_open_init_execute( + order, + connection_hops, + port_id, + channel_id, + counterparty, + version, + ) + } + + #[inline(always)] + fn middleware_on_chan_open_try_validate( + &self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + counterparty_version: &Version, + ) -> Result { + self.next_middleware().on_chan_open_try_validate( + order, + connection_hops, + port_id, + channel_id, + counterparty, + counterparty_version, + ) + } + + #[inline(always)] + fn middleware_on_chan_open_try_execute( + &mut self, + order: Order, + connection_hops: &[ConnectionId], + port_id: &PortId, + channel_id: &ChannelId, + counterparty: &Counterparty, + counterparty_version: &Version, + ) -> Result<(ModuleExtras, Version), ChannelError> { + self.next_middleware_mut().on_chan_open_try_execute( + order, + connection_hops, + port_id, + channel_id, + counterparty, + counterparty_version, + ) + } + + #[inline(always)] + fn middleware_on_chan_open_ack_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + counterparty_version: &Version, + ) -> Result<(), ChannelError> { + self.next_middleware() + .on_chan_open_ack_validate(port_id, channel_id, counterparty_version) + } + + #[inline(always)] + fn middleware_on_chan_open_ack_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + counterparty_version: &Version, + ) -> Result { + self.next_middleware_mut().on_chan_open_ack_execute( + port_id, + channel_id, + counterparty_version, + ) + } + + #[inline(always)] + fn middleware_on_chan_open_confirm_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result<(), ChannelError> { + self.next_middleware() + .on_chan_open_confirm_validate(port_id, channel_id) + } + + #[inline(always)] + fn middleware_on_chan_open_confirm_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + self.next_middleware_mut() + .on_chan_open_confirm_execute(port_id, channel_id) + } + + #[inline(always)] + fn middleware_on_chan_close_init_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result<(), ChannelError> { + self.next_middleware() + .on_chan_close_init_validate(port_id, channel_id) + } + + #[inline(always)] + fn middleware_on_chan_close_init_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + self.next_middleware_mut() + .on_chan_close_init_execute(port_id, channel_id) + } + + #[inline(always)] + fn middleware_on_chan_close_confirm_validate( + &self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result<(), ChannelError> { + self.next_middleware() + .on_chan_close_confirm_validate(port_id, channel_id) + } + + #[inline(always)] + fn middleware_on_chan_close_confirm_execute( + &mut self, + port_id: &PortId, + channel_id: &ChannelId, + ) -> Result { + self.next_middleware_mut() + .on_chan_close_confirm_execute(port_id, channel_id) + } + + #[inline(always)] + fn middleware_on_recv_packet_execute( + &mut self, + packet: &Packet, + relayer: &Signer, + ) -> (ModuleExtras, Option) { + self.next_middleware_mut() + .on_recv_packet_execute(packet, relayer) + } + + #[inline(always)] + fn middleware_on_acknowledgement_packet_validate( + &self, + packet: &Packet, + acknowledgement: &Acknowledgement, + relayer: &Signer, + ) -> Result<(), PacketError> { + self.next_middleware() + .on_acknowledgement_packet_validate(packet, acknowledgement, relayer) + } + + #[inline(always)] + fn middleware_on_acknowledgement_packet_execute( + &mut self, + packet: &Packet, + acknowledgement: &Acknowledgement, + relayer: &Signer, + ) -> (ModuleExtras, Result<(), PacketError>) { + self.next_middleware_mut() + .on_acknowledgement_packet_execute(packet, acknowledgement, relayer) + } + + #[inline(always)] + fn middleware_on_timeout_packet_validate( + &self, + packet: &Packet, + relayer: &Signer, + ) -> Result<(), PacketError> { + self.next_middleware() + .on_timeout_packet_validate(packet, relayer) + } + + #[inline(always)] + fn middleware_on_timeout_packet_execute( + &mut self, + packet: &Packet, + relayer: &Signer, + ) -> (ModuleExtras, Result<(), PacketError>) { + self.next_middleware_mut() + .on_timeout_packet_execute(packet, relayer) + } +} + +#[cfg(test)] +mod tests { + use ibc_middleware_module_macros::ModuleFromMiddleware; + use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; + + use super::*; + + #[derive(Debug, ModuleFromMiddleware)] + struct DummyMiddleware(DummyTransferModule); + + impl MiddlewareModule for DummyMiddleware { + type NextMiddleware = DummyTransferModule; + + fn next_middleware(&self) -> &Self::NextMiddleware { + &self.0 + } + + fn next_middleware_mut(&mut self) -> &mut Self::NextMiddleware { + &mut self.0 + } + + fn middleware_on_chan_close_init_validate( + &self, + _: &PortId, + _: &ChannelId, + ) -> Result<(), ChannelError> { + panic!("panicked from middleware") + } + } + + fn assert_module_impl() {} + + #[test] + fn dummy_middleware_is_module() { + assert_module_impl::(); + } + + #[test] + #[should_panic = "panicked from middleware"] + fn dummy_middleware_overrides_method() { + _ = DummyMiddleware(DummyTransferModule) + .on_chan_close_init_validate(&PortId::transfer(), &ChannelId::new(0)); + } +}