penumbra_sdk_ibc/component/msg_handler/
channel_close_init.rs1use anyhow::Result;
2use async_trait::async_trait;
3use cnidarium::StateWrite;
4use ibc_types::core::{
5 channel::channel::State as ChannelState, channel::events, channel::msgs::MsgChannelCloseInit,
6 channel::PortId, connection::State as ConnectionState,
7};
8
9use crate::component::{
10 app_handler::{AppHandlerCheck, AppHandlerExecute},
11 channel::{StateReadExt as _, StateWriteExt as _},
12 connection::StateReadExt as _,
13 HostInterface, MsgHandler,
14};
15
16#[async_trait]
17impl MsgHandler for MsgChannelCloseInit {
18 async fn check_stateless<H: AppHandlerCheck>(&self) -> Result<()> {
19 Ok(())
22 }
23
24 async fn try_execute<
25 S: StateWrite,
26 AH: AppHandlerCheck + AppHandlerExecute,
27 HI: HostInterface,
28 >(
29 &self,
30 mut state: S,
31 ) -> Result<()> {
32 tracing::debug!(msg = ?self);
33 let mut channel = state
39 .get_channel(&self.chan_id_on_a, &self.port_id_on_a)
40 .await?
41 .ok_or_else(|| anyhow::anyhow!("channel not found"))?;
42 if channel.state_matches(&ChannelState::Closed) {
43 anyhow::bail!("channel is already closed");
44 }
45
46 let connection = state
47 .get_connection(&channel.connection_hops[0])
48 .await?
49 .ok_or_else(|| anyhow::anyhow!("connection not found for channel"))?;
50 if !connection.state_matches(&ConnectionState::Open) {
51 anyhow::bail!("connection for channel is not open");
52 }
53 let transfer = PortId::transfer();
54 if self.port_id_on_a == transfer {
55 AH::chan_close_init_check(&mut state, self).await?;
56 } else {
57 anyhow::bail!("invalid port id");
58 }
59
60 channel.set_state(ChannelState::Closed);
61 state.put_channel(&self.chan_id_on_a, &self.port_id_on_a, channel.clone());
62
63 state.record(
64 events::channel::CloseInit {
65 port_id: self.port_id_on_a.clone(),
66 channel_id: self.chan_id_on_a.clone(),
67 counterparty_port_id: channel.counterparty().port_id.clone(),
68 counterparty_channel_id: channel
69 .counterparty()
70 .channel_id
71 .clone()
72 .unwrap_or_default(),
73 connection_id: channel.connection_hops[0].clone(),
74 }
75 .into(),
76 );
77
78 let transfer = PortId::transfer();
79 if self.port_id_on_a == transfer {
80 AH::chan_close_init_execute(state, self).await;
81 } else {
82 anyhow::bail!("invalid port id");
83 }
84
85 Ok(())
86 }
87}