use std::sync::{Arc, RwLock};
use miden_protocol::block::{BlockHeader, BlockNumber};
use miden_protocol::crypto::merkle::mmr::PartialMmr;
use miden_protocol::transaction::PartialBlockchain;
#[derive(Debug, Clone)]
pub struct ChainState {
pub chain_tip_header: BlockHeader,
pub chain_mmr: Arc<PartialBlockchain>,
}
impl ChainState {
pub(crate) fn new(chain_tip_header: BlockHeader, chain_mmr: PartialMmr) -> Self {
let chain_mmr = PartialBlockchain::new(chain_mmr, [])
.expect("partial blockchain should build from partial mmr");
Self {
chain_tip_header,
chain_mmr: Arc::new(chain_mmr),
}
}
pub fn into_parts(self) -> (BlockHeader, Arc<PartialBlockchain>) {
(self.chain_tip_header, self.chain_mmr)
}
pub(crate) fn current_mmr(&self) -> PartialMmr {
self.chain_mmr.mmr().clone()
}
pub(crate) fn update_chain_tip(&mut self, tip: BlockHeader, max_block_count: usize) {
if tip.block_num() <= self.chain_tip_header.block_num() {
tracing::debug!(
event_block = %tip.block_num(),
current_tip = %self.chain_tip_header.block_num(),
"skipping committed block already reflected in chain state",
);
return;
}
let mmr_tip = self.chain_tip_header.clone();
Arc::make_mut(&mut self.chain_mmr).add_block(&mmr_tip, true);
self.chain_tip_header = tip;
let pruned_block_height =
(self.chain_mmr.chain_length().as_usize().saturating_sub(max_block_count)) as u32;
Arc::make_mut(&mut self.chain_mmr).prune_to(..pruned_block_height.into());
}
}
pub struct SharedChainState(RwLock<ChainState>);
impl SharedChainState {
pub fn new(chain_tip_header: BlockHeader, chain_mmr: PartialMmr) -> Self {
Self(RwLock::new(ChainState::new(chain_tip_header, chain_mmr)))
}
pub(crate) fn chain_tip_block_number(&self) -> BlockNumber {
self.0.read().expect("chain state lock poisoned").chain_tip_header.block_num()
}
pub(crate) fn current_mmr(&self) -> PartialMmr {
self.0.read().expect("chain state lock poisoned").current_mmr()
}
pub(crate) fn update_chain_tip(&self, tip: BlockHeader, max_block_count: usize) {
self.0
.write()
.expect("chain state lock poisoned")
.update_chain_tip(tip, max_block_count);
}
pub(crate) fn get_cloned(&self) -> ChainState {
self.0.read().expect("chain state lock poisoned").clone()
}
}