1use 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 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 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 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
217impl<S> ProvableContext for MockIbcStore<S>
219where
220 S: ProvableStore + Debug,
221{
222 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
242impl<S> QueryContext for MockIbcStore<S>
244where
245 S: ProvableStore + Debug,
246{
247 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 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 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 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 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 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 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 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 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 fn unreceived_packets(
507 &self,
508 channel_end_path: &ChannelEndPath,
509 sequences: impl ExactSizeIterator<Item = Sequence>,
510 ) -> Result<Vec<Sequence>, HostError> {
511 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 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 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 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 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 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 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}