Skip to main content

tycho_core/block_strider/
state.rs

1use std::sync::Mutex;
2
3use anyhow::Result;
4use tycho_block_util::block::{BlockStuff, ShardHeights};
5use tycho_types::models::BlockId;
6
7use crate::storage::CoreStorage;
8
9pub struct UpdateGcState<'a> {
10    /// Related masterchain block id.
11    /// In case of context for mc block this id is the same as `block.id()`.
12    pub mc_block_id: &'a BlockId,
13    /// Related masterchain block flag.
14    /// In case of context for mc block this flag is the same as `is_key_block`.
15    pub mc_is_key_block: bool,
16    /// Whether the `block` from this context is a key block.
17    pub is_key_block: bool,
18    /// Parsed block data.
19    pub block: &'a BlockStuff,
20}
21
22#[derive(Debug, Clone, Copy)]
23pub struct CommitMasterBlock<'a> {
24    pub block_id: &'a BlockId,
25    pub is_key_block: bool,
26    pub shard_heights: &'a ShardHeights,
27}
28
29#[derive(Debug, Clone, Copy)]
30pub struct CommitShardBlock<'a> {
31    pub block_id: &'a BlockId,
32}
33
34pub trait BlockStriderState: Send + Sync + 'static {
35    fn load_last_mc_block_id(&self) -> BlockId;
36
37    fn is_committed(&self, block_id: &BlockId) -> bool;
38
39    fn update_gc_state(&self, ctx: UpdateGcState<'_>) -> Result<()>;
40
41    fn commit_master(&self, ctx: CommitMasterBlock<'_>);
42    fn commit_shard(&self, ctx: CommitShardBlock<'_>);
43}
44
45pub struct PersistentBlockStriderState {
46    zerostate_id: BlockId,
47    storage: CoreStorage,
48}
49
50impl PersistentBlockStriderState {
51    pub fn new(zerostate_id: BlockId, storage: CoreStorage) -> Self {
52        Self {
53            zerostate_id,
54            storage,
55        }
56    }
57}
58
59impl BlockStriderState for PersistentBlockStriderState {
60    fn load_last_mc_block_id(&self) -> BlockId {
61        match self.storage.node_state().load_last_mc_block_id() {
62            Some(block_id) => block_id,
63            None => self.zerostate_id,
64        }
65    }
66
67    fn is_committed(&self, block_id: &BlockId) -> bool {
68        if block_id.is_masterchain() {
69            let last_mc = self.load_last_mc_block_id();
70            last_mc.seqno >= block_id.seqno
71        } else {
72            match self.storage.block_handle_storage().load_handle(block_id) {
73                Some(handle) => handle.is_committed(),
74                None => false,
75            }
76        }
77    }
78
79    fn update_gc_state(&self, ctx: UpdateGcState<'_>) -> Result<()> {
80        self.storage.update_gc_state(ctx.is_key_block, ctx.block);
81        Ok(())
82    }
83
84    fn commit_master(&self, ctx: CommitMasterBlock<'_>) {
85        assert!(ctx.block_id.is_masterchain());
86        self.storage
87            .node_state()
88            .store_last_mc_block_id(ctx.block_id);
89    }
90
91    fn commit_shard(&self, ctx: CommitShardBlock<'_>) {
92        assert!(!ctx.block_id.is_masterchain());
93
94        let handles = self.storage.block_handle_storage();
95        if let Some(handle) = handles.load_handle(ctx.block_id) {
96            handles.set_block_committed(&handle);
97        } else {
98            tracing::warn!(
99                block_id = %ctx.block_id,
100                "committing shard block without a block handle",
101            );
102        }
103    }
104}
105
106pub struct TempBlockStriderState {
107    top_blocks: Mutex<(BlockId, ShardHeights)>,
108}
109
110impl TempBlockStriderState {
111    pub fn new(mc_block_id: BlockId, shard_heights: ShardHeights) -> Self {
112        Self {
113            top_blocks: Mutex::new((mc_block_id, shard_heights)),
114        }
115    }
116}
117
118impl BlockStriderState for TempBlockStriderState {
119    fn load_last_mc_block_id(&self) -> BlockId {
120        self.top_blocks.lock().unwrap().0
121    }
122
123    fn is_committed(&self, block_id: &BlockId) -> bool {
124        let commited = self.top_blocks.lock().unwrap();
125        let (mc_block_id, shard_heights) = &*commited;
126        if block_id.is_masterchain() {
127            block_id.seqno <= mc_block_id.seqno
128        } else {
129            shard_heights.contains_ext(block_id, |top_block, seqno| seqno <= top_block)
130        }
131    }
132
133    fn update_gc_state(&self, _ctx: UpdateGcState<'_>) -> Result<()> {
134        Ok(())
135    }
136
137    fn commit_master(&self, ctx: CommitMasterBlock<'_>) {
138        assert!(ctx.block_id.is_masterchain());
139        let mut commited = self.top_blocks.lock().unwrap();
140        if commited.0.seqno < ctx.block_id.seqno {
141            *commited = (*ctx.block_id, ctx.shard_heights.clone());
142        }
143    }
144
145    fn commit_shard(&self, ctx: CommitShardBlock<'_>) {
146        assert!(!ctx.block_id.is_masterchain());
147        // TODO: Update shard height
148    }
149}