diff --git a/ibc-apps/ics20-transfer/src/context.rs b/ibc-apps/ics20-transfer/src/context.rs index 8c22ad386b..93aa6cc92d 100644 --- a/ibc-apps/ics20-transfer/src/context.rs +++ b/ibc-apps/ics20-transfer/src/context.rs @@ -5,9 +5,10 @@ use ibc_app_transfer_types::{Memo, PrefixedCoin, PrefixedDenom}; use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; use ibc_core::primitives::Signer; +use ibc_core::router::module::Module; /// Methods required in token transfer validation, to be implemented by the host -pub trait TokenTransferValidationContext { +pub trait TokenTransferValidationContext: Module { type AccountId: TryFrom; /// get_port returns the portID for the transfer module. diff --git a/ibc-apps/ics20-transfer/src/handler/send_transfer.rs b/ibc-apps/ics20-transfer/src/handler/send_transfer.rs index 439e5604c6..c73eb852c5 100644 --- a/ibc-apps/ics20-transfer/src/handler/send_transfer.rs +++ b/ibc-apps/ics20-transfer/src/handler/send_transfer.rs @@ -95,7 +95,7 @@ where } }; - send_packet_validate(send_packet_ctx_a, &packet)?; + send_packet_validate(send_packet_ctx_a, token_ctx_a, &packet)?; Ok(()) } @@ -170,7 +170,7 @@ where } }; - send_packet_execute(send_packet_ctx_a, packet)?; + send_packet_execute(send_packet_ctx_a, token_ctx_a, packet)?; { send_packet_ctx_a.log_message(format!( diff --git a/ibc-apps/ics721-nft-transfer/src/context.rs b/ibc-apps/ics721-nft-transfer/src/context.rs index ede6ee8981..5977fcbf8b 100644 --- a/ibc-apps/ics721-nft-transfer/src/context.rs +++ b/ibc-apps/ics721-nft-transfer/src/context.rs @@ -3,6 +3,7 @@ use ibc_core::host::types::identifiers::{ChannelId, PortId}; use ibc_core::primitives::prelude::*; use ibc_core::primitives::Signer; +use ibc_core::router::module::Module; use crate::types::error::NftTransferError; use crate::types::{ @@ -35,7 +36,7 @@ pub trait NftClassContext { } /// Read-only methods required in NFT transfer validation context. -pub trait NftTransferValidationContext { +pub trait NftTransferValidationContext: Module { type AccountId: TryFrom + PartialEq; type Nft: NftContext; type NftClass: NftClassContext; diff --git a/ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs b/ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs index 4cf1a759cd..320d0b723b 100644 --- a/ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs +++ b/ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs @@ -127,7 +127,7 @@ where } }; - send_packet_validate(send_packet_ctx_a, &packet)?; + send_packet_validate(send_packet_ctx_a, transfer_ctx, &packet)?; Ok(()) } @@ -229,7 +229,7 @@ where } }; - send_packet_execute(send_packet_ctx_a, packet)?; + send_packet_execute(send_packet_ctx_a, transfer_ctx, packet)?; { send_packet_ctx_a.log_message(format!( diff --git a/ibc-core/ics04-channel/src/context.rs b/ibc-core/ics04-channel/src/context.rs index 1fba1de8fd..d39e9cd085 100644 --- a/ibc-core/ics04-channel/src/context.rs +++ b/ibc-core/ics04-channel/src/context.rs @@ -7,8 +7,9 @@ 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::{ConnectionId, Sequence}; -use ibc_core_host::types::path::{ChannelEndPath, CommitmentPath, SeqSendPath}; +use ibc_core_host::types::path::{ChannelEndPath, CommitmentPath, PortPath, SeqSendPath}; use ibc_core_host::{ExecutionContext, ValidationContext}; +use ibc_core_router::module::Module; use ibc_primitives::prelude::*; /// Methods required in send packet validation, to be implemented by the host @@ -26,6 +27,12 @@ pub trait SendPacketValidationContext { fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath) -> Result; + + fn has_port_capability( + &self, + port_path: &PortPath, + module: &impl Module, + ) -> Result<(), ContextError>; } impl SendPacketValidationContext for T @@ -52,6 +59,14 @@ where ) -> Result { self.get_next_sequence_send(seq_send_path) } + + fn has_port_capability( + &self, + port_path: &PortPath, + module: &impl Module, + ) -> Result<(), ContextError> { + self.has_port_capability(port_path, module.identifier().to_string().into()) + } } /// Methods required in send packet execution, to be implemented by the host diff --git a/ibc-core/ics04-channel/src/handler/chan_open_init.rs b/ibc-core/ics04-channel/src/handler/chan_open_init.rs index 58a161d0bd..9ac96a2d0e 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_init.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_init.rs @@ -7,7 +7,7 @@ use ibc_core_client::context::prelude::*; 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::types::path::{ChannelEndPath, PortPath, SeqAckPath, SeqRecvPath, SeqSendPath}; use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_core_router::module::Module; use ibc_primitives::prelude::*; @@ -32,6 +32,13 @@ where &msg.version_proposal, )?; + let port_path = PortPath(msg.port_id_on_a); + + // either the capability is available or the module has the capability. + ctx_a.available_port_capability(&port_path).or_else(|_| { + ctx_a.has_port_capability(&port_path, module.identifier().to_string().into()) + })?; + Ok(()) } @@ -104,6 +111,11 @@ where } } + ctx_a.claim_port_capability( + &PortPath(msg.port_id_on_a), + module.identifier().to_string().into(), + )?; + Ok(()) } diff --git a/ibc-core/ics04-channel/src/handler/chan_open_try.rs b/ibc-core/ics04-channel/src/handler/chan_open_try.rs index 08c82deac7..6413c1a948 100644 --- a/ibc-core/ics04-channel/src/handler/chan_open_try.rs +++ b/ibc-core/ics04-channel/src/handler/chan_open_try.rs @@ -10,7 +10,7 @@ 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, + ChannelEndPath, ClientConsensusStatePath, Path, PortPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; use ibc_core_host::{ExecutionContext, ValidationContext}; use ibc_core_router::module::Module; @@ -38,6 +38,13 @@ where &msg.version_supported_on_a, )?; + let port_path = PortPath(msg.port_id_on_b); + + // either the capability is available or the module has the capability. + ctx_b.available_port_capability(&port_path).or_else(|_| { + ctx_b.has_port_capability(&port_path, module.identifier().to_string().into()) + })?; + Ok(()) } @@ -112,6 +119,11 @@ where } } + ctx_b.claim_port_capability( + &PortPath(msg.port_id_on_b), + module.identifier().to_string().into(), + )?; + Ok(()) } diff --git a/ibc-core/ics04-channel/src/handler/send_packet.rs b/ibc-core/ics04-channel/src/handler/send_packet.rs index 895ad9457e..609ceb12c6 100644 --- a/ibc-core/ics04-channel/src/handler/send_packet.rs +++ b/ibc-core/ics04-channel/src/handler/send_packet.rs @@ -7,8 +7,9 @@ use ibc_core_client::context::prelude::*; 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, + ChannelEndPath, ClientConsensusStatePath, CommitmentPath, PortPath, SeqSendPath, }; +use ibc_core_router::module::Module; use ibc_primitives::prelude::*; use ibc_primitives::Expiry; @@ -19,17 +20,21 @@ use crate::context::{SendPacketExecutionContext, SendPacketValidationContext}; /// Equivalent to calling [`send_packet_validate`], followed by [`send_packet_execute`] pub fn send_packet( ctx_a: &mut impl SendPacketExecutionContext, + module: &impl Module, packet: Packet, ) -> Result<(), ContextError> { - send_packet_validate(ctx_a, &packet)?; - send_packet_execute(ctx_a, packet) + send_packet_validate(ctx_a, module, &packet)?; + send_packet_execute(ctx_a, module, packet) } /// Validate that sending the given packet would succeed. pub fn send_packet_validate( ctx_a: &impl SendPacketValidationContext, + module: &impl Module, packet: &Packet, ) -> Result<(), ContextError> { + ctx_a.has_port_capability(&PortPath(packet.port_id_on_a.clone()), module)?; + if !packet.timeout_height_on_b.is_set() && !packet.timeout_timestamp_on_b.is_set() { return Err(ContextError::PacketError(PacketError::MissingTimeout)); } @@ -104,8 +109,11 @@ pub fn send_packet_validate( /// A prior call to [`send_packet_validate`] MUST have succeeded. pub fn send_packet_execute( ctx_a: &mut impl SendPacketExecutionContext, + module: &impl Module, packet: Packet, ) -> Result<(), ContextError> { + ctx_a.has_port_capability(&PortPath(packet.port_id_on_a.clone()), module)?; + { let seq_send_path_on_a = SeqSendPath::new(&packet.port_id_on_a, &packet.chan_id_on_a); let next_seq_send_on_a = ctx_a.get_next_sequence_send(&seq_send_path_on_a)?; diff --git a/ibc-core/ics04-channel/types/src/error.rs b/ibc-core/ics04-channel/types/src/error.rs index 2b7b760efc..dc8952e08e 100644 --- a/ibc-core/ics04-channel/types/src/error.rs +++ b/ibc-core/ics04-channel/types/src/error.rs @@ -5,6 +5,7 @@ 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_core_host_types::path::PortPath; use ibc_primitives::prelude::*; use ibc_primitives::{ParseTimestampError, Timestamp}; @@ -71,6 +72,10 @@ pub enum ChannelError { InvalidIdentifier(IdentifierError), /// channel counter overflow error CounterOverflow, + /// Capability for `{0}` does not exist + CapabilityNotFound(PortPath), + /// Capability for `{0}` already exists + CapabilityAlreadyExists(PortPath), /// other error: `{description}` Other { description: String }, } diff --git a/ibc-core/ics24-host/src/context.rs b/ibc-core/ics24-host/src/context.rs index da858968d6..b6513a09df 100644 --- a/ibc-core/ics24-host/src/context.rs +++ b/ibc-core/ics24-host/src/context.rs @@ -10,10 +10,10 @@ use ibc_core_connection_types::version::{pick_version, Version as ConnectionVers 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::{ConnectionId, Sequence}; +use ibc_core_host_types::identifiers::{CapabilityKey, ConnectionId, Sequence}; use ibc_core_host_types::path::{ - AckPath, ChannelEndPath, ClientConnectionPath, CommitmentPath, ConnectionPath, ReceiptPath, - SeqAckPath, SeqRecvPath, SeqSendPath, + AckPath, ChannelEndPath, ClientConnectionPath, CommitmentPath, ConnectionPath, PortPath, + ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; use ibc_primitives::prelude::*; use ibc_primitives::{Signer, Timestamp}; @@ -126,6 +126,14 @@ pub trait ValidationContext { /// `ExecutionContext::increase_channel_counter`. fn channel_counter(&self) -> Result; + fn available_port_capability(&self, port_path: &PortPath) -> Result<(), ContextError>; + + fn has_port_capability( + &self, + port_path: &PortPath, + capability: CapabilityKey, + ) -> Result<(), ContextError>; + /// Returns the maximum expected time per block fn max_expected_time_per_block(&self) -> Duration; @@ -233,6 +241,12 @@ pub trait ExecutionContext: ValidationContext { /// Increases the counter, that keeps track of how many channels have been created. fn increase_channel_counter(&mut self) -> Result<(), ContextError>; + fn claim_port_capability( + &mut self, + port_path: &PortPath, + capability: CapabilityKey, + ) -> Result<(), ContextError>; + /// Emit the given IBC event fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), ContextError>; diff --git a/ibc-core/ics24-host/types/src/identifiers/capability_key.rs b/ibc-core/ics24-host/types/src/identifiers/capability_key.rs new file mode 100644 index 0000000000..d26eaed6b8 --- /dev/null +++ b/ibc-core/ics24-host/types/src/identifiers/capability_key.rs @@ -0,0 +1,41 @@ +use core::any::TypeId; +use core::fmt::Write; + +use ibc_primitives::prelude::*; + +#[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, Hash, PartialOrd, Ord)] +pub struct CapabilityKey(Vec); + +impl From for CapabilityKey { + fn from(type_id: TypeId) -> Self { + let mut buf = String::new(); + write!(buf, "{:?}", type_id).unwrap(); + buf.into() + } +} + +impl From for CapabilityKey { + fn from(value: String) -> Self { + Self(value.as_bytes().to_vec()) + } +} + +impl AsRef<[u8]> for CapabilityKey { + fn as_ref(&self) -> &[u8] { + self.0.as_slice() + } +} diff --git a/ibc-core/ics24-host/types/src/identifiers/mod.rs b/ibc-core/ics24-host/types/src/identifiers/mod.rs index 9ae79f6735..6acd8aa3fc 100644 --- a/ibc-core/ics24-host/types/src/identifiers/mod.rs +++ b/ibc-core/ics24-host/types/src/identifiers/mod.rs @@ -1,5 +1,6 @@ //! Defines identifier types +mod capability_key; mod chain_id; mod channel_id; mod client_id; @@ -8,6 +9,7 @@ mod connection_id; mod port_id; mod sequence; +pub use capability_key::CapabilityKey; pub use chain_id::ChainId; pub use channel_id::ChannelId; pub use client_id::ClientId; diff --git a/ibc-core/ics26-routing/src/module.rs b/ibc-core/ics26-routing/src/module.rs index 26b2967134..b046a5a3be 100644 --- a/ibc-core/ics26-routing/src/module.rs +++ b/ibc-core/ics26-routing/src/module.rs @@ -7,11 +7,13 @@ 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_core_router_types::module::{ModuleExtras, ModuleId}; use ibc_primitives::prelude::*; use ibc_primitives::Signer; -pub trait Module: Debug { +pub trait Module: 'static + Debug { + fn identifier(&self) -> ModuleId; + fn on_chan_open_init_validate( &self, order: Order, diff --git a/ibc-testkit/src/context.rs b/ibc-testkit/src/context.rs index 4380de474d..4c1984ddbc 100644 --- a/ibc-testkit/src/context.rs +++ b/ibc-testkit/src/context.rs @@ -16,9 +16,10 @@ use ibc::core::handler::types::msgs::MsgEnvelope; use ibc::core::host::types::identifiers::{ChannelId, ClientId, ConnectionId, PortId, Sequence}; use ibc::core::host::types::path::{ ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ConnectionPath, - SeqAckPath, SeqRecvPath, SeqSendPath, + PortPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; use ibc::core::host::{ExecutionContext, ValidationContext}; +use ibc::core::router::module::Module; use ibc::primitives::prelude::*; use ibc::primitives::Timestamp; @@ -386,6 +387,7 @@ where /// This does not bootstrap any corresponding IBC connection or light client. pub fn with_channel( mut self, + module: &impl Module, port_id: PortId, chan_id: ChannelId, channel_end: ChannelEnd, @@ -394,6 +396,11 @@ where self.ibc_store .store_channel(&channel_end_path, channel_end) .expect("error writing to store"); + + self.ibc_store + .claim_port_capability(&PortPath(port_id), module.identifier().to_string().into()) + .expect("error writing to store"); + self } diff --git a/ibc-testkit/src/testapp/ibc/applications/nft_transfer/module.rs b/ibc-testkit/src/testapp/ibc/applications/nft_transfer/module.rs index 06652a1dd6..81f8e23cfe 100644 --- a/ibc-testkit/src/testapp/ibc/applications/nft_transfer/module.rs +++ b/ibc-testkit/src/testapp/ibc/applications/nft_transfer/module.rs @@ -7,11 +7,15 @@ use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Signer; use ibc::core::router::module::Module; -use ibc::core::router::types::module::ModuleExtras; +use ibc::core::router::types::module::{ModuleExtras, ModuleId}; use super::types::DummyNftTransferModule; impl Module for DummyNftTransferModule { + fn identifier(&self) -> ModuleId { + ModuleId::new("nft-transfer".to_string()) + } + fn on_chan_open_init_validate( &self, _order: Order, diff --git a/ibc-testkit/src/testapp/ibc/applications/transfer/module.rs b/ibc-testkit/src/testapp/ibc/applications/transfer/module.rs index 2246c893bc..c1de202120 100644 --- a/ibc-testkit/src/testapp/ibc/applications/transfer/module.rs +++ b/ibc-testkit/src/testapp/ibc/applications/transfer/module.rs @@ -7,11 +7,15 @@ use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Signer; use ibc::core::router::module::Module; -use ibc::core::router::types::module::ModuleExtras; +use ibc::core::router::types::module::{ModuleExtras, ModuleId}; use super::types::DummyTransferModule; impl Module for DummyTransferModule { + fn identifier(&self) -> ModuleId { + ModuleId::new("transfer".to_string()) + } + fn on_chan_open_init_validate( &self, _order: Order, diff --git a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs index d650cccd12..af7c26b5a5 100644 --- a/ibc-testkit/src/testapp/ibc/core/core_ctx.rs +++ b/ibc-testkit/src/testapp/ibc/core/core_ctx.rs @@ -18,11 +18,11 @@ use ibc::core::connection::types::error::ConnectionError; use ibc::core::connection::types::{ConnectionEnd, IdentifiedConnectionEnd}; 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::identifiers::{CapabilityKey, ClientId, ConnectionId, Sequence}; use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, CommitmentPath, ConnectionPath, - NextChannelSequencePath, NextClientSequencePath, NextConnectionSequencePath, Path, ReceiptPath, - SeqAckPath, SeqRecvPath, SeqSendPath, + NextChannelSequencePath, NextClientSequencePath, NextConnectionSequencePath, Path, PortPath, + ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; use ibc::core::host::{ClientStateRef, ConsensusStateRef, ExecutionContext, ValidationContext}; use ibc::core::primitives::prelude::*; @@ -233,10 +233,7 @@ where ) -> Result { Ok(self .packet_ack_store - .get( - StoreHeight::Pending, - &AckPath::new(&ack_path.port_id, &ack_path.channel_id, ack_path.sequence), - ) + .get(StoreHeight::Pending, ack_path) .ok_or(PacketError::PacketAcknowledgementNotFound { sequence: ack_path.sequence, })?) @@ -266,6 +263,30 @@ where fn get_client_validation_context(&self) -> &Self::V { self } + + fn available_port_capability(&self, port_path: &PortPath) -> Result<(), ContextError> { + self.port_capabilities + .get(StoreHeight::Pending, port_path) + .is_none() + .then_some(()) + .ok_or_else(|| { + ContextError::ChannelError(ChannelError::CapabilityAlreadyExists(port_path.clone())) + }) + } + + fn has_port_capability( + &self, + port_path: &PortPath, + capability: CapabilityKey, + ) -> Result<(), ContextError> { + self.port_capabilities + .get(StoreHeight::Pending, port_path) + .filter(|stored_capability| stored_capability == &capability) + .ok_or_else(|| { + ContextError::ChannelError(ChannelError::CapabilityNotFound(port_path.clone())) + }) + .map(|_| ()) + } } /// Trait to provide proofs in gRPC service blanket implementations. @@ -776,6 +797,20 @@ where Ok(()) } + fn claim_port_capability( + &mut self, + port_path: &PortPath, + capability: CapabilityKey, + ) -> Result<(), ContextError> { + self.port_capabilities + .set(port_path.clone(), capability) + .map_err(|_| ChannelError::Other { + description: "Port capability claim store error".to_string(), + })?; + + Ok(()) + } + fn store_next_sequence_send( &mut self, seq_send_path: &SeqSendPath, diff --git a/ibc-testkit/src/testapp/ibc/core/types.rs b/ibc-testkit/src/testapp/ibc/core/types.rs index a1296cf6a3..12742c0fb3 100644 --- a/ibc-testkit/src/testapp/ibc/core/types.rs +++ b/ibc-testkit/src/testapp/ibc/core/types.rs @@ -12,12 +12,12 @@ use ibc::core::client::context::client_state::ClientStateValidation; use ibc::core::client::types::Height; use ibc::core::connection::types::ConnectionEnd; use ibc::core::handler::types::events::IbcEvent; -use ibc::core::host::types::identifiers::{ConnectionId, Sequence}; +use ibc::core::host::types::identifiers::{CapabilityKey, ConnectionId, Sequence}; use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, ClientUpdateHeightPath, ClientUpdateTimePath, CommitmentPath, ConnectionPath, - NextChannelSequencePath, NextClientSequencePath, NextConnectionSequencePath, ReceiptPath, - SeqAckPath, SeqRecvPath, SeqSendPath, + NextChannelSequencePath, NextClientSequencePath, NextConnectionSequencePath, PortPath, + ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; use ibc::core::primitives::prelude::*; use ibc::core::primitives::Timestamp; @@ -89,6 +89,8 @@ where pub host_consensus_states: Arc>>, /// Map of older ibc commitment proofs pub ibc_commiment_proofs: Arc>>, + /// Map of port capabilities + pub port_capabilities: JsonStore, PortPath, CapabilityKey>, /// IBC Events pub events: Arc>>, /// message logs @@ -138,6 +140,7 @@ where packet_commitment_store: TypedStore::new(shared_store.clone()), packet_receipt_store: TypedStore::new(shared_store.clone()), packet_ack_store: TypedStore::new(shared_store.clone()), + port_capabilities: TypedStore::new(shared_store.clone()), events: Arc::new(Mutex::new(Vec::new())), logs: Arc::new(Mutex::new(Vec::new())), store: shared_store, @@ -224,6 +227,10 @@ mod tests { } impl Module for FooModule { + fn identifier(&self) -> ModuleId { + ModuleId::new("foomodule".to_string()) + } + fn on_chan_open_init_validate( &self, _order: Order, @@ -324,6 +331,10 @@ mod tests { struct BarModule; impl Module for BarModule { + fn identifier(&self) -> ModuleId { + ModuleId::new("barmodule".to_string()) + } + fn on_chan_open_init_validate( &self, _order: Order, diff --git a/tests-integration/tests/core/ics04_channel/acknowledgement.rs b/tests-integration/tests/core/ics04_channel/acknowledgement.rs index 1afd22fe17..6228241ae1 100644 --- a/tests-integration/tests/core/ics04_channel/acknowledgement.rs +++ b/tests-integration/tests/core/ics04_channel/acknowledgement.rs @@ -16,6 +16,7 @@ use ibc::core::primitives::*; use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_acknowledgement; use ibc_testkit::hosts::MockHost; +use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; use ibc_testkit::testapp::ibc::core::router::MockRouter; use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; @@ -128,6 +129,7 @@ fn ack_success_no_packet_commitment(fixture: Fixture) { LightClientState::::with_latest_height(client_height), ) .with_channel( + &DummyTransferModule, PortId::transfer(), ChannelId::zero(), chan_end_on_a_unordered, @@ -162,6 +164,7 @@ fn ack_success_happy_path(fixture: Fixture) { LightClientState::::with_latest_height(client_height), ) .with_channel( + &DummyTransferModule, PortId::transfer(), ChannelId::zero(), chan_end_on_a_unordered, @@ -197,6 +200,7 @@ fn ack_unordered_chan_execute(fixture: Fixture) { } = fixture; let mut ctx = ctx .with_channel( + &DummyTransferModule, PortId::transfer(), ChannelId::zero(), chan_end_on_a_unordered, @@ -237,7 +241,12 @@ fn ack_ordered_chan_execute(fixture: Fixture) { .. } = fixture; let mut ctx = ctx - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a_ordered) + .with_channel( + &DummyTransferModule, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a_ordered, + ) .with_connection(ConnectionId::zero(), conn_end_on_a) .with_packet_commitment( msg.packet.port_id_on_a.clone(), diff --git a/tests-integration/tests/core/ics04_channel/chan_close_confirm.rs b/tests-integration/tests/core/ics04_channel/chan_close_confirm.rs index f3491f9ca6..571f33a64a 100644 --- a/tests-integration/tests/core/ics04_channel/chan_close_confirm.rs +++ b/tests-integration/tests/core/ics04_channel/chan_close_confirm.rs @@ -15,6 +15,7 @@ use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_close_confirm; use ibc_testkit::fixtures::core::connection::dummy_raw_counterparty_conn; use ibc_testkit::hosts::MockHost; +use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; 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::LightClientState; @@ -61,6 +62,7 @@ fn test_chan_close_confirm_validate() { ) .with_connection(conn_id, conn_end) .with_channel( + &DummyTransferModule, msg_chan_close_confirm.port_id_on_b.clone(), msg_chan_close_confirm.chan_id_on_b, chan_end, @@ -118,6 +120,7 @@ fn test_chan_close_confirm_execute() { ) .with_connection(conn_id, conn_end) .with_channel( + &DummyTransferModule, msg_chan_close_confirm.port_id_on_b.clone(), msg_chan_close_confirm.chan_id_on_b, chan_end, diff --git a/tests-integration/tests/core/ics04_channel/chan_close_init.rs b/tests-integration/tests/core/ics04_channel/chan_close_init.rs index 63fd30d656..6cc0a3052d 100644 --- a/tests-integration/tests/core/ics04_channel/chan_close_init.rs +++ b/tests-integration/tests/core/ics04_channel/chan_close_init.rs @@ -15,6 +15,7 @@ use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_close_init; use ibc_testkit::fixtures::core::connection::dummy_raw_counterparty_conn; use ibc_testkit::hosts::MockHost; +use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; 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::LightClientState; @@ -61,6 +62,7 @@ fn test_chan_close_init_validate() { ) .with_connection(conn_id, conn_end) .with_channel( + &DummyTransferModule, msg_chan_close_init.port_id_on_a.clone(), msg_chan_close_init.chan_id_on_a, chan_end, @@ -119,6 +121,7 @@ fn test_chan_close_init_execute() { ) .with_connection(conn_id, conn_end) .with_channel( + &DummyTransferModule, msg_chan_close_init.port_id_on_a.clone(), msg_chan_close_init.chan_id_on_a, chan_end, diff --git a/tests-integration/tests/core/ics04_channel/chan_open_ack.rs b/tests-integration/tests/core/ics04_channel/chan_open_ack.rs index e4250dd83a..1be144c298 100644 --- a/tests-integration/tests/core/ics04_channel/chan_open_ack.rs +++ b/tests-integration/tests/core/ics04_channel/chan_open_ack.rs @@ -16,6 +16,7 @@ use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_open_ack; use ibc_testkit::fixtures::core::connection::dummy_raw_counterparty_conn; use ibc_testkit::hosts::MockHost; +use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; 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::LightClientState; @@ -98,6 +99,7 @@ fn chan_open_ack_happy_path(fixture: Fixture) { ) .with_connection(conn_id_on_a, conn_end_on_a) .with_channel( + &DummyTransferModule, msg.port_id_on_a.clone(), msg.chan_id_on_a.clone(), chan_end_on_a, @@ -131,6 +133,7 @@ fn chan_open_ack_execute_happy_path(fixture: Fixture) { ) .with_connection(conn_id_on_a, conn_end_on_a) .with_channel( + &DummyTransferModule, msg.port_id_on_a.clone(), msg.chan_id_on_a.clone(), chan_end_on_a, @@ -170,6 +173,7 @@ fn chan_open_ack_fail_no_connection(fixture: Fixture) { LightClientState::::with_latest_height(Height::new(0, proof_height).unwrap()), ) .with_channel( + &DummyTransferModule, msg.port_id_on_a.clone(), msg.chan_id_on_a.clone(), chan_end_on_a, @@ -242,6 +246,7 @@ fn chan_open_ack_fail_channel_wrong_state(fixture: Fixture) { ) .with_connection(conn_id_on_a, conn_end_on_a) .with_channel( + &DummyTransferModule, msg.port_id_on_a.clone(), msg.chan_id_on_a.clone(), wrong_chan_end, diff --git a/tests-integration/tests/core/ics04_channel/chan_open_confirm.rs b/tests-integration/tests/core/ics04_channel/chan_open_confirm.rs index 0b399aa400..09efbd991d 100644 --- a/tests-integration/tests/core/ics04_channel/chan_open_confirm.rs +++ b/tests-integration/tests/core/ics04_channel/chan_open_confirm.rs @@ -15,6 +15,7 @@ use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_chan_open_confirm; use ibc_testkit::fixtures::core::connection::dummy_raw_counterparty_conn; use ibc_testkit::hosts::MockHost; +use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; 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::LightClientState; @@ -94,7 +95,12 @@ fn chan_open_confirm_validate_happy_path(fixture: Fixture) { LightClientState::::with_latest_height(Height::new(0, proof_height).unwrap()), ) .with_connection(conn_id_on_b, conn_end_on_b) - .with_channel(msg.port_id_on_b.clone(), ChannelId::zero(), chan_end_on_b); + .with_channel( + &DummyTransferModule, + msg.port_id_on_b.clone(), + ChannelId::zero(), + chan_end_on_b, + ); let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); @@ -123,7 +129,12 @@ fn chan_open_confirm_execute_happy_path(fixture: Fixture) { LightClientState::::with_latest_height(Height::new(0, proof_height).unwrap()), ) .with_connection(conn_id_on_b, conn_end_on_b) - .with_channel(msg.port_id_on_b.clone(), ChannelId::zero(), chan_end_on_b); + .with_channel( + &DummyTransferModule, + msg.port_id_on_b.clone(), + ChannelId::zero(), + chan_end_on_b, + ); let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); @@ -199,7 +210,12 @@ fn chan_open_confirm_fail_channel_wrong_state(fixture: Fixture) { LightClientState::::with_latest_height(Height::new(0, proof_height).unwrap()), ) .with_connection(conn_id_on_b, conn_end_on_b) - .with_channel(msg.port_id_on_b.clone(), ChannelId::zero(), wrong_chan_end); + .with_channel( + &DummyTransferModule, + msg.port_id_on_b.clone(), + ChannelId::zero(), + wrong_chan_end, + ); let msg_envelope = MsgEnvelope::from(ChannelMsg::from(msg)); diff --git a/tests-integration/tests/core/ics04_channel/recv_packet.rs b/tests-integration/tests/core/ics04_channel/recv_packet.rs index df946f1e35..6c3e041f19 100644 --- a/tests-integration/tests/core/ics04_channel/recv_packet.rs +++ b/tests-integration/tests/core/ics04_channel/recv_packet.rs @@ -17,6 +17,7 @@ use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::{dummy_msg_recv_packet, dummy_raw_msg_recv_packet}; use ibc_testkit::fixtures::core::signer::dummy_account_id; use ibc_testkit::hosts::MockHost; +use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; use ibc_testkit::testapp::ibc::core::router::MockRouter; use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; @@ -124,6 +125,7 @@ fn recv_packet_validate_happy_path(fixture: Fixture) { ) .with_connection(ConnectionId::zero(), conn_end_on_b) .with_channel( + &DummyTransferModule, packet.port_id_on_b.clone(), packet.chan_id_on_b.clone(), chan_end_on_b, @@ -190,7 +192,12 @@ fn recv_packet_timeout_expired(fixture: Fixture) { LightClientState::::with_latest_height(client_height), ) .with_connection(ConnectionId::zero(), conn_end_on_b) - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_b) + .with_channel( + &DummyTransferModule, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_b, + ) .with_send_sequence(PortId::transfer(), ChannelId::zero(), 1.into()) .advance_block_up_to_height(host_height); @@ -219,7 +226,12 @@ fn recv_packet_execute_happy_path(fixture: Fixture) { LightClientState::::with_latest_height(client_height), ) .with_connection(ConnectionId::zero(), conn_end_on_b) - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_b); + .with_channel( + &DummyTransferModule, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_b, + ); let msg_env = MsgEnvelope::from(PacketMsg::from(msg)); diff --git a/tests-integration/tests/core/ics04_channel/send_packet.rs b/tests-integration/tests/core/ics04_channel/send_packet.rs index 3a2bace448..dec5343f76 100644 --- a/tests-integration/tests/core/ics04_channel/send_packet.rs +++ b/tests-integration/tests/core/ics04_channel/send_packet.rs @@ -18,6 +18,7 @@ use ibc::core::primitives::*; use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_packet; use ibc_testkit::hosts::MockHost; +use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; use ibc_testkit::testapp::ibc::core::types::LightClientState; use test_log::test; @@ -92,6 +93,8 @@ fn send_packet_processing() { packet }; + let dummy_transfer_module = DummyTransferModule; + let tests: Vec = vec![ Test { name: "Processing fails because no channel exists in the context".to_string(), @@ -107,7 +110,12 @@ fn send_packet_processing() { LightClientState::::with_latest_height(client_height), ) .with_connection(ConnectionId::zero(), conn_end_on_a.clone()) - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a.clone()) + .with_channel( + &dummy_transfer_module, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a.clone(), + ) .with_send_sequence(PortId::transfer(), ChannelId::zero(), 1.into()), packet, want_pass: true, @@ -120,7 +128,12 @@ fn send_packet_processing() { LightClientState::::with_latest_height(client_height), ) .with_connection(ConnectionId::zero(), conn_end_on_a.clone()) - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a.clone()) + .with_channel( + &dummy_transfer_module, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a.clone(), + ) .with_send_sequence(PortId::transfer(), ChannelId::zero(), 1.into()), packet: packet_timeout_equal_client_height, want_pass: true, @@ -133,7 +146,12 @@ fn send_packet_processing() { LightClientState::::with_latest_height(client_height), ) .with_connection(ConnectionId::zero(), conn_end_on_a.clone()) - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a.clone()) + .with_channel( + &dummy_transfer_module, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a.clone(), + ) .with_send_sequence(PortId::transfer(), ChannelId::zero(), 1.into()), packet: packet_timeout_one_before_client_height, want_pass: false, @@ -146,7 +164,12 @@ fn send_packet_processing() { LightClientState::::with_latest_height(client_height), ) .with_connection(ConnectionId::zero(), conn_end_on_a.clone()) - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a.clone()) + .with_channel( + &dummy_transfer_module, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a.clone(), + ) .with_send_sequence(PortId::transfer(), ChannelId::zero(), 1.into()), packet: packet_with_no_timeout, want_pass: false, @@ -159,7 +182,12 @@ fn send_packet_processing() { LightClientState::::with_latest_height(client_height), ) .with_connection(ConnectionId::zero(), conn_end_on_a) - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a) + .with_channel( + &dummy_transfer_module, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a, + ) .with_send_sequence(PortId::transfer(), ChannelId::zero(), 1.into()), packet: packet_with_timestamp_old, want_pass: false, @@ -169,7 +197,11 @@ fn send_packet_processing() { .collect(); for mut test in tests { - let res = send_packet(&mut test.ctx.ibc_store, test.packet.clone()); + let res = send_packet( + &mut test.ctx.ibc_store, + &DummyTransferModule, + test.packet.clone(), + ); // Additionally check the events and the output objects in the result. match res { Ok(()) => { diff --git a/tests-integration/tests/core/ics04_channel/timeout.rs b/tests-integration/tests/core/ics04_channel/timeout.rs index 240ddd4a85..6322e6e27f 100644 --- a/tests-integration/tests/core/ics04_channel/timeout.rs +++ b/tests-integration/tests/core/ics04_channel/timeout.rs @@ -18,6 +18,7 @@ use ibc::core::primitives::*; use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_timeout; use ibc_testkit::hosts::MockHost; +use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; use ibc_testkit::testapp::ibc::core::router::MockRouter; use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; @@ -145,6 +146,7 @@ fn timeout_fail_no_consensus_state_for_height(fixture: Fixture) { let mut ctx = ctx .with_channel( + &DummyTransferModule, PortId::transfer(), ChannelId::zero(), chan_end_on_a_unordered, @@ -208,6 +210,7 @@ fn timeout_fail_proof_timeout_not_reached(fixture: Fixture) { ) .with_connection(ConnectionId::zero(), conn_end_on_a) .with_channel( + &DummyTransferModule, PortId::transfer(), ChannelId::zero(), chan_end_on_a_unordered, @@ -242,6 +245,7 @@ fn timeout_success_no_packet_commitment(fixture: Fixture) { } = fixture; let ctx = ctx .with_channel( + &DummyTransferModule, PortId::transfer(), ChannelId::zero(), chan_end_on_a_unordered, @@ -280,6 +284,7 @@ fn timeout_unordered_channel_validate(fixture: Fixture) { ) .with_connection(ConnectionId::zero(), conn_end_on_a) .with_channel( + &DummyTransferModule, PortId::transfer(), ChannelId::zero(), chan_end_on_a_unordered, @@ -319,7 +324,12 @@ fn timeout_ordered_channel_validate(fixture: Fixture) { LightClientState::::with_latest_height(client_height), ) .with_connection(ConnectionId::zero(), conn_end_on_a) - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a_ordered) + .with_channel( + &DummyTransferModule, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a_ordered, + ) .with_packet_commitment( packet.port_id_on_a, packet.chan_id_on_a, @@ -347,6 +357,7 @@ fn timeout_unordered_chan_execute(fixture: Fixture) { } = fixture; let mut ctx = ctx .with_channel( + &DummyTransferModule, PortId::transfer(), ChannelId::zero(), chan_end_on_a_unordered, @@ -388,7 +399,12 @@ fn timeout_ordered_chan_execute(fixture: Fixture) { .. } = fixture; let mut ctx = ctx - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a_ordered) + .with_channel( + &DummyTransferModule, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a_ordered, + ) .with_connection(ConnectionId::zero(), conn_end_on_a) .with_packet_commitment( msg.packet.port_id_on_a.clone(), diff --git a/tests-integration/tests/core/ics04_channel/timeout_on_close.rs b/tests-integration/tests/core/ics04_channel/timeout_on_close.rs index a454261fda..73e4b4aaa9 100644 --- a/tests-integration/tests/core/ics04_channel/timeout_on_close.rs +++ b/tests-integration/tests/core/ics04_channel/timeout_on_close.rs @@ -15,6 +15,7 @@ use ibc::core::primitives::*; use ibc_testkit::context::MockContext; use ibc_testkit::fixtures::core::channel::dummy_raw_msg_timeout_on_close; use ibc_testkit::hosts::MockHost; +use ibc_testkit::testapp::ibc::applications::transfer::types::DummyTransferModule; use ibc_testkit::testapp::ibc::core::router::MockRouter; use ibc_testkit::testapp::ibc::core::types::LightClientState; use rstest::*; @@ -117,7 +118,12 @@ fn timeout_on_close_success_no_packet_commitment(fixture: Fixture) { .. } = fixture; let context = context - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a) + .with_channel( + &DummyTransferModule, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a, + ) .with_connection(ConnectionId::zero(), conn_end_on_a); let msg_envelope = MsgEnvelope::from(PacketMsg::from(msg)); @@ -142,7 +148,12 @@ fn timeout_on_close_success_happy_path(fixture: Fixture) { .. } = fixture; let context = context - .with_channel(PortId::transfer(), ChannelId::zero(), chan_end_on_a) + .with_channel( + &DummyTransferModule, + PortId::transfer(), + ChannelId::zero(), + chan_end_on_a, + ) .with_connection(ConnectionId::zero(), conn_end_on_a) .with_packet_commitment( msg.packet.port_id_on_a.clone(),