ibc_testkit/hosts/
tendermint.rs1use core::str::FromStr;
2
3use bon::Builder;
4use ibc::clients::tendermint::client_state::ClientState;
5use ibc::clients::tendermint::consensus_state::ConsensusState;
6use ibc::clients::tendermint::types::proto::v1::Header as RawHeader;
7use ibc::clients::tendermint::types::{Header, TENDERMINT_HEADER_TYPE_URL};
8use ibc::core::client::types::Height;
9use ibc::core::host::types::identifiers::ChainId;
10use ibc::core::primitives::prelude::*;
11use ibc::core::primitives::Timestamp;
12use ibc::primitives::proto::Any;
13use ibc::primitives::{IntoHostTime, IntoTimestamp, ToVec};
14use tendermint::block::Header as TmHeader;
15use tendermint::validator::Set as ValidatorSet;
16use tendermint_testgen::light_block::TmLightBlock;
17use tendermint_testgen::{
18 Generator, Header as TestgenHeader, LightBlock as TestgenLightBlock,
19 Validator as TestgenValidator,
20};
21
22use crate::fixtures::clients::tendermint::ClientStateConfig;
23use crate::hosts::{TestBlock, TestHeader, TestHost};
24
25#[derive(Debug, Builder)]
27pub struct TendermintHost {
28 #[builder(default = ChainId::new("mock-0").expect("Never fails"))]
30 pub chain_id: ChainId,
31 #[builder(default)]
33 pub history: Vec<TmLightBlock>,
34}
35
36impl Default for TendermintHost {
37 fn default() -> Self {
38 Self::builder().build()
39 }
40}
41
42impl TestHost for TendermintHost {
43 type Block = TmLightBlock;
44 type BlockParams = BlockParams;
45 type LightClientParams = ClientStateConfig;
46 type ClientState = ClientState;
47
48 fn history(&self) -> &Vec<Self::Block> {
49 &self.history
50 }
51
52 fn push_block(&mut self, block: Self::Block) {
53 self.history.push(block);
54 }
55
56 fn generate_block(
57 &self,
58 commitment_root: Vec<u8>,
59 height: u64,
60 timestamp: Timestamp,
61 params: &Self::BlockParams,
62 ) -> Self::Block {
63 TestgenLightBlock::new_default_with_header(
64 TestgenHeader::new(¶ms.validators)
65 .app_hash(commitment_root.try_into().expect("infallible"))
66 .height(height)
67 .chain_id(self.chain_id.as_str())
68 .next_validators(¶ms.next_validators)
69 .time(timestamp.into_host_time().expect("Never fails")),
70 )
71 .validators(¶ms.validators)
72 .next_validators(¶ms.next_validators)
73 .generate()
74 .expect("Never fails")
75 }
76
77 fn generate_client_state(
78 &self,
79 latest_height: &Height,
80 params: &Self::LightClientParams,
81 ) -> Self::ClientState {
82 let client_state = ClientStateConfig::builder()
83 .trusting_period(params.trusting_period)
84 .max_clock_drift(params.max_clock_drift)
85 .unbonding_period(params.unbonding_period)
86 .proof_specs(params.proof_specs.clone())
87 .build()
88 .into_client_state(
89 self.chain_id.clone(),
90 self.get_block(latest_height)
91 .expect("block exists")
92 .height(),
93 )
94 .expect("never fails");
95
96 client_state.inner().validate().expect("never fails");
97
98 client_state
99 }
100}
101
102impl TestBlock for TmLightBlock {
103 type Header = TendermintHeader;
104
105 fn height(&self) -> Height {
106 Height::new(
107 ChainId::from_str(self.signed_header.header.chain_id.as_str())
108 .expect("Never fails")
109 .revision_number(),
110 self.signed_header.header.height.value(),
111 )
112 .expect("Never fails")
113 }
114
115 fn timestamp(&self) -> Timestamp {
116 self.signed_header
117 .header
118 .time
119 .into_timestamp()
120 .expect("Never fails")
121 }
122
123 fn into_header_with_trusted(self, trusted_block: &Self) -> Self::Header {
124 let mut header = TendermintHeader::from(self.clone());
125 header.set_trusted_height(trusted_block.height());
126 header.set_trusted_next_validators_set(trusted_block.validators.clone());
127 header
128 }
129}
130
131#[derive(Debug, Builder)]
132pub struct BlockParams {
133 pub validators: Vec<TestgenValidator>,
134 pub next_validators: Vec<TestgenValidator>,
135}
136
137impl BlockParams {
138 pub fn from_validator_history(validator_history: Vec<Vec<TestgenValidator>>) -> Vec<Self> {
139 validator_history
140 .windows(2)
141 .map(|vals| {
142 Self::builder()
143 .validators(vals[0].clone())
144 .next_validators(vals[1].clone())
145 .build()
146 })
147 .collect()
148 }
149}
150
151impl Default for BlockParams {
152 fn default() -> Self {
153 Self::builder()
154 .validators(vec![
155 TestgenValidator::new("1").voting_power(50),
156 TestgenValidator::new("2").voting_power(50),
157 ])
158 .next_validators(vec![
159 TestgenValidator::new("1").voting_power(50),
160 TestgenValidator::new("2").voting_power(50),
161 ])
162 .build()
163 }
164}
165
166#[derive(Debug, Clone)]
169pub struct TendermintHeader(Header);
170
171impl TendermintHeader {
172 pub fn set_trusted_height(&mut self, trusted_height: Height) {
173 self.0.trusted_height = trusted_height
174 }
175
176 pub fn set_trusted_next_validators_set(&mut self, trusted_next_validator_set: ValidatorSet) {
177 self.0.trusted_next_validator_set = trusted_next_validator_set
178 }
179
180 pub fn header(&self) -> &TmHeader {
181 &self.0.signed_header.header
182 }
183}
184
185impl TestHeader for TendermintHeader {
186 type ConsensusState = ConsensusState;
187
188 fn height(&self) -> Height {
189 Height::new(
190 ChainId::from_str(self.0.signed_header.header.chain_id.as_str())
191 .expect("Never fails")
192 .revision_number(),
193 self.0.signed_header.header.height.value(),
194 )
195 .expect("Never fails")
196 }
197
198 fn timestamp(&self) -> Timestamp {
199 self.0
200 .signed_header
201 .header
202 .time
203 .into_timestamp()
204 .expect("Never fails")
205 }
206}
207
208impl From<TendermintHeader> for Header {
209 fn from(header: TendermintHeader) -> Self {
210 header.0
211 }
212}
213
214impl From<TendermintHeader> for ConsensusState {
215 fn from(header: TendermintHeader) -> Self {
216 header.0.signed_header.header.into()
217 }
218}
219
220impl From<TmLightBlock> for TendermintHeader {
221 fn from(block: TmLightBlock) -> Self {
222 let trusted_height = block.height();
223
224 let TmLightBlock {
225 signed_header,
226 validators: validator_set,
227 ..
228 } = block;
229
230 let trusted_next_validator_set = validator_set.clone();
231
232 Self(Header {
234 signed_header,
235 validator_set,
236 trusted_height,
237 trusted_next_validator_set,
238 })
239 }
240}
241
242impl From<TendermintHeader> for Any {
243 fn from(value: TendermintHeader) -> Self {
244 Self {
245 type_url: TENDERMINT_HEADER_TYPE_URL.to_string(),
246 value: RawHeader::from(value.0).to_vec(),
247 }
248 }
249}