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 all 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
17 changes: 16 additions & 1 deletion ibc-core/ics04-channel/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,6 +27,12 @@ pub trait SendPacketValidationContext {

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

fn has_port_capability(
&self,
port_path: &PortPath,
module: &impl Module,
) -> Result<(), ContextError>;
}

impl<T> SendPacketValidationContext for T
Expand All @@ -52,6 +59,14 @@ where
) -> Result<Sequence, ContextError> {
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
Expand Down
14 changes: 13 additions & 1 deletion ibc-core/ics04-channel/src/handler/chan_open_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -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(())
}

Expand Down Expand Up @@ -104,6 +111,11 @@ where
}
}

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

Ok(())
}

Expand Down
14 changes: 13 additions & 1 deletion ibc-core/ics04-channel/src/handler/chan_open_try.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(())
}

Expand Down Expand Up @@ -112,6 +119,11 @@ where
}
}

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

Ok(())
}

Expand Down
14 changes: 11 additions & 3 deletions ibc-core/ics04-channel/src/handler/send_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

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(&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));
}
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(&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)?;
Expand Down
5 changes: 5 additions & 0 deletions ibc-core/ics04-channel/types/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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 },
}
Expand Down
20 changes: 17 additions & 3 deletions ibc-core/ics24-host/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -126,6 +126,14 @@ pub trait ValidationContext {
/// `ExecutionContext::increase_channel_counter`.
fn channel_counter(&self) -> Result<u64, ContextError>;

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;

Expand Down Expand Up @@ -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>;

Expand Down
41 changes: 41 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,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

Check warning on line 11 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#L11

Added line #L11 was not covered by tests
)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)

Check warning on line 16 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#L16

Added line #L16 was not covered by tests
)]
#[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<u8>);

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

Check warning on line 28 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-L28

Added lines #L24 - L28 were not covered by tests
}

impl From<String> 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()
}

Check warning on line 40 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#L38-L40

Added lines #L38 - L40 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
6 changes: 4 additions & 2 deletions ibc-core/ics26-routing/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 8 additions & 1 deletion ibc-testkit/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

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(&PortPath(port_id), module.identifier().to_string().into())
.expect("error writing to store");

self
}

Expand Down
Loading
Loading