penumbra_sdk_ibc/component/msg_handler/
channel_open_confirm.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::MsgChannelOpenConfirm,
6 channel::ChannelEnd, channel::Counterparty, channel::PortId,
7 connection::State as ConnectionState,
8};
9
10use crate::component::{
11 app_handler::{AppHandlerCheck, AppHandlerExecute},
12 channel::{StateReadExt as _, StateWriteExt as _},
13 connection::StateReadExt as _,
14 proof_verification::ChannelProofVerifier,
15 HostInterface, MsgHandler,
16};
17
18#[async_trait]
19impl MsgHandler for MsgChannelOpenConfirm {
20 async fn check_stateless<H: AppHandlerCheck>(&self) -> Result<()> {
21 Ok(())
24 }
25
26 async fn try_execute<
27 S: StateWrite,
28 AH: AppHandlerCheck + AppHandlerExecute,
29 HI: HostInterface,
30 >(
31 &self,
32 mut state: S,
33 ) -> Result<()> {
34 tracing::debug!(msg = ?self);
35 let mut channel = state
36 .get_channel(&self.chan_id_on_b, &self.port_id_on_b)
37 .await?
38 .ok_or_else(|| anyhow::anyhow!("channel not found"))?;
39 if !channel.state_matches(&ChannelState::TryOpen) {
40 anyhow::bail!("channel is not in the correct state");
41 }
42
43 let connection = state
46 .get_connection(&channel.connection_hops[0])
47 .await?
48 .ok_or_else(|| anyhow::anyhow!("connection not found for channel"))?;
49 if !connection.state_matches(&ConnectionState::Open) {
50 anyhow::bail!("connection for channel is not open");
51 }
52
53 let expected_connection_hops = vec![connection
54 .counterparty
55 .connection_id
56 .clone()
57 .ok_or_else(|| anyhow::anyhow!("no counterparty connection id provided"))?];
58
59 let expected_counterparty =
60 Counterparty::new(self.port_id_on_b.clone(), Some(self.chan_id_on_b.clone()));
61
62 let expected_channel = ChannelEnd {
63 state: ChannelState::Open,
64 ordering: channel.ordering,
65 remote: expected_counterparty,
66 connection_hops: expected_connection_hops,
67 version: channel.version.clone(),
68 ..ChannelEnd::default()
69 };
70
71 state
72 .verify_channel_proof(
73 &connection,
74 &self.proof_chan_end_on_a,
75 &self.proof_height_on_a,
76 &channel
77 .remote
78 .channel_id
79 .clone()
80 .ok_or_else(|| anyhow::anyhow!("no channel id"))?,
81 &channel.remote.port_id.clone(),
82 &expected_channel,
83 )
84 .await?;
85
86 let transfer = PortId::transfer();
87 if self.port_id_on_b == transfer {
88 AH::chan_open_confirm_check(&mut state, self).await?;
89 } else {
90 anyhow::bail!("invalid port id");
91 }
92
93 channel.set_state(ChannelState::Open);
94 state.put_channel(&self.chan_id_on_b, &self.port_id_on_b, channel.clone());
95
96 state.record(
97 events::channel::OpenConfirm {
98 port_id: self.port_id_on_b.clone(),
99 channel_id: self.chan_id_on_b.clone(),
100 counterparty_port_id: channel.counterparty().port_id.clone(),
101 counterparty_channel_id: channel
102 .counterparty()
103 .channel_id
104 .clone()
105 .unwrap_or_default(),
106 connection_id: channel.connection_hops[0].clone(),
107 }
108 .into(),
109 );
110
111 let transfer = PortId::transfer();
112 if self.port_id_on_b == transfer {
113 AH::chan_open_confirm_execute(state, self).await;
114 } else {
115 anyhow::bail!("invalid port id");
116 }
117
118 Ok(())
119 }
120}