ibc_core_handler/
entrypoint.rs

1use ibc_core_channel::handler::{
2    acknowledgement_packet_execute, acknowledgement_packet_validate, chan_close_confirm_execute,
3    chan_close_confirm_validate, chan_close_init_execute, chan_close_init_validate,
4    chan_open_ack_execute, chan_open_ack_validate, chan_open_confirm_execute,
5    chan_open_confirm_validate, chan_open_init_execute, chan_open_init_validate,
6    chan_open_try_execute, chan_open_try_validate, recv_packet_execute, recv_packet_validate,
7    timeout_packet_execute, timeout_packet_validate, TimeoutMsgType,
8};
9use ibc_core_channel::types::msgs::{
10    channel_msg_to_port_id, packet_msg_to_port_id, ChannelMsg, PacketMsg,
11};
12use ibc_core_client::context::{ClientExecutionContext, ClientValidationContext};
13use ibc_core_client::handler::{create_client, update_client, upgrade_client};
14use ibc_core_client::types::error::ClientError;
15use ibc_core_client::types::msgs::{ClientMsg, MsgUpdateOrMisbehaviour};
16use ibc_core_connection::handler::{
17    conn_open_ack, conn_open_confirm, conn_open_init, conn_open_try,
18};
19use ibc_core_connection::types::msgs::ConnectionMsg;
20use ibc_core_handler_types::error::HandlerError;
21use ibc_core_handler_types::msgs::MsgEnvelope;
22use ibc_core_host::types::error::HostError;
23use ibc_core_host::{ExecutionContext, ValidationContext};
24use ibc_core_router::router::Router;
25use ibc_core_router::types::error::RouterError;
26use ibc_primitives::prelude::*;
27use ibc_primitives::proto::Any;
28
29/// Entrypoint which performs both validation and message execution
30pub fn dispatch<Ctx>(
31    ctx: &mut Ctx,
32    router: &mut impl Router,
33    msg: MsgEnvelope,
34) -> Result<(), HandlerError>
35where
36    Ctx: ExecutionContext,
37    <<Ctx::V as ClientValidationContext>::ClientStateRef as TryFrom<Any>>::Error: Into<ClientError>,
38    <<Ctx::E as ClientExecutionContext>::ClientStateMut as TryFrom<Any>>::Error: Into<ClientError>,
39    <Ctx::HostClientState as TryFrom<Any>>::Error: Into<ClientError>,
40{
41    validate(ctx, router, msg.clone())?;
42    execute(ctx, router, msg)
43}
44
45/// Entrypoint which only performs message validation
46///
47/// If a transaction contains `n` messages `m_1` ... `m_n`, then
48/// they MUST be processed as follows:
49///     validate(m_1), execute(m_1), ..., validate(m_n), execute(m_n)
50/// That is, the state transition of message `i` must be applied before
51/// message `i+1` is validated. This is equivalent to calling
52/// `dispatch()` on each successively.
53pub fn validate<Ctx>(ctx: &Ctx, router: &impl Router, msg: MsgEnvelope) -> Result<(), HandlerError>
54where
55    Ctx: ValidationContext,
56    <<Ctx::V as ClientValidationContext>::ClientStateRef as TryFrom<Any>>::Error: Into<ClientError>,
57    <Ctx::HostClientState as TryFrom<Any>>::Error: Into<ClientError>,
58{
59    match msg {
60        MsgEnvelope::Client(msg) => match msg {
61            ClientMsg::CreateClient(msg) => create_client::validate(ctx, msg)?,
62            ClientMsg::UpdateClient(msg) => {
63                update_client::validate(ctx, MsgUpdateOrMisbehaviour::UpdateClient(msg))?
64            }
65            ClientMsg::Misbehaviour(msg) => {
66                update_client::validate(ctx, MsgUpdateOrMisbehaviour::Misbehaviour(msg))?
67            }
68            ClientMsg::UpgradeClient(msg) => upgrade_client::validate(ctx, msg)?,
69            ClientMsg::RecoverClient(_msg) => {
70                // Recover client messages are not dispatched by ibc-rs as they can only be
71                // authorized via a passing governance proposal
72            }
73        },
74        MsgEnvelope::Connection(msg) => match msg {
75            ConnectionMsg::OpenInit(msg) => conn_open_init::validate(ctx, msg)?,
76            ConnectionMsg::OpenTry(msg) => conn_open_try::validate(ctx, msg)?,
77            ConnectionMsg::OpenAck(msg) => conn_open_ack::validate(ctx, msg)?,
78            ConnectionMsg::OpenConfirm(msg) => conn_open_confirm::validate(ctx, &msg)?,
79        },
80        MsgEnvelope::Channel(msg) => {
81            let port_id = channel_msg_to_port_id(&msg);
82            let module_id = router.lookup_module(port_id).ok_or(RouterError::Host(
83                HostError::missing_state(format!("missing module ID for port {}", port_id.clone())),
84            ))?;
85            let module = router
86                .get_route(&module_id)
87                .ok_or(RouterError::MissingModule)?;
88
89            match msg {
90                ChannelMsg::OpenInit(msg) => chan_open_init_validate(ctx, module, msg)?,
91                ChannelMsg::OpenTry(msg) => chan_open_try_validate(ctx, module, msg)?,
92                ChannelMsg::OpenAck(msg) => chan_open_ack_validate(ctx, module, msg)?,
93                ChannelMsg::OpenConfirm(msg) => chan_open_confirm_validate(ctx, module, msg)?,
94                ChannelMsg::CloseInit(msg) => chan_close_init_validate(ctx, module, msg)?,
95                ChannelMsg::CloseConfirm(msg) => chan_close_confirm_validate(ctx, module, msg)?,
96            }
97        }
98        MsgEnvelope::Packet(msg) => {
99            let port_id = packet_msg_to_port_id(&msg);
100            let module_id = router.lookup_module(port_id).ok_or(RouterError::Host(
101                HostError::missing_state(format!("missing module ID for port {}", port_id.clone())),
102            ))?;
103            let module = router
104                .get_route(&module_id)
105                .ok_or(RouterError::MissingModule)?;
106
107            match msg {
108                PacketMsg::Recv(msg) => recv_packet_validate(ctx, msg)?,
109                PacketMsg::Ack(msg) => acknowledgement_packet_validate(ctx, module, msg)?,
110                PacketMsg::Timeout(msg) => {
111                    timeout_packet_validate(ctx, module, TimeoutMsgType::Timeout(msg))?
112                }
113                PacketMsg::TimeoutOnClose(msg) => {
114                    timeout_packet_validate(ctx, module, TimeoutMsgType::TimeoutOnClose(msg))?
115                }
116            }
117        }
118    };
119
120    Ok(())
121}
122
123/// Entrypoint which only performs message execution
124pub fn execute<Ctx>(
125    ctx: &mut Ctx,
126    router: &mut impl Router,
127    msg: MsgEnvelope,
128) -> Result<(), HandlerError>
129where
130    Ctx: ExecutionContext,
131    <<Ctx::E as ClientExecutionContext>::ClientStateMut as TryFrom<Any>>::Error: Into<ClientError>,
132{
133    match msg {
134        MsgEnvelope::Client(msg) => match msg {
135            ClientMsg::CreateClient(msg) => create_client::execute(ctx, msg)?,
136            ClientMsg::UpdateClient(msg) => {
137                update_client::execute(ctx, MsgUpdateOrMisbehaviour::UpdateClient(msg))?
138            }
139            ClientMsg::Misbehaviour(msg) => {
140                update_client::execute(ctx, MsgUpdateOrMisbehaviour::Misbehaviour(msg))?
141            }
142            ClientMsg::UpgradeClient(msg) => upgrade_client::execute(ctx, msg)?,
143            ClientMsg::RecoverClient(_msg) => {
144                // Recover client messages are not dispatched by ibc-rs as they can only be
145                // authorized via a passing governance proposal
146            }
147        },
148        MsgEnvelope::Connection(msg) => match msg {
149            ConnectionMsg::OpenInit(msg) => conn_open_init::execute(ctx, msg)?,
150            ConnectionMsg::OpenTry(msg) => conn_open_try::execute(ctx, msg)?,
151            ConnectionMsg::OpenAck(msg) => conn_open_ack::execute(ctx, msg)?,
152            ConnectionMsg::OpenConfirm(msg) => conn_open_confirm::execute(ctx, &msg)?,
153        },
154        MsgEnvelope::Channel(msg) => {
155            let port_id = channel_msg_to_port_id(&msg);
156            let module_id = router.lookup_module(port_id).ok_or(RouterError::Host(
157                HostError::missing_state(format!("missing module ID for port {}", port_id.clone())),
158            ))?;
159            let module = router
160                .get_route_mut(&module_id)
161                .ok_or(RouterError::MissingModule)?;
162
163            match msg {
164                ChannelMsg::OpenInit(msg) => chan_open_init_execute(ctx, module, msg)?,
165                ChannelMsg::OpenTry(msg) => chan_open_try_execute(ctx, module, msg)?,
166                ChannelMsg::OpenAck(msg) => chan_open_ack_execute(ctx, module, msg)?,
167                ChannelMsg::OpenConfirm(msg) => chan_open_confirm_execute(ctx, module, msg)?,
168                ChannelMsg::CloseInit(msg) => chan_close_init_execute(ctx, module, msg)?,
169                ChannelMsg::CloseConfirm(msg) => chan_close_confirm_execute(ctx, module, msg)?,
170            }
171        }
172        MsgEnvelope::Packet(msg) => {
173            let port_id = packet_msg_to_port_id(&msg);
174            let module_id = router.lookup_module(port_id).ok_or(RouterError::Host(
175                HostError::missing_state(format!("missing module ID for port {}", port_id.clone())),
176            ))?;
177            let module = router
178                .get_route_mut(&module_id)
179                .ok_or(RouterError::MissingModule)?;
180
181            match msg {
182                PacketMsg::Recv(msg) => recv_packet_execute(ctx, module, msg)?,
183                PacketMsg::Ack(msg) => acknowledgement_packet_execute(ctx, module, msg)?,
184                PacketMsg::Timeout(msg) => {
185                    timeout_packet_execute(ctx, module, TimeoutMsgType::Timeout(msg))?
186                }
187                PacketMsg::TimeoutOnClose(msg) => {
188                    timeout_packet_execute(ctx, module, TimeoutMsgType::TimeoutOnClose(msg))?
189                }
190            }
191        }
192    }
193
194    Ok(())
195}