ibc_core_client_context/
client_state.rs

1//! Defines `ClientState`, the core type to be implemented by light clients
2
3use ibc_core_client_types::error::ClientError;
4use ibc_core_client_types::{Height, Status};
5use ibc_core_commitment_types::commitment::{
6    CommitmentPrefix, CommitmentProofBytes, CommitmentRoot,
7};
8use ibc_core_host_types::identifiers::{ClientId, ClientType};
9use ibc_core_host_types::path::{Path, PathBytes};
10use ibc_primitives::prelude::*;
11use ibc_primitives::proto::Any;
12use ibc_primitives::Timestamp;
13
14use crate::context::{ClientExecutionContext, ClientValidationContext};
15use crate::Convertible;
16
17/// `ClientState` methods needed in both validation and execution.
18///
19/// They do not require access to a client `ValidationContext` nor
20/// `ExecutionContext`.
21pub trait ClientStateCommon: Convertible<Any> {
22    /// Performs basic validation on the `consensus_state`.
23    ///
24    /// Notably, an implementation should verify that it can properly
25    /// deserialize the object into the expected format.
26    fn verify_consensus_state(
27        &self,
28        consensus_state: Any,
29        host_timestamp: &Timestamp,
30    ) -> Result<(), ClientError>;
31
32    /// Type of client associated with this state (eg. Tendermint)
33    fn client_type(&self) -> ClientType;
34
35    /// The latest height the client was updated to
36    fn latest_height(&self) -> Height;
37
38    /// Validate that the client is at a sufficient height
39    fn validate_proof_height(&self, proof_height: Height) -> Result<(), ClientError>;
40
41    /// Verify the upgraded client and consensus states and validate proofs
42    /// against the given root.
43    ///
44    /// NOTE: proof heights are not included, as upgrade to a new revision is
45    /// expected to pass only on the last height committed by the current
46    /// revision. Clients are responsible for ensuring that the planned last
47    /// height of the current revision is somehow encoded in the proof
48    /// verification process. This is to ensure that no premature upgrades
49    /// occur, since upgrade plans committed to by the counterparty may be
50    /// cancelled or modified before the last planned height.
51    fn verify_upgrade_client(
52        &self,
53        upgraded_client_state: Any,
54        upgraded_consensus_state: Any,
55        proof_upgrade_client: CommitmentProofBytes,
56        proof_upgrade_consensus_state: CommitmentProofBytes,
57        root: &CommitmentRoot,
58    ) -> Result<(), ClientError>;
59
60    /// Serializes a given path object into a raw path bytes.
61    ///
62    /// This method provides essential information for IBC modules, enabling
63    /// them to understand how path serialization is performed on the chain this
64    /// light client represents it before passing the path bytes to either
65    /// `verify_membership_raw()` or `verify_non_membership_raw()`.
66    fn serialize_path(&self, path: Path) -> Result<PathBytes, ClientError>;
67
68    /// Verifies a proof of the existence of a value at a given raw path bytes.
69    fn verify_membership_raw(
70        &self,
71        prefix: &CommitmentPrefix,
72        proof: &CommitmentProofBytes,
73        root: &CommitmentRoot,
74        path: PathBytes,
75        value: Vec<u8>,
76    ) -> Result<(), ClientError>;
77
78    /// Verifies a proof of the existence of a value at a given path object.
79    fn verify_membership(
80        &self,
81        prefix: &CommitmentPrefix,
82        proof: &CommitmentProofBytes,
83        root: &CommitmentRoot,
84        path: Path,
85        value: Vec<u8>,
86    ) -> Result<(), ClientError> {
87        let path_bytes = self.serialize_path(path)?;
88        self.verify_membership_raw(prefix, proof, root, path_bytes, value)
89    }
90
91    /// Verifies the absence of a given proof at a given raw path bytes.
92    fn verify_non_membership_raw(
93        &self,
94        prefix: &CommitmentPrefix,
95        proof: &CommitmentProofBytes,
96        root: &CommitmentRoot,
97        path: PathBytes,
98    ) -> Result<(), ClientError>;
99
100    /// Verifies the absence of a given proof at a given path object.
101    fn verify_non_membership(
102        &self,
103        prefix: &CommitmentPrefix,
104        proof: &CommitmentProofBytes,
105        root: &CommitmentRoot,
106        path: Path,
107    ) -> Result<(), ClientError> {
108        let path_bytes = self.serialize_path(path)?;
109        self.verify_non_membership_raw(prefix, proof, root, path_bytes)
110    }
111}
112
113/// `ClientState` methods which require access to the client's validation
114/// context
115///
116/// The generic type `V` enables light client developers to expand the set of
117/// methods available under the [`ClientValidationContext`] trait and use them in
118/// their implementation for validating a client state transition.
119///
120/// ```ignore
121/// impl<V> ClientStateValidation<V> for MyClientState
122/// where
123///     V: ClientValidationContext + MyValidationContext,
124/// {
125///   // `MyValidationContext` methods available
126/// }
127///
128/// trait MyValidationContext {
129///   // My Context methods
130/// }
131/// ```
132pub trait ClientStateValidation<V>: ClientStateCommon
133where
134    V: ClientValidationContext,
135{
136    /// verify_client_message must verify a client_message. A client_message
137    /// could be a Header, Misbehaviour. It must handle each type of
138    /// client_message appropriately. Calls to check_for_misbehaviour,
139    /// update_state, and update_state_on_misbehaviour will assume that the
140    /// content of the client_message has been verified and can be trusted. An
141    /// error should be returned if the client_message fails to verify.
142    fn verify_client_message(
143        &self,
144        ctx: &V,
145        client_id: &ClientId,
146        client_message: Any,
147    ) -> Result<(), ClientError>;
148
149    /// Checks for evidence of a misbehaviour in Header or Misbehaviour type. It
150    /// assumes the client_message has already been verified.
151    fn check_for_misbehaviour(
152        &self,
153        ctx: &V,
154        client_id: &ClientId,
155        client_message: Any,
156    ) -> Result<bool, ClientError>;
157
158    /// Returns the status of the client. Only Active clients are allowed to process packets.
159    fn status(&self, ctx: &V, client_id: &ClientId) -> Result<Status, ClientError>;
160
161    /// Verifies whether the calling (subject) client state matches the substitute
162    /// client state for the purposes of client recovery.
163    ///
164    /// Note that this validation function does not need to perform *all* of the
165    /// validation steps necessary to confirm client recovery. Some checks, such
166    /// as checking that the subject client state's latest height < the substitute
167    /// client's latest height, as well as checking that the subject client is
168    /// inactive and that the substitute client is active, are performed by the
169    /// `validate` function in the `recover_client` module at the ics02-client
170    /// level.
171    ///
172    /// Returns `Ok` if the subject and substitute client states match, `Err` otherwise.
173    fn check_substitute(&self, ctx: &V, substitute_client_state: Any) -> Result<(), ClientError>;
174}
175
176/// `ClientState` methods which require access to the client's
177/// `ExecutionContext`.
178///
179/// The generic type `E` enables light client developers to expand the set of
180/// methods available under the [`ClientExecutionContext`] trait and use them in
181/// their implementation for executing a client state transition.
182pub trait ClientStateExecution<E>: ClientStateValidation<E>
183where
184    E: ClientExecutionContext,
185{
186    /// Initialises the client with the initial client and consensus states.
187    ///
188    /// Most clients will want to call `E::store_client_state` and
189    /// `E::store_consensus_state`.
190    fn initialise(
191        &self,
192        ctx: &mut E,
193        client_id: &ClientId,
194        consensus_state: Any,
195    ) -> Result<(), ClientError>;
196
197    /// Updates and stores as necessary any associated information for an IBC
198    /// client, such as the ClientState and corresponding ConsensusState. Upon
199    /// successful update, a list of consensus heights is returned. It assumes
200    /// the client_message has already been verified.
201    ///
202    /// Note that `header` is the field associated with `UpdateKind::UpdateClient`.
203    ///
204    /// Post-condition: on success, the return value MUST contain at least one
205    /// height.
206    fn update_state(
207        &self,
208        ctx: &mut E,
209        client_id: &ClientId,
210        header: Any,
211    ) -> Result<Vec<Height>, ClientError>;
212
213    /// update_state_on_misbehaviour should perform appropriate state changes on
214    /// a client state given that misbehaviour has been detected and verified
215    fn update_state_on_misbehaviour(
216        &self,
217        ctx: &mut E,
218        client_id: &ClientId,
219        client_message: Any,
220    ) -> Result<(), ClientError>;
221
222    /// Update the client state and consensus state in the store with the upgraded ones.
223    fn update_state_on_upgrade(
224        &self,
225        ctx: &mut E,
226        client_id: &ClientId,
227        upgraded_client_state: Any,
228        upgraded_consensus_state: Any,
229    ) -> Result<Height, ClientError>;
230
231    /// Update the subject client using the `substitute_client_state` in response
232    /// to a successful client recovery.
233    fn update_on_recovery(
234        &self,
235        ctx: &mut E,
236        subject_client_id: &ClientId,
237        substitute_client_state: Any,
238        substitute_consensus_state: Any,
239    ) -> Result<(), ClientError>;
240}
241
242/// Primary client trait. Defines all the methods that clients must implement.
243///
244/// `ClientState` is broken up into 3 separate traits to avoid needing to use
245/// fully qualified syntax for every method call (see ADR 7 for more details).
246/// One only needs to implement [`ClientStateCommon`], [`ClientStateValidation`]
247/// and [`ClientStateExecution`]; a blanket implementation will automatically
248/// implement `ClientState`.
249///
250/// Refer to [`ClientStateValidation`] and [`ClientStateExecution`] to learn
251/// more about what both generic parameters represent.
252pub trait ClientState<V: ClientValidationContext, E: ClientExecutionContext>:
253    Send + Sync + ClientStateCommon + ClientStateValidation<V> + ClientStateExecution<E>
254{
255}
256
257impl<V: ClientValidationContext, E: ClientExecutionContext, T> ClientState<V, E> for T where
258    T: Send + Sync + ClientStateCommon + ClientStateValidation<V> + ClientStateExecution<E>
259{
260}