Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ibc-apps/ics20-transfer/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Signer>;

/// get_port returns the portID for the transfer module.
Expand Down
4 changes: 2 additions & 2 deletions ibc-apps/ics20-transfer/src/handler/send_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
Expand Down Expand Up @@ -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!(
Expand Down
3 changes: 2 additions & 1 deletion ibc-apps/ics721-nft-transfer/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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<Signer> + PartialEq;
type Nft: NftContext;
type NftClass: NftClassContext;
Expand Down
4 changes: 2 additions & 2 deletions ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ where
}
};

send_packet_validate(send_packet_ctx_a, &packet)?;
send_packet_validate(send_packet_ctx_a, transfer_ctx, &packet)?;

Ok(())
}
Expand Down Expand Up @@ -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!(
Expand Down
1 change: 0 additions & 1 deletion ibc-core/ics03-connection/types/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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;
Expand Down
19 changes: 18 additions & 1 deletion ibc-core/ics04-channel/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use ibc_core_client::context::prelude::*;
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::{ChannelId, ConnectionId, PortId, Sequence};
use ibc_core_host::types::path::{ChannelEndPath, CommitmentPath, 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
Expand All @@ -26,6 +27,13 @@ pub trait SendPacketValidationContext {

fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath)
-> Result<Sequence, ContextError>;

fn has_port_capability(
&self,
module: &impl Module,
port_id: &PortId,
channel_id: &ChannelId,
) -> Result<(), ContextError>;
}

impl<T> SendPacketValidationContext for T
Expand All @@ -52,6 +60,15 @@ where
) -> Result<Sequence, ContextError> {
self.get_next_sequence_send(seq_send_path)
}

fn has_port_capability(
&self,
module: &impl Module,
port_id: &PortId,
channel_id: &ChannelId,
) -> Result<(), ContextError> {
self.has_port_capability(module.identifier().to_string().into(), port_id, channel_id)
}
}

/// Methods required in send packet execution, to be implemented by the host
Expand Down
8 changes: 8 additions & 0 deletions ibc-core/ics04-channel/src/handler/chan_open_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ where
&msg.version_proposal,
)?;

ctx_a.available_port_capability(&msg.port_id_on_a, &chan_id_on_a)?;

Ok(())
}

Expand Down Expand Up @@ -104,6 +106,12 @@ where
}
}

ctx_a.claim_port_capability(
module.identifier().to_string().into(),
&msg.port_id_on_a,
&chan_id_on_a,
)?;

Ok(())
}

Expand Down
8 changes: 8 additions & 0 deletions ibc-core/ics04-channel/src/handler/chan_open_try.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ where
&msg.version_supported_on_a,
)?;

ctx_b.available_port_capability(&msg.port_id_on_b, &chan_id_on_b)?;

Ok(())
}

Expand Down Expand Up @@ -112,6 +114,12 @@ where
}
}

ctx_b.claim_port_capability(
module.identifier().to_string().into(),
&msg.port_id_on_b,
&chan_id_on_b,
)?;

Ok(())
}

Expand Down
12 changes: 10 additions & 2 deletions ibc-core/ics04-channel/src/handler/send_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use ibc_core_handler_types::events::{IbcEvent, MessageEvent};
use ibc_core_host::types::path::{
ChannelEndPath, ClientConsensusStatePath, CommitmentPath, SeqSendPath,
};
use ibc_core_router::module::Module;
use ibc_primitives::prelude::*;
use ibc_primitives::Expiry;

Expand All @@ -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(module, &packet.port_id_on_a, &packet.chan_id_on_a)?;

if !packet.timeout_height_on_b.is_set() && !packet.timeout_timestamp_on_b.is_set() {
return Err(ContextError::PacketError(PacketError::MissingTimeout));
}
Expand Down Expand Up @@ -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(module, &packet.port_id_on_a, &packet.chan_id_on_a)?;

{
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)?;
Expand Down
10 changes: 10 additions & 0 deletions ibc-core/ics04-channel/types/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ pub enum ChannelError {
InvalidIdentifier(IdentifierError),
/// channel counter overflow error
CounterOverflow,
/// Capability for `{port_id}/{channel_id}` does not exist
CapabilityNotFound {
port_id: PortId,
channel_id: ChannelId,
},
/// Capability for `{port_id}/{channel_id}` already exists
CapabilityAlreadyExists {
port_id: PortId,
channel_id: ChannelId,
},
/// other error: `{description}`
Other { description: String },
}
Expand Down
22 changes: 21 additions & 1 deletion ibc-core/ics24-host/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ 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, ChannelId, ConnectionId, PortId, Sequence};
use ibc_core_host_types::path::{
AckPath, ChannelEndPath, ClientConnectionPath, CommitmentPath, ConnectionPath, ReceiptPath,
SeqAckPath, SeqRecvPath, SeqSendPath,
Expand Down Expand Up @@ -126,6 +126,19 @@ pub trait ValidationContext {
/// `ExecutionContext::increase_channel_counter`.
fn channel_counter(&self) -> Result<u64, ContextError>;

fn available_port_capability(
&self,
port_id: &PortId,
channel_id: &ChannelId,
) -> Result<(), ContextError>;

fn has_port_capability(
&self,
capability: CapabilityKey,
port_id: &PortId,
channel_id: &ChannelId,
) -> Result<(), ContextError>;

/// Returns the maximum expected time per block
fn max_expected_time_per_block(&self) -> Duration;

Expand Down Expand Up @@ -233,6 +246,13 @@ 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,
capability: CapabilityKey,
port_id: &PortId,
channel_id: &ChannelId,
) -> Result<(), ContextError>;

/// Emit the given IBC event
fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), ContextError>;

Expand Down
27 changes: 27 additions & 0 deletions ibc-core/ics24-host/types/src/identifiers/capability_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use core::any::TypeId;
use core::fmt::Write;

use ibc_primitives::prelude::String;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CapabilityKey(String);

impl From<TypeId> for CapabilityKey {
fn from(type_id: TypeId) -> Self {
let mut buf = String::new();
write!(buf, "{:?}", type_id).unwrap();
Self(buf)
}
}

impl From<String> for CapabilityKey {
fn from(value: String) -> Self {
Self(value)
}
}

impl AsRef<str> for CapabilityKey {
fn as_ref(&self) -> &str {
self.0.as_str()
}
}
2 changes: 2 additions & 0 deletions ibc-core/ics24-host/types/src/identifiers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Defines identifier types

mod capability_key;
mod chain_id;
mod channel_id;
mod client_id;
Expand All @@ -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;
Expand Down
12 changes: 10 additions & 2 deletions ibc-core/ics26-routing/src/module.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
use core::any::TypeId;
/// The trait that defines an IBC application
use core::fmt::Debug;
use core::fmt::Write;

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_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 {
let mut buf = String::new();
write!(buf, "{:?}", TypeId::of::<Self>()).expect("Never fails");
ModuleId::new(buf)
}

fn on_chan_open_init_validate(
&self,
order: Order,
Expand Down
7 changes: 7 additions & 0 deletions ibc-testkit/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use ibc::core::host::types::path::{
SeqAckPath, SeqRecvPath, SeqSendPath,
};
use ibc::core::host::{ExecutionContext, ValidationContext};
use ibc::core::router::module::Module;
use ibc::primitives::prelude::*;
use ibc::primitives::Timestamp;

Expand Down Expand Up @@ -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,
Expand All @@ -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(module.identifier().to_string().into(), &port_id, &chan_id)
.expect("error writing to store");

self
}

Expand Down
Loading