Skip to content

Commit

Permalink
removes fallible ErasureMeta.fec_set_index type-casts
Browse files Browse the repository at this point in the history
fec_set_index is u32 by the definition in the shred struct. Blockstore
however uses u64 for ErasureMeta.fec_set_index for backward
compatibility reasons which results in weird typing and fallible
conversions from u64 to u32. Any ErasureMeta with a fec_set_index which
does not fit in u32 is invalid and should be discarded early.

The commit changes ErasureMeta.fec_set_index type to u32 while using
serde attributes to maintain backward compatibility for
(de)serialization.
  • Loading branch information
behzadnouri committed Jul 18, 2024
1 parent 736bf93 commit 463dd5c
Showing 1 changed file with 45 additions and 10 deletions.
55 changes: 45 additions & 10 deletions ledger/src/blockstore_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,11 @@ pub struct ShredIndex {
/// Erasure coding information
pub struct ErasureMeta {
/// Which erasure set in the slot this is
fec_set_index: u64,
#[serde(
serialize_with = "serde_compat_cast::serialize::<_, u64, _>",
deserialize_with = "serde_compat_cast::deserialize::<_, u64, _>"
)]
fec_set_index: u32,
/// First coding index in the FEC set
first_coding_index: u64,
/// Index of the first received coding shred in the FEC set
Expand All @@ -131,6 +135,39 @@ pub struct ErasureMeta {
config: ErasureConfig,
}

// Helper module to serde values by type-casting to an intermediate
// type for backward compatibility.
mod serde_compat_cast {
use super::*;

// Serializes a value of type T by first type-casting to type R.
pub(super) fn serialize<S: Serializer, R, T: Copy>(
&val: &T,
serializer: S,
) -> Result<S::Ok, S::Error>
where
R: TryFrom<T> + Serialize,
<R as TryFrom<T>>::Error: std::fmt::Display,
{
R::try_from(val)
.map_err(serde::ser::Error::custom)?
.serialize(serializer)
}

// Deserializes a value of type R and type-casts it to type T.
pub(super) fn deserialize<'de, D, R, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
R: Deserialize<'de>,
T: TryFrom<R>,
<T as TryFrom<R>>::Error: std::fmt::Display,
{
R::deserialize(deserializer)
.map(T::try_from)?
.map_err(serde::de::Error::custom)
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub(crate) struct ErasureConfig {
num_data: usize,
Expand Down Expand Up @@ -349,7 +386,7 @@ impl ErasureMeta {
let first_coding_index = u64::from(shred.first_coding_index()?);
let first_received_coding_index = u64::from(shred.index());
let erasure_meta = ErasureMeta {
fec_set_index: u64::from(shred.fec_set_index()),
fec_set_index: shred.fec_set_index(),
config,
first_coding_index,
first_received_coding_index,
Expand Down Expand Up @@ -384,7 +421,8 @@ impl ErasureMeta {

pub(crate) fn data_shreds_indices(&self) -> Range<u64> {
let num_data = self.config.num_data as u64;
self.fec_set_index..self.fec_set_index + num_data
let fec_set_index = u64::from(self.fec_set_index);
fec_set_index..fec_set_index + num_data
}

pub(crate) fn coding_shreds_indices(&self) -> Range<u64> {
Expand All @@ -397,11 +435,8 @@ impl ErasureMeta {
}

pub(crate) fn next_fec_set_index(&self) -> Option<u32> {
let num_data = u64::try_from(self.config.num_data).ok()?;
self.fec_set_index
.checked_add(num_data)
.map(u32::try_from)?
.ok()
let num_data = u32::try_from(self.config.num_data).ok()?;
self.fec_set_index.checked_add(num_data)
}

pub(crate) fn status(&self, index: &Index) -> ErasureMetaStatus {
Expand Down Expand Up @@ -575,7 +610,7 @@ mod test {
};
let e_meta = ErasureMeta {
fec_set_index,
first_coding_index: fec_set_index,
first_coding_index: u64::from(fec_set_index),
config: erasure_config,
first_received_coding_index: 0,
};
Expand Down Expand Up @@ -754,7 +789,7 @@ mod test {
config: erasure_config,
};
let mut new_erasure_meta = ErasureMeta {
fec_set_index: set_index,
fec_set_index: u32::try_from(set_index).unwrap(),
first_coding_index: set_index,
first_received_coding_index: 0,
config: erasure_config,
Expand Down

0 comments on commit 463dd5c

Please sign in to comment.