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 ledger_info_with_sigs(&self) -> &[LedgerInfoWithSignatures] {
138 &self.ledger_info_with_sigs
139 }
140
141 pub fn get_all_ledger_infos(&self) -> Vec<LedgerInfoWithSignatures> {
142 self.ledger_info_with_sigs.clone()
143 }
144}
145
146#[cfg(any(test, feature = "fuzzing"))]
147impl Arbitrary for EpochChangeProof {
148 type Parameters = ();
149 type Strategy = BoxedStrategy<Self>;
150
151 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
152 (vec(any::<LedgerInfoWithSignatures>(), 0..10), any::<bool>())
153 .prop_map(|(ledger_infos_with_sigs, more)| {
154 Self::new(ledger_infos_with_sigs, more)
155 })
156 .boxed()
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use crate::{block_info::BlockInfo, epoch_state::EpochState};
164
165 #[test]
166 fn verify_epoch_change_proof() {
167 use crate::{
168 ledger_info::LedgerInfo,
169 validator_verifier::random_validator_verifier,
170 };
171 use diem_crypto::hash::HashValue;
172 use std::collections::BTreeMap;
173
174 let all_epoch: Vec<u64> = (1..=10).collect();
175 let mut valid_ledger_info = vec![];
176 let mut validator_verifier = vec![];
177
178 let (mut current_signers, mut current_verifier) =
181 random_validator_verifier(1, None, true);
182 let mut current_version = 123;
183 for epoch in &all_epoch {
184 validator_verifier.push(current_verifier.clone());
185 let (next_signers, next_verifier) =
186 random_validator_verifier((*epoch + 1) as usize, None, true);
187 let epoch_state =
188 EpochState::new(*epoch + 1, next_verifier.clone(), vec![]);
189 let ledger_info = LedgerInfo::new(
190 BlockInfo::new(
191 *epoch,
192 0,
193 HashValue::zero(),
194 HashValue::zero(),
195 current_version,
196 0,
197 Some(epoch_state),
198 None,
199 ),
200 HashValue::zero(),
201 );
202 let signatures = current_signers
203 .iter()
204 .map(|s| (s.author(), s.sign(&ledger_info)))
205 .collect();
206 valid_ledger_info
207 .push(LedgerInfoWithSignatures::new(ledger_info, signatures));
208 current_signers = next_signers;
209 current_verifier = next_verifier;
210 current_version += 1;
211 }
212
213 let proof_1 = EpochChangeProof::new(
215 valid_ledger_info.clone(),
216 false,
217 );
218 assert!(proof_1
219 .verify(&EpochState::new(
220 all_epoch[0],
221 validator_verifier[0].clone(),
222 vec![]
223 ))
224 .is_ok());
225
226 let proof_2 = EpochChangeProof::new(
227 valid_ledger_info[2..5].to_vec(),
228 false,
229 );
230 assert!(proof_2
231 .verify(&EpochState::new(
232 all_epoch[2],
233 validator_verifier[2].clone(),
234 vec![]
235 ))
236 .is_ok());
237
238 assert!(proof_1
240 .verify(&EpochState::new(
241 all_epoch[4],
242 validator_verifier[4].clone(),
243 vec![]
244 ))
245 .is_ok());
246
247 let proof_3 = EpochChangeProof::new(vec![], false);
249 assert!(proof_3
250 .verify(&EpochState::new(
251 all_epoch[0],
252 validator_verifier[0].clone(),
253 vec![]
254 ))
255 .is_err());
256
257 let mut list = valid_ledger_info[3..5].to_vec();
259 list.extend_from_slice(&valid_ledger_info[8..9]);
260 let proof_4 = EpochChangeProof::new(list, false);
261 assert!(proof_4
262 .verify(&EpochState::new(
263 all_epoch[3],
264 validator_verifier[3].clone(),
265 vec![]
266 ))
267 .is_err());
268
269 let mut list = valid_ledger_info.clone();
271 list.reverse();
272 let proof_5 = EpochChangeProof::new(list, false);
273 assert!(proof_5
274 .verify(&EpochState::new(
275 all_epoch[9],
276 validator_verifier[9].clone(),
277 vec![]
278 ))
279 .is_err());
280
281 let proof_6 = EpochChangeProof::new(
283 vec![LedgerInfoWithSignatures::new(
284 valid_ledger_info[0].ledger_info().clone(),
285 BTreeMap::new(),
286 )],
287 false,
288 );
289 assert!(proof_6
290 .verify(&EpochState::new(
291 all_epoch[0],
292 validator_verifier[0].clone(),
293 vec![]
294 ))
295 .is_err());
296 }
297}