use std::ops::RangeInclusive;
use std::sync::Arc;
use miden_node_tracing::Span;
use miden_protocol::block::{BlockNumber, Blockchain};
use crate::account_state_forest::{AccountStateForest, AccountStateForestBackendReader};
use crate::db::Db;
use crate::errors::RangeBeyondTip;
use crate::state::State;
mod scoped;
pub use scoped::{ScopedBlockNum, ScopedBlockRange};
mod snapshot;
pub(in crate::state) use snapshot::{
PublishedGenerations,
SNAPSHOTS_LIVE_WARN_THRESHOLD,
SnapshotGuard,
StateSnapshot,
};
mod account;
mod block;
mod inclusion_proofs;
mod note;
mod protocol_config;
mod state_witnesses;
pub use state_witnesses::StateWitnesses;
mod sync;
mod transaction_inputs;
pub use transaction_inputs::TransactionInputs;
pub struct StateView {
snapshot: Arc<StateSnapshot>,
db: Arc<Db>,
}
impl State {
pub fn view(&self) -> StateView {
StateView {
snapshot: self.latest_snapshot.load_full(),
db: Arc::clone(&self.db),
}
}
pub async fn with_view<R>(&self, f: impl AsyncFnOnce(&StateView) -> R) -> R {
let view = self.view();
f(&view).await
}
}
impl StateView {
pub fn tip(&self) -> ScopedBlockNum {
ScopedBlockNum::new(self.snapshot.latest_block_num())
}
fn blockchain(&self) -> &Blockchain {
&self.snapshot.blockchain
}
fn scope_block(&self, block_num: BlockNumber) -> Option<ScopedBlockNum> {
(block_num <= *self.tip()).then(|| ScopedBlockNum::new(block_num))
}
fn scope_range(
&self,
range: RangeInclusive<BlockNumber>,
) -> Result<ScopedBlockRange, RangeBeyondTip> {
let tip = *self.tip();
if *range.end() > tip {
return Err(RangeBeyondTip { chain_tip: tip, block_to: *range.end() });
}
Ok(ScopedBlockRange::new(range))
}
fn with_inner_read_blocking<R>(&self, f: impl FnOnce(&StateSnapshot) -> R) -> R {
let span = Span::current();
tokio::task::block_in_place(|| span.in_scope(|| f(&self.snapshot)))
}
fn with_forest_read_blocking<R>(
&self,
f: impl FnOnce(&AccountStateForest<AccountStateForestBackendReader>) -> R,
) -> R {
self.with_inner_read_blocking(|snapshot| f(&snapshot.forest))
}
}