near_primitives/stateless_validation/
chunk_endorsements_bitmap.rs1use bitvec::prelude::*;
2use borsh::{BorshDeserialize, BorshSerialize};
3use near_schema_checker_lib::ProtocolSchema;
4
5#[derive(
13 BorshSerialize,
14 BorshDeserialize,
15 serde::Serialize,
16 serde::Deserialize,
17 Debug,
18 Clone,
19 Eq,
20 PartialEq,
21 Default,
22 ProtocolSchema,
23)]
24pub struct ChunkEndorsementsBitmap {
25 inner: Vec<Vec<u8>>,
26}
27
28type BitVecType = BitVec<u8, Lsb0>;
30
31impl ChunkEndorsementsBitmap {
32 pub fn new(num_shards: usize) -> Self {
34 Self { inner: vec![Default::default(); num_shards] }
35 }
36
37 pub fn genesis() -> Self {
41 Self::new(0)
42 }
43
44 pub fn from_bytes(bytes: Vec<Vec<u8>>) -> Self {
46 Self { inner: bytes }
47 }
48
49 pub fn bytes(&self) -> Vec<Vec<u8>> {
52 self.inner.clone()
53 }
54
55 pub fn from_endorsements(shards_to_endorsements: Vec<Vec<bool>>) -> Self {
57 let mut bitmap = ChunkEndorsementsBitmap::new(shards_to_endorsements.len());
58 for (shard_index, endorsements) in shards_to_endorsements.into_iter().enumerate() {
59 bitmap.add_endorsements(shard_index, endorsements);
60 }
61 bitmap
62 }
63
64 pub fn add_endorsements(&mut self, shard_index: usize, endorsements: Vec<bool>) {
66 let bitvec: BitVecType = endorsements.iter().collect();
67 self.inner[shard_index] = bitvec.into();
68 }
69
70 pub fn iter(&self, shard_index: usize) -> Box<dyn Iterator<Item = bool>> {
72 let bitvec = BitVecType::from_vec(self.inner[shard_index].clone());
73 Box::new(bitvec.into_iter())
74 }
75
76 pub fn num_shards(&self) -> usize {
78 self.inner.len()
79 }
80
81 pub fn len(&self, shard_index: usize) -> Option<usize> {
84 self.inner.get(shard_index).map(|v| v.len() * 8)
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::ChunkEndorsementsBitmap;
91 use itertools::Itertools;
92 use rand::Rng;
93
94 const NUM_SHARDS: usize = 4;
95
96 fn assert_bitmap(
98 bitmap: &ChunkEndorsementsBitmap,
99 num_assignments: usize,
100 expected_endorsements: &Vec<Vec<bool>>,
101 ) {
102 for (shard_index, endorsements) in expected_endorsements.iter().enumerate() {
104 let num_bits = bitmap.len(shard_index).unwrap();
105 let bits = bitmap.iter(shard_index).collect_vec();
106 assert_eq!(num_bits, bits.len());
108 assert_eq!(num_bits, num_assignments.div_ceil(8) * 8);
110 let mut expected_bits = endorsements.clone();
112 expected_bits.extend(std::iter::repeat(false).take(num_bits - num_assignments));
114 assert_eq!(bits, expected_bits);
115 }
116 }
117
118 fn run_bitmap_test(num_assignments: usize, num_produced: usize) {
119 let mut rng = rand::thread_rng();
120 let mut bitmap = ChunkEndorsementsBitmap::new(NUM_SHARDS);
121 let mut expected_endorsements = vec![];
122 for shard_index in 0..NUM_SHARDS {
123 let mut endorsements = vec![false; num_assignments];
124 for _ in 0..num_produced {
125 endorsements[rng.gen_range(0..num_assignments)] = true;
126 }
127 expected_endorsements.push(endorsements.clone());
128 bitmap.add_endorsements(shard_index, endorsements);
129 }
130 assert_bitmap(&bitmap, num_assignments, &expected_endorsements);
132
133 let serialized = borsh::to_vec(&bitmap).unwrap();
135 let bitmap = borsh::from_slice::<ChunkEndorsementsBitmap>(&serialized).unwrap();
136 assert_bitmap(&bitmap, num_assignments, &expected_endorsements);
137 }
138
139 #[test]
140 fn test_chunk_endorsements_bitmap() {
141 run_bitmap_test(0, 0);
142 run_bitmap_test(60, 20);
143 run_bitmap_test(68, 20);
144 run_bitmap_test(125, 30);
145 run_bitmap_test(130, 50);
146 run_bitmap_test(300, 100);
147 }
148}