Skip to content

Commit 62854d6

Browse files
authored
refactor: introduces types for info returned from reconstructing slice and block (#174)
Part of #85. - Introduces new types for what `try_reconstruct_slice` and `try_reconstruct_block` return. - documents why an `unwrap` is safe. - uses `Entry` API to reduce map lookups and not having to validate that insertion is not overwriting.
1 parent e2d375f commit 62854d6

File tree

1 file changed

+60
-32
lines changed

1 file changed

+60
-32
lines changed

src/consensus/blockstore/slot_block_data.rs

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//!
77
88
use std::collections::BTreeMap;
9+
use std::collections::btree_map::Entry;
910

1011
use log::{debug, trace, warn};
1112
use thiserror::Error;
@@ -101,6 +102,27 @@ impl SlotBlockData {
101102
}
102103
}
103104

105+
/// Returned value from [`try_reconstruct_slice`]
106+
enum ReconstructSliceResult {
107+
/// Either slice was already reconstructed or not enough data.
108+
NoAction,
109+
/// Encountered an error reconstructing the slice.
110+
Error,
111+
/// Slice successfully reconstructed.
112+
Complete,
113+
}
114+
115+
/// Returned value from [`try_reconstruct_block`]
116+
enum ReconstructBlockResult {
117+
/// Either block was already reconstructed or not enough data.
118+
NoAction,
119+
/// Encountered an error reconstructing the block.
120+
Error,
121+
/// Block successfully reconstructed.
122+
/// [`BlockInfo`] describing the block is returned.
123+
Complete(BlockInfo),
124+
}
125+
104126
/// Holds all data corresponding to a single block.
105127
pub struct BlockData {
106128
/// Slot number this block is in.
@@ -161,14 +183,16 @@ impl BlockData {
161183
}
162184

163185
// maybe reconstruct slice and block
164-
if self.try_reconstruct_slice(slice_index) {
165-
self.try_reconstruct_block()
166-
.map(|block_info| VotorEvent::Block {
186+
// TODO: handle error cases.
187+
match self.try_reconstruct_slice(slice_index) {
188+
ReconstructSliceResult::NoAction | ReconstructSliceResult::Error => None,
189+
ReconstructSliceResult::Complete => match self.try_reconstruct_block() {
190+
ReconstructBlockResult::NoAction | ReconstructBlockResult::Error => None,
191+
ReconstructBlockResult::Complete(block_info) => Some(VotorEvent::Block {
167192
slot: self.slot,
168193
block_info,
169-
})
170-
} else {
171-
None
194+
}),
195+
},
172196
}
173197
}
174198

@@ -217,55 +241,59 @@ impl BlockData {
217241

218242
/// Reconstructs the slice if the blockstore contains enough shreds.
219243
///
220-
/// Returns `true` if a slice was reconstructed, `false` otherwise.
221-
fn try_reconstruct_slice(&mut self, slice: SliceIndex) -> bool {
244+
/// See [`ReconstructSliceResult`] for more info on what the function returns.
245+
fn try_reconstruct_slice(&mut self, index: SliceIndex) -> ReconstructSliceResult {
222246
if self.completed.is_some() {
223247
trace!("already have block for slot {}", self.slot);
224-
return false;
248+
return ReconstructSliceResult::NoAction;
225249
}
226-
if self.slices.contains_key(&slice) {
227-
trace!("already have slice {} in slot {}", slice, self.slot);
228-
return false;
229-
}
230-
let slice_shreds = self.shreds.get_mut(&slice).unwrap();
250+
251+
let entry = match self.slices.entry(index) {
252+
Entry::Occupied(_) => return ReconstructSliceResult::NoAction,
253+
Entry::Vacant(entry) => entry,
254+
};
255+
256+
// assuming caller has inserted at least one valid shred so unwrap() should be safe
257+
let slice_shreds = self.shreds.get_mut(&index).unwrap();
231258
let (reconstructed_slice, mut reconstructed_shreds) =
232259
match RegularShredder::deshred(slice_shreds) {
233260
Ok(output) => output,
234-
Err(DeshredError::NotEnoughShreds) => return false,
261+
Err(DeshredError::NotEnoughShreds) => return ReconstructSliceResult::NoAction,
235262
rest => {
236263
warn!("deshreding failed with {rest:?}");
237-
return false;
264+
return ReconstructSliceResult::Error;
238265
}
239266
};
240267
if reconstructed_slice.parent.is_none() && reconstructed_slice.slice_index.is_first() {
241268
warn!(
242269
"reconstructed slice {} in slot {} expected to contain parent",
243-
slice, self.slot
270+
index, self.slot
244271
);
245-
return false;
272+
return ReconstructSliceResult::Error;
246273
}
247274

248275
// insert reconstructed slice and shreds
249-
self.slices.insert(slice, reconstructed_slice);
276+
entry.insert(reconstructed_slice);
250277
std::mem::swap(slice_shreds, &mut reconstructed_shreds);
251-
trace!("reconstructed slice {} in slot {}", slice, self.slot);
278+
trace!("reconstructed slice {} in slot {}", index, self.slot);
252279

253-
true
280+
ReconstructSliceResult::Complete
254281
}
255282

256283
/// Reconstructs the block if the blockstore contains all slices.
257284
///
258-
/// Returns `Some(block_info)` if a block was reconstructed, `None` otherwise.
259-
/// In the `Some`-case, `block_info` is the [`BlockInfo`] of the reconstructed block.
260-
fn try_reconstruct_block(&mut self) -> Option<BlockInfo> {
285+
/// See [`ReconstructBlockResult`] for more info on what the function returns.
286+
fn try_reconstruct_block(&mut self) -> ReconstructBlockResult {
261287
if self.completed.is_some() {
262288
trace!("already have block for slot {}", self.slot);
263-
return None;
289+
return ReconstructBlockResult::NoAction;
264290
}
265-
let last_slice = self.last_slice?;
291+
let Some(last_slice) = self.last_slice else {
292+
return ReconstructBlockResult::NoAction;
293+
};
266294
if self.slices.len() != last_slice.inner() + 1 {
267295
trace!("don't have all slices for slot {} yet", self.slot);
268-
return None;
296+
return ReconstructBlockResult::NoAction;
269297
}
270298

271299
// calculate double-Merkle tree & block hash
@@ -292,11 +320,11 @@ impl BlockData {
292320
{
293321
if new_parent == parent {
294322
warn!("parent switched to same value");
295-
return None;
323+
return ReconstructBlockResult::Error;
296324
}
297325
if parent_switched {
298326
warn!("parent switched more than once");
299-
return None;
327+
return ReconstructBlockResult::Error;
300328
}
301329
parent_switched = true;
302330
parent = new_parent;
@@ -307,7 +335,7 @@ impl BlockData {
307335
Ok(r) => r,
308336
Err(err) => {
309337
warn!("decoding slice {ind} failed with {err:?}");
310-
return None;
338+
return ReconstructBlockResult::Error;
311339
}
312340
};
313341
if bytes_read != slice.data.len() {
@@ -317,7 +345,7 @@ impl BlockData {
317345
bytes_read,
318346
slice.data.len()
319347
);
320-
return None;
348+
return ReconstructBlockResult::Error;
321349
}
322350
transactions.append(&mut txs);
323351
}
@@ -337,7 +365,7 @@ impl BlockData {
337365
self.slices.remove(&slice_index);
338366
}
339367

340-
Some(block_info)
368+
ReconstructBlockResult::Complete(block_info)
341369
}
342370
}
343371

0 commit comments

Comments
 (0)