ibc_client_cw/
handlers.rs

1use core::fmt::Display;
2
3use cosmwasm_std::{to_json_binary, Binary};
4use ibc_core::client::context::prelude::*;
5use ibc_core::host::types::error::DecodingError;
6use ibc_core::host::types::path::ClientConsensusStatePath;
7use ibc_core::primitives::proto::Any;
8use prost::Message;
9
10use crate::api::ClientType;
11use crate::context::Context;
12use crate::types::{
13    CheckForMisbehaviourMsg, CheckForMisbehaviourResponse, ContractError, ContractResult,
14    InstantiateMsg, QueryMsg, StatusMsg, StatusResponse, SudoMsg, TimestampAtHeightResponse,
15    UpdateStateMsg, UpdateStateOnMisbehaviourMsg, VerifyClientMessageMsg,
16    VerifyClientMessageResponse, VerifyMembershipMsg, VerifyNonMembershipMsg,
17    VerifyUpgradeAndUpdateStateMsg,
18};
19
20impl<'a, C: ClientType<'a>> Context<'a, C>
21where
22    <C::ClientState as TryFrom<Any>>::Error: Display,
23    <C::ConsensusState as TryFrom<Any>>::Error: Display,
24{
25    /// Instantiates a new client with the given [`InstantiateMsg`] message.
26    pub fn instantiate(&mut self, msg: InstantiateMsg) -> Result<Binary, ContractError> {
27        let any = Any::decode(&mut msg.client_state.as_slice())?;
28
29        let client_state =
30            C::ClientState::try_from(any).map_err(DecodingError::invalid_raw_data)?;
31
32        let any_consensus_state = Any::decode(&mut msg.consensus_state.as_slice())?;
33
34        self.set_checksum(msg.checksum);
35
36        client_state.initialise(self, &self.client_id(), any_consensus_state)?;
37
38        Ok(to_json_binary(&ContractResult::success())?)
39    }
40
41    /// Executes the given [`SudoMsg`].
42    pub fn sudo(&mut self, msg: SudoMsg) -> Result<Binary, ContractError> {
43        let client_id = self.client_id();
44
45        if let SudoMsg::MigrateClientStore(_) = msg {
46            self.set_subject_prefix();
47        };
48
49        let client_state = self.client_state(&client_id)?;
50
51        let result = match msg {
52            SudoMsg::UpdateState(msg_raw) => {
53                let msg = UpdateStateMsg::try_from(msg_raw)?;
54
55                let heights = client_state.update_state(self, &client_id, msg.client_message)?;
56
57                ContractResult::success().heights(heights)
58            }
59            SudoMsg::UpdateStateOnMisbehaviour(msg_raw) => {
60                let msg = UpdateStateOnMisbehaviourMsg::try_from(msg_raw)?;
61
62                client_state.update_state_on_misbehaviour(self, &client_id, msg.client_message)?;
63
64                ContractResult::success()
65            }
66            SudoMsg::VerifyMembership(msg) => {
67                let msg = VerifyMembershipMsg::try_from(msg)?;
68
69                let client_cons_state_path = ClientConsensusStatePath::new(
70                    self.client_id(),
71                    msg.height.revision_number(),
72                    msg.height.revision_height(),
73                );
74
75                let consensus_state = self.consensus_state(&client_cons_state_path)?;
76
77                client_state.verify_membership_raw(
78                    &msg.prefix,
79                    &msg.proof,
80                    consensus_state.root(),
81                    msg.path,
82                    msg.value,
83                )?;
84
85                ContractResult::success()
86            }
87            SudoMsg::VerifyNonMembership(msg) => {
88                let msg = VerifyNonMembershipMsg::try_from(msg)?;
89
90                let client_cons_state_path = ClientConsensusStatePath::new(
91                    client_id.clone(),
92                    msg.height.revision_number(),
93                    msg.height.revision_height(),
94                );
95
96                let consensus_state = self.consensus_state(&client_cons_state_path)?;
97
98                client_state.verify_non_membership_raw(
99                    &msg.prefix,
100                    &msg.proof,
101                    consensus_state.root(),
102                    msg.path,
103                )?;
104
105                ContractResult::success()
106            }
107            SudoMsg::VerifyUpgradeAndUpdateState(msg) => {
108                let msg = VerifyUpgradeAndUpdateStateMsg::try_from(msg)?;
109
110                let client_cons_state_path = ClientConsensusStatePath::new(
111                    client_id.clone(),
112                    client_state.latest_height().revision_number(),
113                    client_state.latest_height().revision_height(),
114                );
115
116                let consensus_state = self.consensus_state(&client_cons_state_path)?;
117
118                client_state.verify_upgrade_client(
119                    msg.upgrade_client_state.clone(),
120                    msg.upgrade_consensus_state.clone(),
121                    msg.proof_upgrade_client,
122                    msg.proof_upgrade_consensus_state,
123                    consensus_state.root(),
124                )?;
125
126                client_state.update_state_on_upgrade(
127                    self,
128                    &client_id,
129                    msg.upgrade_client_state,
130                    msg.upgrade_consensus_state,
131                )?;
132
133                ContractResult::success()
134            }
135            SudoMsg::MigrateClientStore(_) => {
136                self.set_substitute_prefix();
137                let substitute_client_state = self.client_state(&client_id)?;
138                let substitute_consensus_state =
139                    self.consensus_state(&ClientConsensusStatePath::new(
140                        client_id.clone(),
141                        substitute_client_state.latest_height().revision_number(),
142                        substitute_client_state.latest_height().revision_height(),
143                    ))?;
144
145                let substitute_client_state_any = substitute_client_state.into();
146
147                self.set_subject_prefix();
148                client_state.check_substitute(self, substitute_client_state_any.clone())?;
149
150                client_state.update_on_recovery(
151                    self,
152                    &self.client_id(),
153                    substitute_client_state_any,
154                    substitute_consensus_state.into(),
155                )?;
156
157                ContractResult::success()
158            }
159        };
160        Ok(to_json_binary(&result)?)
161    }
162
163    /// Queries the client with the given [`QueryMsg`] message.
164    pub fn query(&self, msg: QueryMsg) -> Result<Binary, ContractError> {
165        let client_id = self.client_id();
166
167        let client_state = self.client_state(&client_id)?;
168
169        match msg {
170            QueryMsg::Status(StatusMsg {}) => {
171                let status = client_state.status(self, &client_id)?;
172                to_json_binary(&StatusResponse { status })
173            }
174            QueryMsg::TimestampAtHeight(msg) => {
175                let client_cons_state_path = ClientConsensusStatePath::new(
176                    client_id,
177                    msg.height.revision_number(),
178                    msg.height.revision_height(),
179                );
180
181                let consensus_state = self.consensus_state(&client_cons_state_path)?;
182                let timestamp = consensus_state.timestamp()?.nanoseconds();
183                to_json_binary(&TimestampAtHeightResponse { timestamp })
184            }
185            QueryMsg::VerifyClientMessage(msg) => {
186                let msg = VerifyClientMessageMsg::try_from(msg)?;
187
188                let is_valid = client_state
189                    .verify_client_message(self, &client_id, msg.client_message)
190                    .is_ok();
191                to_json_binary(&VerifyClientMessageResponse { is_valid })
192            }
193            QueryMsg::CheckForMisbehaviour(msg) => {
194                let msg = CheckForMisbehaviourMsg::try_from(msg)?;
195
196                let found_misbehaviour =
197                    client_state.check_for_misbehaviour(self, &client_id, msg.client_message)?;
198                to_json_binary(&CheckForMisbehaviourResponse { found_misbehaviour })
199            }
200        }
201        .map_err(Into::into)
202    }
203}