tendermint_testgen/
light_chain.rs1use tendermint::{
2 block::{self, Height},
3 chain::Info,
4};
5
6use crate::{light_block::LightBlock, Generator};
7
8#[derive(Clone, Debug)]
9pub struct LightChain {
10 pub info: Info,
11 pub light_blocks: Vec<LightBlock>,
12}
13
14impl LightChain {
15 pub fn new(info: Info, light_blocks: Vec<LightBlock>) -> Self {
16 LightChain { info, light_blocks }
17 }
18
19 pub fn default_with_length(num: u64) -> Self {
22 let mut last_block = LightBlock::new_default(1);
23 let mut light_blocks: Vec<LightBlock> = vec![last_block.clone()];
24
25 for _i in 2..=num {
26 last_block = last_block.next();
28 light_blocks.push(last_block.clone());
29 }
30
31 let id = last_block.chain_id().parse().unwrap();
32 let height = last_block.height().try_into().unwrap();
33 let last_block_hash = last_block.header.map(|h| h.generate().unwrap().hash());
34 let last_block_id = last_block_hash.map(|hash| block::Id {
35 hash,
36 part_set_header: Default::default(),
37 });
38
39 let info = Info {
40 id,
41 height,
42 last_block_id,
43 time: None,
45 };
46
47 Self::new(info, light_blocks)
48 }
49
50 pub fn advance_chain(&mut self) -> &LightBlock {
52 let last_light_block = self
53 .light_blocks
54 .last()
55 .expect("Cannot find testgen light block");
56
57 let new_light_block = last_light_block.next();
58
59 self.info.height = Height::try_from(new_light_block.height())
60 .expect("failed to convert from u64 to Height");
61
62 let last_block_id_hash = new_light_block
63 .header
64 .as_ref()
65 .expect("missing header in new light block")
66 .generate()
67 .expect("failed to generate header")
68 .hash();
69
70 self.info.last_block_id = Some(block::Id {
71 hash: last_block_id_hash,
72 part_set_header: Default::default(),
73 });
74
75 self.light_blocks.push(new_light_block);
76 self.light_blocks.last().unwrap() }
78
79 pub fn block(&self, target_height: u64) -> Option<&LightBlock> {
82 self.light_blocks
83 .iter()
84 .find(|lb| lb.height() == target_height)
85 }
86
87 pub fn block_mut(&mut self, target_height: u64) -> Option<&mut LightBlock> {
90 self.light_blocks
91 .iter_mut()
92 .find(|lb| lb.height() == target_height)
93 }
94
95 pub fn latest_block(&self) -> &LightBlock {
97 self.light_blocks
98 .last()
99 .expect("cannot find last light block")
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_advance_chain() {
109 let mut light_chain = LightChain::default_with_length(1);
110 let advance_1 = light_chain.advance_chain();
111
112 assert_eq!(2, advance_1.height());
113 assert_eq!(2, light_chain.info.height.value());
114
115 let advance_2 = light_chain.advance_chain();
116
117 assert_eq!(3, advance_2.height());
118 assert_eq!(3, light_chain.info.height.value());
119 }
120
121 #[test]
122 fn test_block() {
123 let mut light_chain = LightChain::default_with_length(1);
124 let first_block = light_chain.block(1);
125 assert_eq!(1, first_block.unwrap().height());
126
127 light_chain.advance_chain();
128 let second_block = light_chain.block(2);
129 assert_eq!(2, second_block.unwrap().height());
130 }
131
132 #[test]
133 fn test_latest_block() {
134 let mut light_chain = LightChain::default_with_length(1);
135 let first_block = light_chain.latest_block();
136 assert_eq!(1, first_block.height());
137
138 light_chain.advance_chain();
139 let second_block = light_chain.latest_block();
140 assert_eq!(2, second_block.height());
141 }
142
143 #[test]
144 fn test_light_chain_with_length() {
145 const CHAIN_HEIGHT: u64 = 10;
146
147 let chain = LightChain::default_with_length(CHAIN_HEIGHT);
148
149 let blocks = chain
150 .light_blocks
151 .into_iter()
152 .flat_map(|lb| lb.generate())
153 .collect::<Vec<_>>();
154
155 assert_eq!(blocks.len(), chain.info.height.value() as usize);
157 assert_eq!(blocks.len(), CHAIN_HEIGHT as usize);
158
159 let first_block = blocks.first().unwrap();
160 let last_block = blocks.last().unwrap();
161
162 assert_eq!(first_block.signed_header.header.height.value(), 1);
164
165 assert!(first_block.signed_header.header.last_block_id.is_none());
167
168 assert_eq!(last_block.signed_header.header.height, chain.info.height);
170
171 for i in 1..blocks.len() {
172 let prv = &blocks[i - 1];
173 let cur = &blocks[i];
174
175 assert_eq!(
177 cur.signed_header.header.height.value(),
178 prv.signed_header.header.height.value() + 1
179 );
180
181 assert_eq!(
183 cur.signed_header.header.last_block_id.map(|lbi| lbi.hash),
184 Some(prv.signed_header.header.hash())
185 );
186 }
187 }
188}