massa_storage/
block_indexes.rs1use std::{collections::btree_map, collections::hash_map, collections::BTreeMap, ops::RangeBounds};
2
3use massa_models::{
4 address::Address,
5 block::SecureShareBlock,
6 block_id::BlockId,
7 endorsement::EndorsementId,
8 operation::OperationId,
9 prehash::{PreHashMap, PreHashSet},
10 slot::Slot,
11};
12
13#[derive(Default)]
16pub struct BlockIndexes {
17 blocks: PreHashMap<BlockId, Box<SecureShareBlock>>,
19 index_by_creator: PreHashMap<Address, PreHashSet<BlockId>>,
21 index_by_slot: BTreeMap<Slot, PreHashSet<BlockId>>,
23 index_by_op: PreHashMap<OperationId, PreHashSet<BlockId>>,
25 index_by_endorsement: PreHashMap<EndorsementId, PreHashSet<BlockId>>,
27}
28
29impl BlockIndexes {
30 pub(crate) fn insert(&mut self, block: SecureShareBlock) {
34 if let hash_map::Entry::Vacant(vac) = self.blocks.entry(block.id) {
35 let block = vac.insert(Box::new(block));
36 self.index_by_creator
38 .entry(block.content_creator_address)
39 .or_default()
40 .insert(block.id);
41
42 self.index_by_slot
44 .entry(block.content.header.content.slot)
45 .or_default()
46 .insert(block.id);
47
48 for op in &block.content.operations {
50 self.index_by_op.entry(*op).or_default().insert(block.id);
51 }
52
53 for ed in &block.content.header.content.endorsements {
55 self.index_by_endorsement
56 .entry(ed.id)
57 .or_default()
58 .insert(block.id);
59 }
60
61 massa_metrics::set_blocks_counter(self.blocks.len());
62 }
63 }
64
65 pub(crate) fn remove(&mut self, block_id: &BlockId) -> Option<Box<SecureShareBlock>> {
69 if let Some(b) = self.blocks.remove(block_id) {
70 if let hash_map::Entry::Occupied(mut occ) =
72 self.index_by_creator.entry(b.content_creator_address)
73 {
74 occ.get_mut().remove(&b.id);
75 if occ.get().is_empty() {
76 occ.remove();
77 }
78 }
79
80 if let btree_map::Entry::Occupied(mut occ) =
82 self.index_by_slot.entry(b.content.header.content.slot)
83 {
84 occ.get_mut().remove(&b.id);
85 if occ.get().is_empty() {
86 occ.remove();
87 }
88 }
89
90 for op in &b.content.operations {
92 if let hash_map::Entry::Occupied(mut occ) = self.index_by_op.entry(*op) {
93 occ.get_mut().remove(&b.id);
94 if occ.get().is_empty() {
95 occ.remove();
96 }
97 }
98 }
99
100 for ed in &b.content.header.content.endorsements {
102 if let hash_map::Entry::Occupied(mut occ) = self.index_by_endorsement.entry(ed.id) {
103 occ.get_mut().remove(&b.id);
104 if occ.get().is_empty() {
105 occ.remove();
106 }
107 }
108 }
109 massa_metrics::set_blocks_counter(self.blocks.len());
110 return Some(b);
111 }
112 None
113 }
114
115 pub fn get(&self, id: &BlockId) -> Option<&SecureShareBlock> {
122 self.blocks.get(id).map(|v| v.as_ref())
123 }
124
125 pub fn contains(&self, id: &BlockId) -> bool {
127 self.blocks.contains_key(id)
128 }
129
130 pub fn get_blocks_created_by(&self, address: &Address) -> Option<&PreHashSet<BlockId>> {
137 self.index_by_creator.get(address)
138 }
139
140 pub fn get_blocks_by_slot(&self, slot: &Slot) -> Option<&PreHashSet<BlockId>> {
147 self.index_by_slot.get(slot)
148 }
149
150 pub fn aggregate_blocks_by_slot_range<R>(&self, slot_range: R) -> PreHashSet<BlockId>
157 where
158 R: RangeBounds<Slot>,
159 {
160 self.index_by_slot.range(slot_range).fold(
161 PreHashSet::default(),
162 |mut acc: PreHashSet<BlockId>, (_, v)| {
163 acc.extend(v);
164 acc
165 },
166 )
167 }
168
169 pub fn get_blocks_by_operation(&self, id: &OperationId) -> Option<&PreHashSet<BlockId>> {
176 self.index_by_op.get(id)
177 }
178
179 pub fn get_blocks_by_endorsement(&self, id: &EndorsementId) -> Option<&PreHashSet<BlockId>> {
186 self.index_by_endorsement.get(id)
187 }
188}