1pub mod mock;
2pub mod tendermint;
3
4use core::fmt::Debug;
5use core::ops::Add;
6use core::time::Duration;
7
8use ibc::core::client::context::consensus_state::ConsensusState;
9use ibc::core::client::types::Height;
10use ibc::core::primitives::prelude::*;
11use ibc::core::primitives::Timestamp;
12use ibc::primitives::proto::Any;
13
14pub use self::mock::MockHost;
15pub use self::tendermint::TendermintHost;
16use crate::testapp::ibc::clients::{AnyClientState, AnyConsensusState};
17
18pub type HostClientState<H> = <H as TestHost>::ClientState;
19pub type HostBlock<H> = <H as TestHost>::Block;
20pub type HostBlockParams<H> = <H as TestHost>::BlockParams;
21pub type HostLightClientParams<H> = <H as TestHost>::LightClientParams;
22pub type HostHeader<H> = <HostBlock<H> as TestBlock>::Header;
23pub type HostConsensusState<H> = <HostHeader<H> as TestHeader>::ConsensusState;
24
25pub trait TestHost: Default + Debug + Sized {
27 type Block: TestBlock;
29
30 type ClientState: Into<AnyClientState> + Debug;
32
33 type BlockParams: Debug + Default;
35
36 type LightClientParams: Debug + Default;
38
39 fn history(&self) -> &Vec<Self::Block>;
41
42 fn is_empty(&self) -> bool {
44 self.history().is_empty()
45 }
46
47 fn latest_height(&self) -> Height {
49 self.latest_block().height()
50 }
51
52 fn latest_block(&self) -> Self::Block {
54 self.history().last().cloned().expect("no error")
55 }
56
57 fn get_block(&self, target_height: &Height) -> Option<Self::Block> {
59 self.history()
60 .get(target_height.revision_height() as usize - 1)
61 .cloned() }
63
64 fn push_block(&mut self, block: Self::Block);
66
67 fn commit_block(
69 &mut self,
70 commitment_root: Vec<u8>,
71 block_time: Duration,
72 params: &Self::BlockParams,
73 ) {
74 let latest_block = self.latest_block();
75
76 let height = TestBlock::height(&latest_block)
77 .increment()
78 .revision_height();
79 let timestamp = TestBlock::timestamp(&latest_block)
80 .add(block_time)
81 .expect("Never fails");
82
83 let new_block = self.generate_block(commitment_root, height, timestamp, params);
84
85 self.push_block(new_block);
87 }
88
89 fn generate_block(
91 &self,
92 commitment_root: Vec<u8>,
93 height: u64,
94 timestamp: Timestamp,
95 params: &Self::BlockParams,
96 ) -> Self::Block;
97
98 fn generate_client_state(
100 &self,
101 latest_height: &Height,
102 params: &Self::LightClientParams,
103 ) -> Self::ClientState;
104
105 fn validate(&self) -> Result<(), String> {
106 let latest_height = self.latest_height();
108 let mut current_height = Height::min(latest_height.revision_number());
109
110 while current_height <= latest_height {
111 if current_height != self.get_block(¤t_height).expect("no error").height() {
112 return Err("block height does not match".to_owned());
113 }
114 current_height = current_height.increment();
115 }
116 Ok(())
117 }
118}
119
120pub trait TestBlock: Clone + Debug {
122 type Header: TestHeader;
124
125 fn height(&self) -> Height;
127
128 fn timestamp(&self) -> Timestamp;
130
131 fn into_header_with_trusted(self, trusted_block: &Self) -> Self::Header;
133
134 fn into_header(self) -> Self::Header {
137 self.clone().into_header_with_trusted(&self)
138 }
139}
140
141pub trait TestHeader: Clone + Debug + Into<Any> {
144 type ConsensusState: ConsensusState + Into<AnyConsensusState> + From<Self> + Clone + Debug;
146
147 fn height(&self) -> Height;
149
150 fn timestamp(&self) -> Timestamp;
152
153 fn into_consensus_state(self) -> Self::ConsensusState {
155 Self::ConsensusState::from(self)
156 }
157}