saito_core/core/consensus/
ringitem.rs

1use crate::core::defs::SaitoHash;
2
3//
4// This is an index with shorthand information on the block_ids and hashes of the blocks
5// in the longest-chain.
6//
7// The BlockRing is a fixed size Vector which can be made contiguous and theoretically
8// made available for fast-access through a slice with the same lifetime as the vector
9// itself.
10//
11#[derive(Debug, Default)]
12pub struct RingItem {
13    pub lc_pos: Option<usize>,
14    pub block_hashes: Vec<SaitoHash>,
15    pub block_ids: Vec<u64>,
16}
17
18impl RingItem {
19    pub fn add_block(&mut self, block_id: u64, hash: SaitoHash) {
20        self.block_hashes.push(hash);
21        self.block_ids.push(block_id);
22    }
23
24    pub fn contains_block_hash(&self, hash: SaitoHash) -> bool {
25        self.block_hashes.iter().any(|&i| i == hash)
26    }
27
28    pub fn delete_block(&mut self, block_id: u64, hash: SaitoHash) {
29        let mut new_block_hashes: Vec<SaitoHash> = vec![];
30        let mut new_block_ids: Vec<u64> = vec![];
31        let mut index_loop = 0;
32        let mut new_lc_pos = Some(0);
33
34        for i in 0..self.block_ids.len() {
35            if self.block_ids[i] == block_id && self.block_hashes[i] == hash {
36            } else {
37                new_block_hashes.push(self.block_hashes[i]);
38                new_block_ids.push(self.block_ids[i]);
39                if self.lc_pos == Some(i) {
40                    new_lc_pos = Some(index_loop);
41                }
42                index_loop += 1;
43            }
44        }
45
46        self.block_hashes = new_block_hashes;
47        self.block_ids = new_block_ids;
48        self.lc_pos = new_lc_pos;
49    }
50
51    pub fn on_chain_reorganization(&mut self, hash: SaitoHash, lc: bool) {
52        if !lc {
53            self.lc_pos = None;
54        } else {
55            self.lc_pos = self.block_hashes.iter().position(|b_hash| b_hash == &hash);
56        }
57    }
58}
59
60#[cfg(test)]
61mod tests {
62
63    use crate::core::consensus::block::Block;
64    use crate::core::consensus::ringitem::RingItem;
65
66    #[test]
67    fn ringitem_new_test() {
68        let ringitem = RingItem::default();
69        assert_eq!(ringitem.block_hashes.len() as u64, 0);
70        assert_eq!(ringitem.block_ids.len() as u64, 0);
71        assert_eq!(ringitem.lc_pos, None);
72    }
73
74    #[test]
75    fn ringitem_add_and_delete_block() {
76        let mut ringitem = RingItem::default();
77        let mut block = Block::new();
78        block.generate_hash();
79        let block_id = block.id;
80        let block_hash = block.hash;
81
82        assert_eq!(ringitem.contains_block_hash(block_hash), false);
83        assert_eq!(ringitem.block_hashes.len() as u64, 0);
84        assert_eq!(ringitem.block_ids.len() as u64, 0);
85
86        ringitem.add_block(block.id, block.hash);
87
88        assert_eq!(ringitem.contains_block_hash(block_hash), true);
89        assert_eq!(ringitem.block_hashes.len() as u64, 1);
90        assert_eq!(ringitem.block_ids.len() as u64, 1);
91
92        ringitem.delete_block(block_id, block_hash);
93
94        assert_eq!(ringitem.contains_block_hash(block_hash), false);
95        assert_eq!(ringitem.block_hashes.len() as u64, 0);
96        assert_eq!(ringitem.block_ids.len() as u64, 0);
97    }
98}