ibc_core_client/handler/
update_client.rs

1//! Protocol logic specific to processing ICS2 messages of type `MsgUpdateAnyClient`.
2
3use ibc_core_client_context::prelude::*;
4use ibc_core_client_types::error::ClientError;
5use ibc_core_client_types::events::{ClientMisbehaviour, UpdateClient};
6use ibc_core_client_types::msgs::MsgUpdateOrMisbehaviour;
7use ibc_core_client_types::UpdateKind;
8use ibc_core_handler_types::events::{IbcEvent, MessageEvent};
9use ibc_core_host::types::error::HostError;
10use ibc_core_host::{ExecutionContext, ValidationContext};
11use ibc_primitives::prelude::*;
12use ibc_primitives::ToVec;
13
14pub fn validate<Ctx>(ctx: &Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ClientError>
15where
16    Ctx: ValidationContext,
17{
18    ctx.validate_message_signer(msg.signer())?;
19
20    let client_id = msg.client_id().clone();
21
22    let client_val_ctx = ctx.get_client_validation_context();
23
24    // Read client state from the host chain store. The client should already exist.
25    let client_state = client_val_ctx.client_state(&client_id)?;
26
27    client_state
28        .status(client_val_ctx, &client_id)?
29        .verify_is_active()?;
30
31    let client_message = msg.client_message();
32
33    client_state.verify_client_message(client_val_ctx, &client_id, client_message)?;
34
35    Ok(())
36}
37
38pub fn execute<Ctx>(ctx: &mut Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ClientError>
39where
40    Ctx: ExecutionContext,
41{
42    let client_id = msg.client_id().clone();
43    let update_kind = match msg {
44        MsgUpdateOrMisbehaviour::UpdateClient(_) => UpdateKind::UpdateClient,
45        MsgUpdateOrMisbehaviour::Misbehaviour(_) => UpdateKind::SubmitMisbehaviour,
46    };
47    let client_message = msg.client_message();
48
49    let client_exec_ctx = ctx.get_client_execution_context();
50
51    let client_state = client_exec_ctx.client_state(&client_id)?;
52
53    let found_misbehaviour =
54        client_state.check_for_misbehaviour(client_exec_ctx, &client_id, client_message.clone())?;
55
56    if found_misbehaviour {
57        client_state.update_state_on_misbehaviour(client_exec_ctx, &client_id, client_message)?;
58
59        let event = IbcEvent::ClientMisbehaviour(ClientMisbehaviour::new(
60            client_id,
61            client_state.client_type(),
62        ));
63        ctx.emit_ibc_event(IbcEvent::Message(MessageEvent::Client))?;
64        ctx.emit_ibc_event(event)?;
65    } else {
66        if !matches!(update_kind, UpdateKind::UpdateClient) {
67            return Err(ClientError::FailedToHandleMisbehaviour {
68                description: "misbehaviour submitted, but none found".to_string(),
69            });
70        }
71
72        let header = client_message;
73
74        let consensus_heights =
75            client_state.update_state(client_exec_ctx, &client_id, header.clone())?;
76
77        {
78            let event = {
79                let consensus_height = consensus_heights.first().ok_or(
80                    HostError::missing_state("updated height in client update state"),
81                )?;
82
83                IbcEvent::UpdateClient(UpdateClient::new(
84                    client_id,
85                    client_state.client_type(),
86                    *consensus_height,
87                    consensus_heights,
88                    header.to_vec(),
89                ))
90            };
91            ctx.emit_ibc_event(IbcEvent::Message(MessageEvent::Client))?;
92            ctx.emit_ibc_event(event)?;
93        }
94    }
95
96    Ok(())
97}