ibc_core_connection/handler/
conn_open_ack.rs1use ibc_core_client::context::prelude::*;
4use ibc_core_client::types::error::ClientError;
5use ibc_core_connection_types::error::ConnectionError;
6use ibc_core_connection_types::events::OpenAck;
7use ibc_core_connection_types::msgs::MsgConnectionOpenAck;
8use ibc_core_connection_types::{ConnectionEnd, Counterparty, State};
9use ibc_core_handler_types::events::{IbcEvent, MessageEvent};
10use ibc_core_host::types::identifiers::ClientId;
11use ibc_core_host::types::path::{ClientConsensusStatePath, ClientStatePath, ConnectionPath, Path};
12use ibc_core_host::{ExecutionContext, ValidationContext};
13use ibc_primitives::prelude::*;
14use ibc_primitives::proto::{Any, Protobuf};
15use ibc_primitives::ToVec;
16
17use crate::handler::{pack_host_consensus_state, unpack_host_client_state};
18
19pub fn validate<Ctx>(ctx_a: &Ctx, msg: MsgConnectionOpenAck) -> Result<(), ConnectionError>
20where
21 Ctx: ValidationContext,
22 <Ctx::HostClientState as TryFrom<Any>>::Error: Into<ClientError>,
23{
24 let vars = LocalVars::new(ctx_a, &msg)?;
25 validate_impl(ctx_a, &msg, &vars)
26}
27
28fn validate_impl<Ctx>(
29 ctx_a: &Ctx,
30 msg: &MsgConnectionOpenAck,
31 vars: &LocalVars,
32) -> Result<(), ConnectionError>
33where
34 Ctx: ValidationContext,
35 <Ctx::HostClientState as TryFrom<Any>>::Error: Into<ClientError>,
36{
37 ctx_a.validate_message_signer(&msg.signer)?;
38
39 let host_height = ctx_a.host_height()?;
40
41 if msg.consensus_height_of_a_on_b > host_height {
42 return Err(ConnectionError::InsufficientConsensusHeight {
43 target_height: msg.consensus_height_of_a_on_b,
44 current_height: host_height,
45 });
46 }
47
48 let client_val_ctx_a = ctx_a.get_client_validation_context();
49
50 let client_state_of_a_on_b = unpack_host_client_state::<Ctx::HostClientState>(
51 msg.client_state_of_a_on_b.clone(),
52 vars.client_id_on_b(),
53 )?;
54
55 ctx_a.validate_self_client(client_state_of_a_on_b)?;
56
57 msg.version
58 .verify_is_supported(vars.conn_end_on_a.versions())?;
59
60 vars.conn_end_on_a.verify_state_matches(&State::Init)?;
61
62 {
64 let client_state_of_b_on_a = client_val_ctx_a.client_state(vars.client_id_on_a())?;
65
66 client_state_of_b_on_a
67 .status(client_val_ctx_a, vars.client_id_on_a())?
68 .verify_is_active()?;
69
70 client_state_of_b_on_a.validate_proof_height(msg.proofs_height_on_b)?;
71
72 let client_cons_state_path_on_a = ClientConsensusStatePath::new(
73 vars.client_id_on_a().clone(),
74 msg.proofs_height_on_b.revision_number(),
75 msg.proofs_height_on_b.revision_height(),
76 );
77
78 let consensus_state_of_b_on_a =
79 client_val_ctx_a.consensus_state(&client_cons_state_path_on_a)?;
80
81 let prefix_on_a = ctx_a.commitment_prefix();
82 let prefix_on_b = vars.conn_end_on_a.counterparty().prefix();
83
84 {
85 let expected_conn_end_on_b = ConnectionEnd::new(
86 State::TryOpen,
87 vars.client_id_on_b().clone(),
88 Counterparty::new(
89 vars.client_id_on_a().clone(),
90 Some(msg.conn_id_on_a.clone()),
91 prefix_on_a,
92 ),
93 vec![msg.version.clone()],
94 vars.conn_end_on_a.delay_period(),
95 )?;
96
97 client_state_of_b_on_a.verify_membership(
98 prefix_on_b,
99 &msg.proof_conn_end_on_b,
100 consensus_state_of_b_on_a.root(),
101 Path::Connection(ConnectionPath::new(&msg.conn_id_on_b)),
102 expected_conn_end_on_b.encode_vec(),
103 )?;
104 }
105
106 client_state_of_b_on_a.verify_membership(
107 prefix_on_b,
108 &msg.proof_client_state_of_a_on_b,
109 consensus_state_of_b_on_a.root(),
110 Path::ClientState(ClientStatePath::new(vars.client_id_on_b().clone())),
111 msg.client_state_of_a_on_b.to_vec(),
112 )?;
113
114 let expected_consensus_state_of_a_on_b =
115 ctx_a.host_consensus_state(&msg.consensus_height_of_a_on_b)?;
116
117 let stored_consensus_state_of_a_on_b =
118 pack_host_consensus_state(expected_consensus_state_of_a_on_b, vars.client_id_on_b());
119
120 let client_cons_state_path_on_b = ClientConsensusStatePath::new(
121 vars.client_id_on_b().clone(),
122 msg.consensus_height_of_a_on_b.revision_number(),
123 msg.consensus_height_of_a_on_b.revision_height(),
124 );
125
126 client_state_of_b_on_a.verify_membership(
127 prefix_on_b,
128 &msg.proof_consensus_state_of_a_on_b,
129 consensus_state_of_b_on_a.root(),
130 Path::ClientConsensusState(client_cons_state_path_on_b),
131 stored_consensus_state_of_a_on_b.to_vec(),
132 )?;
133 }
134
135 Ok(())
136}
137
138pub fn execute<Ctx>(ctx_a: &mut Ctx, msg: MsgConnectionOpenAck) -> Result<(), ConnectionError>
139where
140 Ctx: ExecutionContext,
141{
142 let vars = LocalVars::new(ctx_a, &msg)?;
143 execute_impl(ctx_a, msg, vars)
144}
145
146fn execute_impl<Ctx>(
147 ctx_a: &mut Ctx,
148 msg: MsgConnectionOpenAck,
149 vars: LocalVars,
150) -> Result<(), ConnectionError>
151where
152 Ctx: ExecutionContext,
153{
154 let event = IbcEvent::OpenAckConnection(OpenAck::new(
155 msg.conn_id_on_a.clone(),
156 vars.client_id_on_a().clone(),
157 msg.conn_id_on_b.clone(),
158 vars.client_id_on_b().clone(),
159 ));
160 ctx_a.emit_ibc_event(IbcEvent::Message(MessageEvent::Connection))?;
161 ctx_a.emit_ibc_event(event)?;
162
163 ctx_a.log_message("success: conn_open_ack verification passed".to_string())?;
164
165 {
166 let new_conn_end_on_a = {
167 let mut counterparty = vars.conn_end_on_a.counterparty().clone();
168 counterparty.connection_id = Some(msg.conn_id_on_b.clone());
169
170 let mut new_conn_end_on_a = vars.conn_end_on_a;
171 new_conn_end_on_a.set_state(State::Open);
172 new_conn_end_on_a.set_version(msg.version.clone());
173 new_conn_end_on_a.set_counterparty(counterparty);
174 new_conn_end_on_a
175 };
176
177 ctx_a.store_connection(&ConnectionPath::new(&msg.conn_id_on_a), new_conn_end_on_a)?;
178 }
179
180 Ok(())
181}
182
183struct LocalVars {
184 conn_end_on_a: ConnectionEnd,
185}
186
187impl LocalVars {
188 fn new<Ctx>(ctx_a: &Ctx, msg: &MsgConnectionOpenAck) -> Result<Self, ConnectionError>
189 where
190 Ctx: ValidationContext,
191 {
192 Ok(LocalVars {
193 conn_end_on_a: ctx_a.connection_end(&msg.conn_id_on_a)?,
194 })
195 }
196
197 fn client_id_on_a(&self) -> &ClientId {
198 self.conn_end_on_a.client_id()
199 }
200
201 fn client_id_on_b(&self) -> &ClientId {
202 self.conn_end_on_a.counterparty().client_id()
203 }
204}