Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ibc-core): port capability #1258

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
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 @@
}
};

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

Check warning on line 130 in ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs

View check run for this annotation

Codecov / codecov/patch

ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs#L130

Added line #L130 was not covered by tests

Ok(())
}
Expand Down Expand Up @@ -229,7 +229,7 @@
}
};

send_packet_execute(send_packet_ctx_a, packet)?;
send_packet_execute(send_packet_ctx_a, transfer_ctx, packet)?;

Check warning on line 232 in ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs

View check run for this annotation

Codecov / codecov/patch

ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs#L232

Added line #L232 was not covered by tests

{
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)
}

Check warning on line 14 in ibc-core/ics24-host/types/src/identifiers/capability_key.rs

View check run for this annotation

Codecov / codecov/patch

ibc-core/ics24-host/types/src/identifiers/capability_key.rs#L10-L14

Added lines #L10 - L14 were not covered by tests
}

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()
}

Check warning on line 26 in ibc-core/ics24-host/types/src/identifiers/capability_key.rs

View check run for this annotation

Codecov / codecov/patch

ibc-core/ics24-host/types/src/identifiers/capability_key.rs#L24-L26

Added lines #L24 - L26 were not covered by tests
}
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
Loading