ibc_core_client/handler/
create_client.rs

1//! Protocol logic specific to processing ICS2 messages of type `MsgCreateClient`.
2
3use ibc_core_client_context::prelude::*;
4use ibc_core_client_types::error::ClientError;
5use ibc_core_client_types::events::CreateClient;
6use ibc_core_client_types::msgs::MsgCreateClient;
7use ibc_core_client_types::Status;
8use ibc_core_handler_types::events::{IbcEvent, MessageEvent};
9use ibc_core_host::{ClientStateMut, ClientStateRef, ExecutionContext, ValidationContext};
10use ibc_primitives::prelude::*;
11use ibc_primitives::proto::Any;
12
13pub fn validate<Ctx>(ctx: &Ctx, msg: MsgCreateClient) -> Result<(), ClientError>
14where
15    Ctx: ValidationContext,
16    <ClientStateRef<Ctx> as TryFrom<Any>>::Error: Into<ClientError>,
17{
18    let MsgCreateClient {
19        client_state,
20        consensus_state,
21        signer,
22    } = msg;
23
24    ctx.validate_message_signer(&signer)?;
25
26    // Construct this client's identifier
27    let id_counter = ctx.client_counter()?;
28
29    let client_val_ctx = ctx.get_client_validation_context();
30
31    let client_state = ClientStateRef::<Ctx>::try_from(client_state).map_err(Into::into)?;
32
33    let client_id = client_state.client_type().build_client_id(id_counter);
34
35    let status = client_state.status(client_val_ctx, &client_id)?;
36
37    if status.is_frozen() {
38        return Err(ClientError::InvalidStatus(Status::Frozen));
39    };
40
41    let host_timestamp = ctx.host_timestamp()?;
42
43    client_state.verify_consensus_state(consensus_state, &host_timestamp)?;
44
45    if client_val_ctx.client_state(&client_id).is_ok() {
46        return Err(ClientError::DuplicateClientState(client_id));
47    };
48
49    Ok(())
50}
51
52pub fn execute<Ctx>(ctx: &mut Ctx, msg: MsgCreateClient) -> Result<(), ClientError>
53where
54    Ctx: ExecutionContext,
55    <ClientStateMut<Ctx> as TryFrom<Any>>::Error: Into<ClientError>,
56{
57    let MsgCreateClient {
58        client_state,
59        consensus_state,
60        signer: _,
61    } = msg;
62
63    // Construct this client's identifier
64    let id_counter = ctx.client_counter()?;
65
66    let client_exec_ctx = ctx.get_client_execution_context();
67
68    let client_state = ClientStateMut::<Ctx>::try_from(client_state).map_err(Into::into)?;
69
70    let client_type = client_state.client_type();
71    let client_id = client_type.build_client_id(id_counter);
72
73    client_state.initialise(client_exec_ctx, &client_id, consensus_state)?;
74
75    ctx.increase_client_counter()?;
76
77    let event = IbcEvent::CreateClient(CreateClient::new(
78        client_id.clone(),
79        client_type,
80        client_state.latest_height(),
81    ));
82    ctx.emit_ibc_event(IbcEvent::Message(MessageEvent::Client))?;
83    ctx.emit_ibc_event(event)?;
84
85    ctx.log_message(format!(
86        "success: generated new client identifier: {client_id}"
87    ))?;
88
89    Ok(())
90}