ibc_core_connection/handler/
conn_open_ack.rs

1//! Protocol logic specific to processing ICS3 messages of type `MsgConnectionOpenAck`.
2
3use 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    // Proof verification.
63    {
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}