hermes_relayer_components/relay/impls/channel/
open_try.rs

1use core::fmt::Debug;
2
3use cgp::core::error::CanRaiseError;
4
5use crate::chain::traits::message_builders::channel_handshake::CanBuildChannelOpenTryMessage;
6use crate::chain::traits::payload_builders::channel_handshake::CanBuildChannelOpenTryPayload;
7use crate::chain::traits::queries::chain_status::CanQueryChainHeight;
8use crate::chain::traits::queries::client_state::CanQueryClientStateWithLatestHeight;
9use crate::chain::traits::types::ibc_events::channel::HasChannelOpenTryEvent;
10use crate::chain::types::aliases::ChannelIdOf;
11use crate::relay::traits::chains::{CanRaiseRelayChainErrors, HasRelayChains};
12use crate::relay::traits::channel::open_try::ChannelOpenTryRelayer;
13use crate::relay::traits::ibc_message_sender::{CanSendSingleIbcMessage, MainSink};
14use crate::relay::traits::target::DestinationTarget;
15use crate::relay::types::aliases::{DstChannelId, DstPortId, SrcChannelId, SrcPortId};
16
17/**
18   A base implementation of [`ChannelOpenTryRelayer`] that relays a new channel
19   at the source chain that is in `OPEN_INIT` state, and submits it as a
20   `ChannelOpenTry` message to the destination chain.
21
22   This implements the `ChanOpenTry` step of the IBC channel handshake protocol.
23
24   Note that this implementation does not check that the channel exists on
25   the destination chain. It also doesn't check that the channel end at the
26   source chain is really in the `OPEN_INIT` state. This will be implemented as
27   a separate wrapper component. (TODO)
28*/
29
30pub struct RelayChannelOpenTry;
31
32pub struct MissingChannelTryEventError<'a, Relay>
33where
34    Relay: HasRelayChains,
35{
36    pub relay: &'a Relay,
37    pub src_channel_id: &'a ChannelIdOf<Relay::SrcChain, Relay::DstChain>,
38}
39
40impl<Relay, SrcChain, DstChain> ChannelOpenTryRelayer<Relay> for RelayChannelOpenTry
41where
42    Relay: HasRelayChains<SrcChain = SrcChain, DstChain = DstChain>
43        + CanSendSingleIbcMessage<MainSink, DestinationTarget>
44        + for<'a> CanRaiseError<MissingChannelTryEventError<'a, Relay>>
45        + CanRaiseRelayChainErrors,
46    SrcChain: CanQueryChainHeight + CanBuildChannelOpenTryPayload<DstChain>,
47    DstChain: CanQueryClientStateWithLatestHeight<SrcChain>
48        + CanBuildChannelOpenTryMessage<SrcChain>
49        + HasChannelOpenTryEvent<SrcChain>,
50    DstChain::ChannelId: Clone,
51{
52    async fn relay_channel_open_try(
53        relay: &Relay,
54        dst_port: &DstPortId<Relay>,
55        src_port_id: &SrcPortId<Relay>,
56        src_channel_id: &SrcChannelId<Relay>,
57    ) -> Result<DstChannelId<Relay>, Relay::Error> {
58        let src_chain = relay.src_chain();
59        let dst_chain = relay.dst_chain();
60
61        let src_proof_height = src_chain
62            .query_chain_height()
63            .await
64            .map_err(Relay::raise_error)?;
65
66        let src_client_state = dst_chain
67            .query_client_state_with_latest_height(relay.dst_client_id())
68            .await
69            .map_err(Relay::raise_error)?;
70
71        let open_try_payload = src_chain
72            .build_channel_open_try_payload(
73                &src_client_state,
74                &src_proof_height,
75                src_port_id,
76                src_channel_id,
77            )
78            .await
79            .map_err(Relay::raise_error)?;
80
81        let open_try_message = dst_chain
82            .build_channel_open_try_message(dst_port, src_port_id, src_channel_id, open_try_payload)
83            .await
84            .map_err(Relay::raise_error)?;
85
86        let events = relay
87            .send_message(DestinationTarget, open_try_message)
88            .await?;
89
90        let open_try_event = events
91            .into_iter()
92            .find_map(|event| DstChain::try_extract_channel_open_try_event(event))
93            .ok_or_else(|| {
94                Relay::raise_error(MissingChannelTryEventError {
95                    relay,
96                    src_channel_id,
97                })
98            })?;
99
100        let dst_channel_id = DstChain::channel_open_try_event_channel_id(&open_try_event);
101
102        Ok(dst_channel_id.clone())
103    }
104}
105
106impl<'a, Relay> Debug for MissingChannelTryEventError<'a, Relay>
107where
108    Relay: HasRelayChains,
109{
110    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
111        f.debug_struct("MissingChannelTryEventError")
112            .field("src_channel_id", &self.src_channel_id)
113            .finish()
114    }
115}