ibc_core_connection/handler/
conn_open_init.rs

1//! Protocol logic specific to ICS3 messages of type `MsgConnectionOpenInit`.
2use ibc_core_client::context::prelude::*;
3use ibc_core_connection_types::error::ConnectionError;
4use ibc_core_connection_types::events::OpenInit;
5use ibc_core_connection_types::msgs::MsgConnectionOpenInit;
6use ibc_core_connection_types::{ConnectionEnd, Counterparty, State};
7use ibc_core_handler_types::events::{IbcEvent, MessageEvent};
8use ibc_core_host::types::identifiers::ConnectionId;
9use ibc_core_host::types::path::{ClientConnectionPath, ConnectionPath};
10use ibc_core_host::{ExecutionContext, ValidationContext};
11use ibc_primitives::prelude::*;
12
13pub fn validate<Ctx>(ctx_a: &Ctx, msg: MsgConnectionOpenInit) -> Result<(), ConnectionError>
14where
15    Ctx: ValidationContext,
16{
17    ctx_a.validate_message_signer(&msg.signer)?;
18
19    let client_val_ctx_a = ctx_a.get_client_validation_context();
20
21    // An IBC client running on the local (host) chain should exist.
22    let client_state_of_b_on_a = client_val_ctx_a.client_state(&msg.client_id_on_a)?;
23
24    client_state_of_b_on_a
25        .status(client_val_ctx_a, &msg.client_id_on_a)?
26        .verify_is_active()?;
27
28    if let Some(version) = msg.version {
29        version.verify_is_supported(&ctx_a.get_compatible_versions())?;
30    }
31
32    Ok(())
33}
34
35pub fn execute<Ctx>(ctx_a: &mut Ctx, msg: MsgConnectionOpenInit) -> Result<(), ConnectionError>
36where
37    Ctx: ExecutionContext,
38{
39    let versions = if let Some(version) = msg.version {
40        version.verify_is_supported(&ctx_a.get_compatible_versions())?;
41        vec![version]
42    } else {
43        ctx_a.get_compatible_versions()
44    };
45
46    let conn_end_on_a = ConnectionEnd::new(
47        State::Init,
48        msg.client_id_on_a.clone(),
49        Counterparty::new(
50            msg.counterparty.client_id().clone(),
51            None,
52            msg.counterparty.prefix().clone(),
53        ),
54        versions,
55        msg.delay_period,
56    )?;
57
58    // Construct the identifier for the new connection.
59    let conn_id_on_a = ConnectionId::new(ctx_a.connection_counter()?);
60
61    ctx_a.log_message(format!(
62        "success: conn_open_init: generated new connection identifier: {conn_id_on_a}"
63    ))?;
64
65    {
66        let client_id_on_b = msg.counterparty.client_id().clone();
67
68        let event = IbcEvent::OpenInitConnection(OpenInit::new(
69            conn_id_on_a.clone(),
70            msg.client_id_on_a.clone(),
71            client_id_on_b,
72        ));
73        ctx_a.emit_ibc_event(IbcEvent::Message(MessageEvent::Connection))?;
74        ctx_a.emit_ibc_event(event)?;
75    }
76
77    ctx_a.increase_connection_counter()?;
78    ctx_a.store_connection_to_client(
79        &ClientConnectionPath::new(msg.client_id_on_a),
80        conn_id_on_a.clone(),
81    )?;
82    ctx_a.store_connection(&ConnectionPath::new(&conn_id_on_a), conn_end_on_a)?;
83
84    Ok(())
85}