tendermint_light_client/state.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
//! State maintained by the light client.
use std::collections::{HashMap, HashSet};
use contracts::*;
use crate::{
store::LightStore,
verifier::types::{Height, LightBlock},
};
/// Records which blocks were needed to verify a target block, eg. during bisection.
pub type VerificationTrace = HashMap<Height, HashSet<Height>>;
/// The state managed by the light client.
#[derive(Debug)]
pub struct State {
/// Store for light blocks.
pub light_store: Box<dyn LightStore>,
/// Records which blocks were needed to verify a target block, eg. during bisection.
pub verification_trace: VerificationTrace,
}
impl State {
/// Create a new state from the given light store with an empty verification trace.
pub fn new(light_store: impl LightStore + 'static) -> Self {
Self {
light_store: Box::new(light_store),
verification_trace: VerificationTrace::new(),
}
}
/// Record that the block at `height` was needed to verify the block at `target_height`.
///
/// ## Preconditions
/// - `height` <= `target_height`
#[requires(height <= target_height)]
pub fn trace_block(&mut self, target_height: Height, height: Height) {
self.verification_trace
.entry(target_height)
.or_insert_with(|| {
let mut trace = HashSet::new();
trace.insert(target_height);
trace
})
.insert(height);
}
/// Get the verification trace for the block at `target_height`.
pub fn get_trace(&self, target_height: Height) -> Vec<LightBlock> {
let mut trace = self
.verification_trace
.get(&target_height)
.unwrap_or(&HashSet::new())
.iter()
.flat_map(|&height| self.light_store.get_trusted_or_verified(height))
.collect::<Vec<_>>();
trace.sort_by_key(|lb| lb.height());
trace
}
}