ibc_core_client/handler/
upgrade_client.rs

1//! Protocol logic specific to processing ICS2 messages of type `MsgUpgradeAnyClient`.
2//!
3use ibc_core_client_context::prelude::*;
4use ibc_core_client_types::error::ClientError;
5use ibc_core_client_types::events::UpgradeClient;
6use ibc_core_client_types::msgs::MsgUpgradeClient;
7use ibc_core_handler_types::events::{IbcEvent, MessageEvent};
8use ibc_core_host::types::path::ClientConsensusStatePath;
9use ibc_core_host::{ExecutionContext, ValidationContext};
10use ibc_primitives::prelude::*;
11
12pub fn validate<Ctx>(ctx: &Ctx, msg: MsgUpgradeClient) -> Result<(), ClientError>
13where
14    Ctx: ValidationContext,
15{
16    let MsgUpgradeClient {
17        client_id, signer, ..
18    } = msg;
19
20    ctx.validate_message_signer(&signer)?;
21
22    let client_val_ctx = ctx.get_client_validation_context();
23
24    // Read the current latest client state from the host chain store.
25    let old_client_state = client_val_ctx.client_state(&client_id)?;
26
27    // Check if the client is active.
28    old_client_state
29        .status(client_val_ctx, &client_id)?
30        .verify_is_active()?;
31
32    // Read the latest consensus state from the host chain store.
33    let old_client_cons_state_path = ClientConsensusStatePath::new(
34        client_id.clone(),
35        old_client_state.latest_height().revision_number(),
36        old_client_state.latest_height().revision_height(),
37    );
38    let old_consensus_state = client_val_ctx.consensus_state(&old_client_cons_state_path)?;
39
40    // Validate the upgraded client state and consensus state and verify proofs against the root
41    old_client_state.verify_upgrade_client(
42        msg.upgraded_client_state.clone(),
43        msg.upgraded_consensus_state,
44        msg.proof_upgrade_client,
45        msg.proof_upgrade_consensus_state,
46        old_consensus_state.root(),
47    )?;
48
49    Ok(())
50}
51
52pub fn execute<Ctx>(ctx: &mut Ctx, msg: MsgUpgradeClient) -> Result<(), ClientError>
53where
54    Ctx: ExecutionContext,
55{
56    let MsgUpgradeClient { client_id, .. } = msg;
57
58    let client_exec_ctx = ctx.get_client_execution_context();
59
60    let old_client_state = client_exec_ctx.client_state(&client_id)?;
61
62    let latest_height = old_client_state.update_state_on_upgrade(
63        client_exec_ctx,
64        &client_id,
65        msg.upgraded_client_state.clone(),
66        msg.upgraded_consensus_state,
67    )?;
68
69    let event = IbcEvent::UpgradeClient(UpgradeClient::new(
70        client_id,
71        old_client_state.client_type(),
72        latest_height,
73    ));
74    ctx.emit_ibc_event(IbcEvent::Message(MessageEvent::Client))?;
75    ctx.emit_ibc_event(event)?;
76
77    Ok(())
78}