ibc_testkit/testapp/ibc/core/
core_ctx.rs

1//! Implementation of a global context mock. Used in testing handlers of all IBC modules.
2
3use core::fmt::Debug;
4use core::time::Duration;
5
6use basecoin_store::context::{ProvableStore, Store};
7use basecoin_store::types::Height as StoreHeight;
8use ibc::core::channel::types::channel::{ChannelEnd, IdentifiedChannelEnd};
9use ibc::core::channel::types::commitment::{AcknowledgementCommitment, PacketCommitment};
10use ibc::core::channel::types::packet::{PacketState, Receipt};
11use ibc::core::client::context::consensus_state::ConsensusState;
12use ibc::core::client::types::error::ClientError;
13use ibc::core::client::types::Height;
14use ibc::core::commitment_types::commitment::CommitmentPrefix;
15use ibc::core::commitment_types::merkle::MerkleProof;
16use ibc::core::connection::types::{ConnectionEnd, IdentifiedConnectionEnd};
17use ibc::core::handler::types::events::IbcEvent;
18use ibc::core::host::types::error::HostError;
19use ibc::core::host::types::identifiers::{ClientId, ConnectionId, Sequence};
20use ibc::core::host::types::path::{
21    AckPath, ChannelEndPath, ClientConnectionPath, CommitmentPath, ConnectionPath,
22    NextChannelSequencePath, NextClientSequencePath, NextConnectionSequencePath, Path, ReceiptPath,
23    SeqAckPath, SeqRecvPath, SeqSendPath,
24};
25use ibc::core::host::{ClientStateRef, ConsensusStateRef, ExecutionContext, ValidationContext};
26use ibc::core::primitives::prelude::*;
27use ibc::core::primitives::{Signer, Timestamp};
28use ibc::primitives::ToVec;
29use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof;
30use ibc_query::core::context::{ProvableContext, QueryContext};
31
32use super::types::{MockIbcStore, DEFAULT_BLOCK_TIME_SECS};
33use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState};
34
35impl<S> ValidationContext for MockIbcStore<S>
36where
37    S: ProvableStore + Debug,
38{
39    type V = Self;
40    type HostClientState = AnyClientState;
41    type HostConsensusState = AnyConsensusState;
42
43    fn host_height(&self) -> Result<Height, HostError> {
44        Height::new(*self.revision_number.lock(), self.store.current_height())
45            .map_err(HostError::invalid_state)
46    }
47
48    fn host_timestamp(&self) -> Result<Timestamp, HostError> {
49        let host_height = self.host_height()?;
50        let host_cons_state = self.host_consensus_state(&host_height)?;
51        let timestamp = host_cons_state
52            .timestamp()
53            .map_err(HostError::invalid_state)?;
54        Ok(timestamp)
55    }
56
57    fn client_counter(&self) -> Result<u64, HostError> {
58        self.client_counter
59            .get(StoreHeight::Pending, &NextClientSequencePath)
60            .ok_or(HostError::missing_state("client counter"))
61    }
62
63    fn host_consensus_state(&self, height: &Height) -> Result<Self::HostConsensusState, HostError> {
64        let consensus_states_binding = self.host_consensus_states.lock();
65
66        consensus_states_binding
67            .get(&height.revision_height())
68            .cloned()
69            .ok_or(HostError::missing_state(
70                ClientError::MissingLocalConsensusState(*height),
71            ))
72    }
73
74    fn validate_self_client(
75        &self,
76        client_state_of_host_on_counterparty: Self::HostClientState,
77    ) -> Result<(), HostError> {
78        if client_state_of_host_on_counterparty.is_frozen() {
79            return Err(HostError::invalid_state("client unexpectedly frozen"));
80        }
81
82        let latest_height = self.host_height()?;
83
84        let self_revision_number = latest_height.revision_number();
85        if self_revision_number
86            != client_state_of_host_on_counterparty
87                .latest_height()
88                .revision_number()
89        {
90            return Err(HostError::invalid_state(format!(
91                "client is not in the same revision as the chain; expected `{}`, actual `{}`",
92                self_revision_number,
93                client_state_of_host_on_counterparty
94                    .latest_height()
95                    .revision_number()
96            )));
97        }
98
99        let host_current_height = latest_height.increment();
100        if client_state_of_host_on_counterparty.latest_height() >= host_current_height {
101            return Err(HostError::invalid_state(
102                format!(
103                    "counterparty client state: client latest height `{}` should be less than chain height `{}`",
104                    client_state_of_host_on_counterparty.latest_height(),
105                    host_current_height
106                ),
107            ));
108        }
109
110        Ok(())
111    }
112
113    fn connection_end(&self, conn_id: &ConnectionId) -> Result<ConnectionEnd, HostError> {
114        self.connection_end_store
115            .get(StoreHeight::Pending, &ConnectionPath::new(conn_id))
116            .ok_or(HostError::missing_state(format!(
117                "connection end for connection `{}`",
118                conn_id.clone()
119            )))
120    }
121
122    fn commitment_prefix(&self) -> CommitmentPrefix {
123        // this is prefix of ibc store
124        // using a dummy prefix as in our mock context
125        CommitmentPrefix::from(b"mock".to_vec())
126    }
127
128    fn connection_counter(&self) -> Result<u64, HostError> {
129        self.conn_counter
130            .get(StoreHeight::Pending, &NextConnectionSequencePath)
131            .ok_or(HostError::missing_state("connection counter"))
132    }
133
134    fn channel_end(&self, channel_end_path: &ChannelEndPath) -> Result<ChannelEnd, HostError> {
135        self.channel_end_store
136            .get(StoreHeight::Pending, channel_end_path)
137            .ok_or(HostError::missing_state(format!(
138                "channel `{}` in port `{}`",
139                channel_end_path.1.clone(),
140                channel_end_path.0.clone()
141            )))
142    }
143
144    fn get_next_sequence_send(&self, seq_send_path: &SeqSendPath) -> Result<Sequence, HostError> {
145        self.send_sequence_store
146            .get(StoreHeight::Pending, seq_send_path)
147            .ok_or(HostError::failed_to_retrieve("send packet sequence"))
148    }
149
150    fn get_next_sequence_recv(&self, seq_recv_path: &SeqRecvPath) -> Result<Sequence, HostError> {
151        self.recv_sequence_store
152            .get(StoreHeight::Pending, seq_recv_path)
153            .ok_or(HostError::failed_to_retrieve("recv packet sequence"))
154    }
155
156    fn get_next_sequence_ack(&self, seq_ack_path: &SeqAckPath) -> Result<Sequence, HostError> {
157        self.ack_sequence_store
158            .get(StoreHeight::Pending, seq_ack_path)
159            .ok_or(HostError::failed_to_retrieve("ack packet sequence"))
160    }
161
162    fn get_packet_commitment(
163        &self,
164        commitment_path: &CommitmentPath,
165    ) -> Result<PacketCommitment, HostError> {
166        self.packet_commitment_store
167            .get(StoreHeight::Pending, commitment_path)
168            .ok_or(HostError::failed_to_retrieve("packet commitment"))
169    }
170
171    fn get_packet_receipt(&self, receipt_path: &ReceiptPath) -> Result<Receipt, HostError> {
172        if self
173            .packet_receipt_store
174            .is_path_set(StoreHeight::Pending, receipt_path)
175        {
176            Ok(Receipt::Ok)
177        } else {
178            Ok(Receipt::None)
179        }
180    }
181
182    fn get_packet_acknowledgement(
183        &self,
184        ack_path: &AckPath,
185    ) -> Result<AcknowledgementCommitment, HostError> {
186        self.packet_ack_store
187            .get(StoreHeight::Pending, ack_path)
188            .ok_or(HostError::failed_to_retrieve(format!(
189                "packet acknowledgment `{}`",
190                ack_path.sequence
191            )))
192    }
193
194    /// Returns a counter of the number of channel ids that have been created thus far.
195    /// The value of this counter should increase only via the
196    /// `ChannelKeeper::increase_channel_counter` method.
197    fn channel_counter(&self) -> Result<u64, HostError> {
198        self.channel_counter
199            .get(StoreHeight::Pending, &NextChannelSequencePath)
200            .ok_or(HostError::failed_to_retrieve("channel counter"))
201    }
202
203    /// Returns the maximum expected time per block
204    fn max_expected_time_per_block(&self) -> Duration {
205        Duration::from_secs(DEFAULT_BLOCK_TIME_SECS)
206    }
207
208    fn validate_message_signer(&self, _signer: &Signer) -> Result<(), HostError> {
209        Ok(())
210    }
211
212    fn get_client_validation_context(&self) -> &Self::V {
213        self
214    }
215}
216
217/// Trait to provide proofs in gRPC service blanket implementations.
218impl<S> ProvableContext for MockIbcStore<S>
219where
220    S: ProvableStore + Debug,
221{
222    /// Returns the proof for the given [`Height`] and [`Path`]
223    fn get_proof(&self, height: Height, path: &Path) -> Option<Vec<u8>> {
224        self.store
225            .get_proof(height.revision_height().into(), &path.to_string().into())
226            .map(|path_proof| {
227                let ibc_commitment_proof = self
228                    .ibc_commiment_proofs
229                    .lock()
230                    .get(&height.revision_height())
231                    .expect("proof exists")
232                    .clone();
233
234                RawMerkleProof::from(MerkleProof {
235                    proofs: vec![path_proof, ibc_commitment_proof],
236                })
237            })
238            .map(|p| p.to_vec())
239    }
240}
241
242/// Trait to complete the gRPC service blanket implementations.
243impl<S> QueryContext for MockIbcStore<S>
244where
245    S: ProvableStore + Debug,
246{
247    /// Returns the list of all client states.
248    fn client_states(&self) -> Result<Vec<(ClientId, ClientStateRef<Self>)>, HostError> {
249        let path = "clients".to_owned().into();
250
251        self.client_state_store
252            .get_keys(&path)
253            .into_iter()
254            .filter_map(|path| {
255                if let Ok(Path::ClientState(client_path)) = path.try_into() {
256                    Some(client_path)
257                } else {
258                    None
259                }
260            })
261            .map(|client_state_path| {
262                let client_state = self
263                    .client_state_store
264                    .get(StoreHeight::Pending, &client_state_path)
265                    .ok_or_else(|| {
266                        HostError::failed_to_retrieve(format!(
267                            "client state from path `{}`",
268                            client_state_path.0.clone()
269                        ))
270                    })?;
271                Ok((client_state_path.0, client_state))
272            })
273            .collect()
274    }
275
276    /// Returns the list of all consensus states of the given client.
277    fn consensus_states(
278        &self,
279        client_id: &ClientId,
280    ) -> Result<Vec<(Height, ConsensusStateRef<Self>)>, HostError> {
281        let path = format!("clients/{}/consensusStates", client_id).into();
282
283        self.consensus_state_store
284            .get_keys(&path)
285            .into_iter()
286            .filter_map(|path| {
287                if let Ok(Path::ClientConsensusState(consensus_path)) = path.try_into() {
288                    Some(consensus_path)
289                } else {
290                    None
291                }
292            })
293            .map(|consensus_path| {
294                let height = Height::new(
295                    consensus_path.revision_number,
296                    consensus_path.revision_height,
297                )
298                .map_err(HostError::invalid_state)?;
299                let client_state = self
300                    .consensus_state_store
301                    .get(StoreHeight::Pending, &consensus_path)
302                    .ok_or(HostError::failed_to_retrieve(format!(
303                        "consensus state for client `{}` at height `{}`",
304                        consensus_path.client_id, height,
305                    )))?;
306                Ok((height, client_state))
307            })
308            .collect()
309    }
310
311    /// Returns the list of heights at which the consensus state of the given client was updated.
312    fn consensus_state_heights(&self, client_id: &ClientId) -> Result<Vec<Height>, HostError> {
313        let path = format!("clients/{}/consensusStates", client_id).into();
314
315        self.consensus_state_store
316            .get_keys(&path)
317            .into_iter()
318            .filter_map(|path| {
319                if let Ok(Path::ClientConsensusState(consensus_path)) = path.try_into() {
320                    Some(consensus_path)
321                } else {
322                    None
323                }
324            })
325            .map(|consensus_path| {
326                Height::new(
327                    consensus_path.revision_number,
328                    consensus_path.revision_height,
329                )
330                .map_err(HostError::invalid_state)
331            })
332            .collect::<Result<Vec<_>, _>>()
333    }
334
335    /// Returns all the IBC connection ends of a chain.
336    fn connection_ends(&self) -> Result<Vec<IdentifiedConnectionEnd>, HostError> {
337        let path = "connections".to_owned().into();
338
339        self.connection_end_store
340            .get_keys(&path)
341            .into_iter()
342            .filter_map(|path| {
343                if let Ok(Path::Connection(connection_path)) = path.try_into() {
344                    Some(connection_path)
345                } else {
346                    None
347                }
348            })
349            .map(|connection_path| {
350                let connection_end = self
351                    .connection_end_store
352                    .get(StoreHeight::Pending, &connection_path)
353                    .ok_or_else(|| {
354                        HostError::failed_to_retrieve(format!(
355                            "connection end `{}`",
356                            connection_path.0.clone()
357                        ))
358                    })?;
359                Ok(IdentifiedConnectionEnd {
360                    connection_id: connection_path.0,
361                    connection_end,
362                })
363            })
364            .collect()
365    }
366
367    /// Returns all the IBC connection ends associated with a client.
368    fn client_connection_ends(&self, client_id: &ClientId) -> Result<Vec<ConnectionId>, HostError> {
369        let client_connection_path = ClientConnectionPath::new(client_id.clone());
370
371        Ok(self
372            .connection_ids_store
373            .get(StoreHeight::Pending, &client_connection_path)
374            .unwrap_or_default())
375    }
376
377    /// Returns all the IBC channel ends of a chain.
378    fn channel_ends(&self) -> Result<Vec<IdentifiedChannelEnd>, HostError> {
379        let path = "channelEnds".to_owned().into();
380
381        self.channel_end_store
382            .get_keys(&path)
383            .into_iter()
384            .filter_map(|path| {
385                if let Ok(Path::ChannelEnd(channel_path)) = path.try_into() {
386                    Some(channel_path)
387                } else {
388                    None
389                }
390            })
391            .map(|channel_path| {
392                let channel_end = self
393                    .channel_end_store
394                    .get(StoreHeight::Pending, &channel_path)
395                    .ok_or_else(|| {
396                        HostError::failed_to_retrieve(format!(
397                            "channel `{}` with port `{}`",
398                            channel_path.1.clone(),
399                            channel_path.0.clone()
400                        ))
401                    })?;
402                Ok(IdentifiedChannelEnd {
403                    port_id: channel_path.0,
404                    channel_id: channel_path.1,
405                    channel_end,
406                })
407            })
408            .collect()
409    }
410
411    /// Returns all the packet commitments associated with a channel.
412    fn packet_commitments(
413        &self,
414        channel_end_path: &ChannelEndPath,
415    ) -> Result<Vec<PacketState>, HostError> {
416        let path = format!(
417            "commitments/ports/{}/channels/{}/sequences",
418            channel_end_path.0, channel_end_path.1
419        )
420        .into();
421
422        self.packet_commitment_store
423            .get_keys(&path)
424            .into_iter()
425            .filter_map(|path| {
426                if let Ok(Path::Commitment(commitment_path)) = path.try_into() {
427                    Some(commitment_path)
428                } else {
429                    None
430                }
431            })
432            .filter(|commitment_path| {
433                self.packet_commitment_store
434                    .get(StoreHeight::Pending, commitment_path)
435                    .is_some()
436            })
437            .map(|commitment_path| {
438                self.get_packet_commitment(&commitment_path)
439                    .map(|packet| PacketState {
440                        seq: commitment_path.sequence,
441                        port_id: commitment_path.port_id,
442                        chan_id: commitment_path.channel_id,
443                        data: packet.as_ref().into(),
444                    })
445            })
446            .collect::<Result<Vec<_>, _>>()
447    }
448
449    /// Returns the acknowledged packets associated with a channel.
450    ///
451    /// Takes a sequence list as an argument.
452    /// If the list set is empty, it returns all acknowledged packets.
453    fn packet_acknowledgements(
454        &self,
455        channel_end_path: &ChannelEndPath,
456        sequences: impl ExactSizeIterator<Item = Sequence>,
457    ) -> Result<Vec<PacketState>, HostError> {
458        let collected_paths: Vec<_> = if sequences.len() == 0 {
459            // if sequences is empty, return all the acks
460            let ack_path_prefix = format!(
461                "acks/ports/{}/channels/{}/sequences",
462                channel_end_path.0, channel_end_path.1
463            )
464            .into();
465
466            self.packet_ack_store
467                .get_keys(&ack_path_prefix)
468                .into_iter()
469                .filter_map(|path| {
470                    if let Ok(Path::Ack(ack_path)) = path.try_into() {
471                        Some(ack_path)
472                    } else {
473                        None
474                    }
475                })
476                .collect()
477        } else {
478            sequences
479                .into_iter()
480                .map(|seq| AckPath::new(&channel_end_path.0, &channel_end_path.1, seq))
481                .collect()
482        };
483
484        collected_paths
485            .into_iter()
486            .filter(|ack_path| {
487                self.packet_ack_store
488                    .get(StoreHeight::Pending, ack_path)
489                    .is_some()
490            })
491            .map(|ack_path| {
492                self.get_packet_acknowledgement(&ack_path)
493                    .map(|packet| PacketState {
494                        seq: ack_path.sequence,
495                        port_id: ack_path.port_id,
496                        chan_id: ack_path.channel_id,
497                        data: packet.as_ref().into(),
498                    })
499            })
500            .collect::<Result<Vec<_>, _>>()
501    }
502
503    /// Returns the unreceived IBC packets associated with a channel and sequences.
504    ///
505    /// Takes a sequence list as an argument.
506    fn unreceived_packets(
507        &self,
508        channel_end_path: &ChannelEndPath,
509        sequences: impl ExactSizeIterator<Item = Sequence>,
510    ) -> Result<Vec<Sequence>, HostError> {
511        // QUESTION. Currently only works for unordered channels; ordered channels
512        // don't use receipts. However, ibc-go does it this way. Investigate if
513        // this query only ever makes sense on unordered channels.
514
515        Ok(sequences
516            .into_iter()
517            .map(|seq| ReceiptPath::new(&channel_end_path.0, &channel_end_path.1, seq))
518            .filter(|receipt_path| {
519                self.packet_receipt_store
520                    .get(StoreHeight::Pending, receipt_path)
521                    .is_none()
522            })
523            .map(|receipts_path| receipts_path.sequence)
524            .collect())
525    }
526
527    /// Returns all the unreceived IBC acknowledgements associated with a channel and sequences.
528    ///
529    /// Takes a sequence list as an argument.
530    /// If the list is empty, it Returns all the unreceived acks.
531    fn unreceived_acks(
532        &self,
533        channel_end_path: &ChannelEndPath,
534        sequences: impl ExactSizeIterator<Item = Sequence>,
535    ) -> Result<Vec<Sequence>, HostError> {
536        let collected_paths: Vec<_> = if sequences.len() == 0 {
537            // if sequences is empty, return all the acks
538            let commitment_path_prefix = format!(
539                "commitments/ports/{}/channels/{}/sequences",
540                channel_end_path.0, channel_end_path.1
541            )
542            .into();
543
544            self.packet_commitment_store
545                .get_keys(&commitment_path_prefix)
546                .into_iter()
547                .filter_map(|path| {
548                    if let Ok(Path::Commitment(commitment_path)) = path.try_into() {
549                        Some(commitment_path)
550                    } else {
551                        None
552                    }
553                })
554                .collect()
555        } else {
556            sequences
557                .into_iter()
558                .map(|seq| CommitmentPath::new(&channel_end_path.0, &channel_end_path.1, seq))
559                .collect()
560        };
561
562        Ok(collected_paths
563            .into_iter()
564            .filter(|commitment_path: &CommitmentPath| -> bool {
565                self.packet_commitment_store
566                    .get(StoreHeight::Pending, commitment_path)
567                    .is_some()
568            })
569            .map(|commitment_path| commitment_path.sequence)
570            .collect())
571    }
572}
573
574impl<S> ExecutionContext for MockIbcStore<S>
575where
576    S: ProvableStore + Debug,
577{
578    type E = Self;
579
580    fn get_client_execution_context(&mut self) -> &mut Self::E {
581        self
582    }
583
584    /// Called upon client creation.
585    /// Increases the counter, that keeps track of how many clients have been created.
586    fn increase_client_counter(&mut self) -> Result<(), HostError> {
587        let current_sequence = self
588            .client_counter
589            .get(StoreHeight::Pending, &NextClientSequencePath)
590            .ok_or(HostError::failed_to_retrieve("client counter"))?;
591
592        self.client_counter
593            .set(NextClientSequencePath, current_sequence + 1)
594            .map_err(|e| HostError::failed_to_store(format!("client counter: {e:?}")))?;
595
596        Ok(())
597    }
598
599    /// Stores the given connection_end at path
600    fn store_connection(
601        &mut self,
602        connection_path: &ConnectionPath,
603        connection_end: ConnectionEnd,
604    ) -> Result<(), HostError> {
605        self.connection_end_store
606            .set(connection_path.clone(), connection_end)
607            .map_err(|e| HostError::failed_to_store(format!("connection end: {e:?}")))?;
608        Ok(())
609    }
610
611    /// Stores the given connection_id at a path associated with the client_id.
612    fn store_connection_to_client(
613        &mut self,
614        client_connection_path: &ClientConnectionPath,
615        conn_id: ConnectionId,
616    ) -> Result<(), HostError> {
617        let mut conn_ids: Vec<ConnectionId> = self
618            .connection_ids_store
619            .get(StoreHeight::Pending, client_connection_path)
620            .unwrap_or_default();
621        conn_ids.push(conn_id);
622        self.connection_ids_store
623            .set(client_connection_path.clone(), conn_ids)
624            .map_err(|e| HostError::failed_to_store(format!("connection IDs: {e:?}")))?;
625        Ok(())
626    }
627
628    /// Called upon connection identifier creation (Init or Try process).
629    /// Increases the counter, that keeps track of how many connections have been created.
630    fn increase_connection_counter(&mut self) -> Result<(), HostError> {
631        let current_sequence = self
632            .conn_counter
633            .get(StoreHeight::Pending, &NextConnectionSequencePath)
634            .ok_or(HostError::failed_to_retrieve("connection counter"))?;
635
636        self.conn_counter
637            .set(NextConnectionSequencePath, current_sequence + 1)
638            .map_err(|e| HostError::failed_to_store(format!("connection counter: {e:?}")))?;
639
640        Ok(())
641    }
642
643    fn store_packet_commitment(
644        &mut self,
645        commitment_path: &CommitmentPath,
646        commitment: PacketCommitment,
647    ) -> Result<(), HostError> {
648        self.packet_commitment_store
649            .set(commitment_path.clone(), commitment)
650            .map_err(|e| HostError::failed_to_store(format!("packet commitment: {e:?}")))?;
651        Ok(())
652    }
653
654    fn delete_packet_commitment(
655        &mut self,
656        commitment_path: &CommitmentPath,
657    ) -> Result<(), HostError> {
658        self.packet_commitment_store.delete(commitment_path.clone());
659        Ok(())
660    }
661
662    fn store_packet_receipt(
663        &mut self,
664        receipt_path: &ReceiptPath,
665        _receipt: Receipt,
666    ) -> Result<(), HostError> {
667        self.packet_receipt_store
668            .set_path(receipt_path.clone())
669            .map_err(|e| HostError::failed_to_store(format!("packet receipt: {e:?}")))?;
670        Ok(())
671    }
672
673    fn store_packet_acknowledgement(
674        &mut self,
675        ack_path: &AckPath,
676        ack_commitment: AcknowledgementCommitment,
677    ) -> Result<(), HostError> {
678        self.packet_ack_store
679            .set(ack_path.clone(), ack_commitment)
680            .map_err(|e| HostError::failed_to_store(format!("packet acknowledgment: {e:?}")))?;
681        Ok(())
682    }
683
684    fn delete_packet_acknowledgement(&mut self, ack_path: &AckPath) -> Result<(), HostError> {
685        self.packet_ack_store.delete(ack_path.clone());
686        Ok(())
687    }
688
689    fn store_channel(
690        &mut self,
691        channel_end_path: &ChannelEndPath,
692        channel_end: ChannelEnd,
693    ) -> Result<(), HostError> {
694        self.channel_end_store
695            .set(channel_end_path.clone(), channel_end)
696            .map_err(|e| HostError::failed_to_store(format!("channel: {e:?}")))?;
697        Ok(())
698    }
699
700    fn store_next_sequence_send(
701        &mut self,
702        seq_send_path: &SeqSendPath,
703        seq: Sequence,
704    ) -> Result<(), HostError> {
705        self.send_sequence_store
706            .set(seq_send_path.clone(), seq)
707            .map_err(|e| HostError::failed_to_store(format!("next send sequence: {e:?}")))?;
708        Ok(())
709    }
710
711    fn store_next_sequence_recv(
712        &mut self,
713        seq_recv_path: &SeqRecvPath,
714        seq: Sequence,
715    ) -> Result<(), HostError> {
716        self.recv_sequence_store
717            .set(seq_recv_path.clone(), seq)
718            .map_err(|e| HostError::failed_to_store(format!("next recv sequence: {e:?}")))?;
719        Ok(())
720    }
721
722    fn store_next_sequence_ack(
723        &mut self,
724        seq_ack_path: &SeqAckPath,
725        seq: Sequence,
726    ) -> Result<(), HostError> {
727        self.ack_sequence_store
728            .set(seq_ack_path.clone(), seq)
729            .map_err(|e| {
730                HostError::failed_to_store(format!("failed to store ack sequence: {e:?}"))
731            })?;
732        Ok(())
733    }
734
735    fn increase_channel_counter(&mut self) -> Result<(), HostError> {
736        let current_sequence = self
737            .channel_counter
738            .get(StoreHeight::Pending, &NextChannelSequencePath)
739            .ok_or(HostError::failed_to_retrieve("channel counter"))?;
740
741        self.channel_counter
742            .set(NextChannelSequencePath, current_sequence + 1)
743            .map_err(|e| HostError::failed_to_store(format!("channel counter: {e:?}")))?;
744        Ok(())
745    }
746
747    fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), HostError> {
748        self.events.lock().push(event);
749        Ok(())
750    }
751
752    fn log_message(&mut self, message: String) -> Result<(), HostError> {
753        self.logs.lock().push(message);
754        Ok(())
755    }
756}