use std::marker::PhantomData;
use blake2::{Blake2b512, Digest};
use tracing::trace;
use usig::{Counter, Usig};
use crate::{
peer_message::usig_message::{
checkpoint::{CheckpointContent, CheckpointHash},
view_peer_message::prepare::Prepare,
},
Config, RequestPayload,
};
#[derive(Debug, Clone)]
pub(crate) struct CheckpointGenerator<P: RequestPayload, U: Usig> {
pub(crate) last_hash: CheckpointHash,
pub(crate) total_amount_accepted_batches: u64,
phantom_data: PhantomData<(P, U)>,
}
impl<P: RequestPayload, U: Usig> CheckpointGenerator<P, U> {
pub(crate) fn new() -> Self {
CheckpointGenerator {
last_hash: [0; 64],
total_amount_accepted_batches: 0,
phantom_data: PhantomData,
}
}
pub(crate) fn generate_checkpoint(
&mut self,
prepare: &Prepare<P, U::Signature>,
config: &Config,
) -> Option<CheckpointContent> {
self.total_amount_accepted_batches += 1;
self.last_hash = self.next_state_hash(prepare);
trace!(
"Accepted in total {:?} batches.",
self.total_amount_accepted_batches
);
if self.total_amount_accepted_batches % config.checkpoint_period != 0 {
return None;
};
let checkpoint = CheckpointContent {
origin: config.id,
state_hash: self.last_hash,
counter_latest_prep: prepare.counter(),
total_amount_accepted_batches: self.total_amount_accepted_batches,
};
Some(checkpoint)
}
fn next_state_hash(&mut self, prepare: &Prepare<P, U::Signature>) -> CheckpointHash {
let mut hasher = Blake2b512::new();
hasher.update(self.last_hash);
hasher.update(bincode::serialize(&prepare.request_batch).unwrap());
self.last_hash = hasher.finalize().into();
self.last_hash
}
}