ibc_core_client/handler/
update_client.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//! Protocol logic specific to processing ICS2 messages of type `MsgUpdateAnyClient`.

use ibc_core_client_context::prelude::*;
use ibc_core_client_types::error::ClientError;
use ibc_core_client_types::events::{ClientMisbehaviour, UpdateClient};
use ibc_core_client_types::msgs::MsgUpdateOrMisbehaviour;
use ibc_core_client_types::UpdateKind;
use ibc_core_handler_types::events::{IbcEvent, MessageEvent};
use ibc_core_host::types::error::HostError;
use ibc_core_host::{ExecutionContext, ValidationContext};
use ibc_primitives::prelude::*;
use ibc_primitives::ToVec;

pub fn validate<Ctx>(ctx: &Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ClientError>
where
    Ctx: ValidationContext,
{
    ctx.validate_message_signer(msg.signer())?;

    let client_id = msg.client_id().clone();

    let client_val_ctx = ctx.get_client_validation_context();

    // Read client state from the host chain store. The client should already exist.
    let client_state = client_val_ctx.client_state(&client_id)?;

    client_state
        .status(client_val_ctx, &client_id)?
        .verify_is_active()?;

    let client_message = msg.client_message();

    client_state.verify_client_message(client_val_ctx, &client_id, client_message)?;

    Ok(())
}

pub fn execute<Ctx>(ctx: &mut Ctx, msg: MsgUpdateOrMisbehaviour) -> Result<(), ClientError>
where
    Ctx: ExecutionContext,
{
    let client_id = msg.client_id().clone();
    let update_kind = match msg {
        MsgUpdateOrMisbehaviour::UpdateClient(_) => UpdateKind::UpdateClient,
        MsgUpdateOrMisbehaviour::Misbehaviour(_) => UpdateKind::SubmitMisbehaviour,
    };
    let client_message = msg.client_message();

    let client_exec_ctx = ctx.get_client_execution_context();

    let client_state = client_exec_ctx.client_state(&client_id)?;

    let found_misbehaviour =
        client_state.check_for_misbehaviour(client_exec_ctx, &client_id, client_message.clone())?;

    if found_misbehaviour {
        client_state.update_state_on_misbehaviour(client_exec_ctx, &client_id, client_message)?;

        let event = IbcEvent::ClientMisbehaviour(ClientMisbehaviour::new(
            client_id,
            client_state.client_type(),
        ));
        ctx.emit_ibc_event(IbcEvent::Message(MessageEvent::Client))?;
        ctx.emit_ibc_event(event)?;
    } else {
        if !matches!(update_kind, UpdateKind::UpdateClient) {
            return Err(ClientError::FailedToHandleMisbehaviour {
                description: "misbehaviour submitted, but none found".to_string(),
            });
        }

        let header = client_message;

        let consensus_heights =
            client_state.update_state(client_exec_ctx, &client_id, header.clone())?;

        {
            let event = {
                let consensus_height = consensus_heights.first().ok_or(
                    HostError::missing_state("updated height in client update state"),
                )?;

                IbcEvent::UpdateClient(UpdateClient::new(
                    client_id,
                    client_state.client_type(),
                    *consensus_height,
                    consensus_heights,
                    header.to_vec(),
                ))
            };
            ctx.emit_ibc_event(IbcEvent::Message(MessageEvent::Client))?;
            ctx.emit_ibc_event(event)?;
        }
    }

    Ok(())
}