Skip to main content

hotmint_storage/
block_store.rs

1use hotmint_consensus::store::BlockStore;
2use hotmint_types::{Block, BlockHash, Height};
3use tracing::debug;
4use vsdb::MapxOrd;
5
6/// Persistent block store backed by vsdb
7pub struct VsdbBlockStore {
8    by_hash: MapxOrd<[u8; 32], Block>,
9    by_height: MapxOrd<u64, [u8; 32]>,
10}
11
12impl VsdbBlockStore {
13    pub fn new() -> Self {
14        let mut store = Self {
15            by_hash: MapxOrd::new(),
16            by_height: MapxOrd::new(),
17        };
18        let genesis = Block::genesis();
19        store.put_block(genesis);
20        store
21    }
22
23    pub fn contains(&self, hash: &BlockHash) -> bool {
24        self.by_hash.contains_key(&hash.0)
25    }
26
27    pub fn flush(&self) {
28        vsdb::vsdb_flush();
29    }
30}
31
32impl Default for VsdbBlockStore {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38impl BlockStore for VsdbBlockStore {
39    fn put_block(&mut self, block: Block) {
40        debug!(height = block.height.as_u64(), hash = %block.hash, "storing block to vsdb");
41        self.by_height.insert(&block.height.as_u64(), &block.hash.0);
42        self.by_hash.insert(&block.hash.0, &block);
43    }
44
45    fn get_block(&self, hash: &BlockHash) -> Option<Block> {
46        self.by_hash.get(&hash.0)
47    }
48
49    fn get_block_by_height(&self, h: Height) -> Option<Block> {
50        self.by_height
51            .get(&h.as_u64())
52            .and_then(|hash_bytes| self.by_hash.get(&hash_bytes))
53    }
54
55    fn get_blocks_in_range(&self, from: Height, to: Height) -> Vec<Block> {
56        self.by_height
57            .range(from.as_u64()..=to.as_u64())
58            .filter_map(|(_, hash_bytes)| self.by_hash.get(&hash_bytes))
59            .collect()
60    }
61
62    fn tip_height(&self) -> Height {
63        self.by_height
64            .last()
65            .map(|(h, _)| Height(h))
66            .unwrap_or(Height::GENESIS)
67    }
68}