penumbra_sdk_ibc/component/msg_handler/
create_client.rs

1use anyhow::{Context, Result};
2use async_trait::async_trait;
3use cnidarium::StateWrite;
4use ibc_types::{
5    core::client::{events::CreateClient, msgs::MsgCreateClient, ClientId},
6    lightclients::tendermint::client_type,
7};
8
9use crate::component::{
10    client::{ConsensusStateWriteExt as _, StateReadExt as _, StateWriteExt as _},
11    client_counter::ClientCounter,
12    ics02_validation, HostInterface, MsgHandler,
13};
14
15#[async_trait]
16impl MsgHandler for MsgCreateClient {
17    async fn check_stateless<H>(&self) -> Result<()> {
18        client_state_is_tendermint(self)?;
19        consensus_state_is_tendermint(self)?;
20
21        Ok(())
22    }
23
24    // execute IBC CreateClient.
25    //
26    //  we compute the client's ID (a concatenation of a monotonically increasing integer, the
27    //  number of clients on Penumbra, and the client type) and commit the following to our state:
28    // - client type
29    // - consensus state
30    // - processed time and height
31    async fn try_execute<S: StateWrite, AH, HI: HostInterface>(&self, mut state: S) -> Result<()> {
32        tracing::debug!(msg = ?self);
33        let client_state =
34            ics02_validation::get_tendermint_client_state(self.client_state.clone())?;
35
36        // get the current client counter
37        let id_counter = state.client_counter().await?;
38        let client_id = ClientId::new(client_type(), id_counter.0)?;
39
40        tracing::info!("creating client {:?}", client_id);
41
42        let consensus_state =
43            ics02_validation::get_tendermint_consensus_state(self.consensus_state.clone())?;
44
45        // store the client data
46        state.put_client(&client_id, client_state.clone());
47
48        // store the genesis consensus state
49        state
50            .put_verified_consensus_state::<HI>(
51                client_state.latest_height(),
52                client_id.clone(),
53                consensus_state,
54            )
55            .await
56            .context("unable to put verified consensus state")?;
57
58        // increment client counter
59        let counter = state.client_counter().await.unwrap_or(ClientCounter(0));
60        state.put_client_counter(ClientCounter(counter.0 + 1));
61
62        state.record(
63            CreateClient {
64                client_id: client_id.clone(),
65                client_type: client_type(),
66                consensus_height: client_state.latest_height(),
67            }
68            .into(),
69        );
70        Ok(())
71    }
72}
73fn client_state_is_tendermint(msg: &MsgCreateClient) -> anyhow::Result<()> {
74    if ics02_validation::is_tendermint_client_state(&msg.client_state) {
75        Ok(())
76    } else {
77        Err(anyhow::anyhow!(
78            "MsgCreateClient: not a tendermint client state"
79        ))
80    }
81}
82
83fn consensus_state_is_tendermint(msg: &MsgCreateClient) -> anyhow::Result<()> {
84    if ics02_validation::is_tendermint_consensus_state(&msg.consensus_state) {
85        Ok(())
86    } else {
87        Err(anyhow::anyhow!(
88            "MsgCreateClient: not a tendermint consensus state"
89        ))
90    }
91}