Skip to main content

miden_node_store/state/
replica.rs

1//! Block and proof serving for replica subscriptions.
2//!
3//! Replica subscribers stream committed blocks and block proofs from this node. The writer pushes
4//! each freshly committed block (and the proof path each proven block) into a FIFO cache here, so
5//! subscribers keeping up with the tip are served from memory; a subscriber that has fallen
6//! behind the cache window falls back to reading the block store.
7//!
8//! These reads serve raw block/proof bytes from the caches and the block store — they never touch
9//! the database or tree state, which is why they live on [`State`] directly rather than on a
10//! [`StateView`](super::StateView). The tip checks gating them are live availability checks
11//! ("is this block committed/proven yet?"), deliberately race-tolerant: a `None` for a block that
12//! commits an instant later is corrected by the next tip-watch wakeup.
13
14use std::sync::Arc;
15
16use miden_node_utils::block_cache::BlockOrderedCache;
17use miden_protocol::block::BlockNumber;
18
19use crate::errors::DatabaseError;
20use crate::state::State;
21
22// BLOCK NOTIFICATION
23// ================================================================================================
24
25/// A committed block notification stored in the [`BlockCache`].
26#[derive(Clone, Debug)]
27pub struct BlockNotification(Arc<Block>);
28
29impl BlockNotification {
30    pub fn new(block_num: BlockNumber, block_bytes: Vec<u8>) -> Self {
31        Self(Arc::new(Block { block_num, block_bytes }))
32    }
33
34    pub fn block_num(&self) -> BlockNumber {
35        self.0.block_num
36    }
37
38    pub fn block_bytes(&self) -> &[u8] {
39        &self.0.block_bytes
40    }
41}
42
43#[derive(Clone, Debug)]
44struct Block {
45    pub block_num: BlockNumber,
46    pub block_bytes: Vec<u8>,
47}
48
49// PROOF NOTIFICATION
50// ================================================================================================
51
52/// A proven block notification stored in the [`ProofCache`].
53#[derive(Clone, Debug)]
54pub struct ProofNotification(Arc<Proof>);
55
56impl ProofNotification {
57    pub fn new(block_num: BlockNumber, proof_bytes: Vec<u8>) -> Self {
58        Self(Arc::new(Proof { block_num, proof_bytes }))
59    }
60
61    pub fn block_num(&self) -> BlockNumber {
62        self.0.block_num
63    }
64
65    pub fn proof_bytes(&self) -> &[u8] {
66        &self.0.proof_bytes
67    }
68}
69
70#[derive(Clone, Debug)]
71struct Proof {
72    block_num: BlockNumber,
73    proof_bytes: Vec<u8>,
74}
75
76// CACHES
77// ================================================================================================
78
79/// FIFO cache of recent committed blocks for replica subscriptions.
80pub type BlockCache = BlockOrderedCache<BlockNotification>;
81
82/// FIFO cache of recent block proofs for replica subscriptions.
83pub type ProofCache = BlockOrderedCache<ProofNotification>;
84
85// REPLICA STATE ACCESS
86// ================================================================================================
87
88impl State {
89    /// Loads a block from the in-memory replica cache or block store. Return `Ok(None)` if the
90    /// block is not found.
91    pub async fn load_block(
92        &self,
93        block_num: BlockNumber,
94    ) -> Result<Option<Vec<u8>>, DatabaseError> {
95        if block_num > self.committed_tip() {
96            return Ok(None);
97        }
98        if let Some(block) = self.block_cache.get(block_num) {
99            return Ok(Some(block.block_bytes().to_vec()));
100        }
101        self.block_store.load_block(block_num).await.map_err(Into::into)
102    }
103
104    /// Loads a block proof from the in-memory replica cache or block store. Returns `Ok(None)` if
105    /// the proof is not found.
106    pub async fn load_proof(
107        &self,
108        block_num: BlockNumber,
109    ) -> Result<Option<Vec<u8>>, DatabaseError> {
110        if block_num > self.proven_tip() {
111            return Ok(None);
112        }
113        if let Some(proof) = self.proof_cache.get(block_num) {
114            return Ok(Some(proof.proof_bytes().to_vec()));
115        }
116        self.block_store.load_proof(block_num).await.map_err(Into::into)
117    }
118
119    /// Loads serialized block proving inputs from the block store.
120    pub async fn load_proving_inputs(
121        &self,
122        block_num: BlockNumber,
123    ) -> std::io::Result<Option<Vec<u8>>> {
124        self.block_store.load_proving_inputs(block_num).await
125    }
126}