diem_types/
epoch_change.rs1#![forbid(unsafe_code)]
9
10use crate::ledger_info::{LedgerInfo, LedgerInfoWithSignatures};
11use anyhow::{ensure, format_err, Result};
12#[cfg(any(test, feature = "fuzzing"))]
13use proptest::{collection::vec, prelude::*};
14use serde::{Deserialize, Serialize};
15use std::fmt::Debug;
16
17pub trait Verifier: Debug + Send + Sync {
21 fn verify(&self, ledger_info: &LedgerInfoWithSignatures) -> Result<()>;
23
24 fn epoch_change_verification_required(&self, epoch: u64) -> bool;
28
29 fn is_ledger_info_stale(&self, ledger_info: &LedgerInfo) -> bool;
39}
40
41#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
42pub struct EpochChangeProof {
45 pub ledger_info_with_sigs: Vec<LedgerInfoWithSignatures>,
46 pub more: bool,
47}
48impl EpochChangeProof {
49 pub fn new(
50 ledger_info_with_sigs: Vec<LedgerInfoWithSignatures>, more: bool,
51 ) -> Self {
52 Self {
53 ledger_info_with_sigs,
54 more,
55 }
56 }
57
58 pub fn epoch(&self) -> Result<u64> {
61 self.ledger_info_with_sigs
62 .first()
63 .map(|li| li.ledger_info().epoch())
64 .ok_or_else(|| format_err!("Empty EpochChangeProof"))
65 }
66
67 pub fn verify(
77 &self, verifier: &dyn Verifier,
78 ) -> Result<&LedgerInfoWithSignatures> {
79 ensure!(
80 !self.ledger_info_with_sigs.is_empty(),
81 "The EpochChangeProof is empty"
82 );
83 ensure!(
84 !verifier.is_ledger_info_stale(
85 self.ledger_info_with_sigs.last().unwrap().ledger_info()
86 ),
87 "The EpochChangeProof is stale as our verifier is already ahead \
88 of the entire EpochChangeProof"
89 );
90 let mut verifier_ref = verifier;
91
92 for ledger_info_with_sigs in self
93 .ledger_info_with_sigs
94 .iter()
95 .skip_while(|&ledger_info_with_sigs| {
116 verifier
117 .is_ledger_info_stale(ledger_info_with_sigs.ledger_info())
118 })
119 {
120 verifier_ref.verify(ledger_info_with_sigs)?;
123 verifier_ref = ledger_info_with_sigs
127 .ledger_info()
128 .next_epoch_state()
129 .ok_or_else(|| {
130 format_err!("LedgerInfo doesn't carry a ValidatorSet")
131 })?;
132 }
133
134 Ok(self.ledger_info_with_sigs.last().unwrap())
135 }
136
137 pub fn get_all_ledger_infos(&self) -> Vec<LedgerInfoWithSignatures> {
138 self.ledger_info_with_sigs.clone()
139 }
140}
141
142#[cfg(any(test, feature = "fuzzing"))]
143impl Arbitrary for EpochChangeProof {
144 type Parameters = ();
145 type Strategy = BoxedStrategy<Self>;
146
147 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
148 (vec(any::<LedgerInfoWithSignatures>(), 0..10), any::<bool>())
149 .prop_map(|(ledger_infos_with_sigs, more)| {
150 Self::new(ledger_infos_with_sigs, more)
151 })
152 .boxed()
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use crate::{
160 block_info::BlockInfo, epoch_state::EpochState, waypoint::Waypoint,
161 };
162
163 #[test]
164 fn verify_epoch_change_proof() {
165 use crate::{
166 ledger_info::LedgerInfo,
167 validator_verifier::random_validator_verifier,
168 };
169 use diem_crypto::hash::HashValue;
170 use std::collections::BTreeMap;
171
172 let all_epoch: Vec<u64> = (1..=10).collect();
173 let mut valid_ledger_info = vec![];
174 let mut validator_verifier = vec![];
175
176 let (mut current_signers, mut current_verifier) =
179 random_validator_verifier(1, None, true);
180 let mut current_version = 123;
181 for epoch in &all_epoch {
182 validator_verifier.push(current_verifier.clone());
183 let (next_signers, next_verifier) =
184 random_validator_verifier((*epoch + 1) as usize, None, true);
185 let epoch_state =
186 EpochState::new(*epoch + 1, next_verifier.clone(), vec![]);
187 let ledger_info = LedgerInfo::new(
188 BlockInfo::new(
189 *epoch,
190 0,
191 HashValue::zero(),
192 HashValue::zero(),
193 current_version,
194 0,
195 Some(epoch_state),
196 None,
197 ),
198 HashValue::zero(),
199 );
200 let signatures = current_signers
201 .iter()
202 .map(|s| (s.author(), s.sign(&ledger_info)))
203 .collect();
204 valid_ledger_info
205 .push(LedgerInfoWithSignatures::new(ledger_info, signatures));
206 current_signers = next_signers;
207 current_verifier = next_verifier;
208 current_version += 1;
209 }
210
211 let proof_1 = EpochChangeProof::new(
213 valid_ledger_info.clone(),
214 false,
215 );
216 assert!(proof_1
217 .verify(&EpochState::new(
218 all_epoch[0],
219 validator_verifier[0].clone(),
220 vec![]
221 ))
222 .is_ok());
223
224 let proof_2 = EpochChangeProof::new(
225 valid_ledger_info[2..5].to_vec(),
226 false,
227 );
228 assert!(proof_2
229 .verify(&EpochState::new(
230 all_epoch[2],
231 validator_verifier[2].clone(),
232 vec![]
233 ))
234 .is_ok());
235
236 assert!(proof_1
238 .verify(&EpochState::new(
239 all_epoch[4],
240 validator_verifier[4].clone(),
241 vec![]
242 ))
243 .is_ok());
244
245 let proof_3 = EpochChangeProof::new(vec![], false);
247 assert!(proof_3
248 .verify(&EpochState::new(
249 all_epoch[0],
250 validator_verifier[0].clone(),
251 vec![]
252 ))
253 .is_err());
254
255 let mut list = valid_ledger_info[3..5].to_vec();
257 list.extend_from_slice(&valid_ledger_info[8..9]);
258 let proof_4 = EpochChangeProof::new(list, false);
259 assert!(proof_4
260 .verify(&EpochState::new(
261 all_epoch[3],
262 validator_verifier[3].clone(),
263 vec![]
264 ))
265 .is_err());
266
267 let mut list = valid_ledger_info.clone();
269 list.reverse();
270 let proof_5 = EpochChangeProof::new(list, false);
271 assert!(proof_5
272 .verify(&EpochState::new(
273 all_epoch[9],
274 validator_verifier[9].clone(),
275 vec![]
276 ))
277 .is_err());
278
279 let proof_6 = EpochChangeProof::new(
281 vec![LedgerInfoWithSignatures::new(
282 valid_ledger_info[0].ledger_info().clone(),
283 BTreeMap::new(),
284 )],
285 false,
286 );
287 assert!(proof_6
288 .verify(&EpochState::new(
289 all_epoch[0],
290 validator_verifier[0].clone(),
291 vec![]
292 ))
293 .is_err());
294
295 let waypoint_for_1_to_2 =
298 Waypoint::new_epoch_boundary(valid_ledger_info[0].ledger_info())
299 .unwrap();
300 assert!(proof_1.verify(&waypoint_for_1_to_2).is_ok());
301
302 let waypoint_for_5_to_6 =
304 Waypoint::new_epoch_boundary(valid_ledger_info[4].ledger_info())
305 .unwrap();
306 assert!(proof_1.verify(&waypoint_for_5_to_6).is_ok());
307
308 let waypoint_for_3_to_4 =
310 Waypoint::new_epoch_boundary(valid_ledger_info[2].ledger_info())
311 .unwrap();
312 let proof_7 = EpochChangeProof::new(
313 valid_ledger_info[4..8].to_vec(),
314 false,
315 );
316 assert!(proof_7.verify(&waypoint_for_3_to_4).is_err());
317
318 let proof_8 = EpochChangeProof::new(
320 valid_ledger_info[..1].to_vec(),
321 false,
322 );
323 assert!(proof_8.verify(&waypoint_for_3_to_4).is_err());
324 }
325}