Skip to content

Commit

Permalink
Add restrictions to RuntimeVariableList api
Browse files Browse the repository at this point in the history
  • Loading branch information
pawanjay176 committed Aug 30, 2024
1 parent 25feedf commit 4dc6e65
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 20 deletions.
1 change: 0 additions & 1 deletion consensus/types/src/blob_sidecar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@ impl<E: EthSpec> BlobSidecar<E> {

pub type BlobSidecarList<E> = RuntimeVariableList<Arc<BlobSidecar<E>>>;
/// Alias for a non length-constrained list of `BlobSidecar`s.
pub type BlobSidecarVec<E> = Vec<Arc<BlobSidecar<E>>>;
pub type FixedBlobSidecarList<E> = RuntimeFixedList<Option<Arc<BlobSidecar<E>>>>;
pub type BlobsList<E> = VariableList<Blob<E>, <E as EthSpec>::MaxBlobCommitmentsPerBlock>;

Expand Down
5 changes: 2 additions & 3 deletions consensus/types/src/data_column_sidecar.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::beacon_block_body::{KzgCommitments, BLOB_KZG_COMMITMENTS_INDEX};
use crate::test_utils::TestRandom;
use crate::{BeaconBlockHeader, Epoch, EthSpec, Hash256, KzgProofs, SignedBeaconBlockHeader, Slot};
use crate::{BeaconStateError, ChainSpec};
use crate::BeaconStateError;
use crate::{BeaconBlockHeader, EthSpec, Hash256, KzgProofs, SignedBeaconBlockHeader, Slot};
use bls::Signature;
use derivative::Derivative;
use kzg::Error as KzgError;
Expand All @@ -11,7 +11,6 @@ use safe_arith::ArithError;
use serde::{Deserialize, Serialize};
use ssz::Encode;
use ssz_derive::{Decode, Encode};
use ssz_types::typenum::Unsigned;
use ssz_types::Error as SszError;
use ssz_types::{FixedVector, VariableList};
use std::hash::Hash;
Expand Down
73 changes: 57 additions & 16 deletions consensus/types/src/runtime_var_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use derivative::Derivative;
use serde::{Deserialize, Serialize};
use ssz::Decode;
use ssz_types::Error;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::ops::{Deref, Index, IndexMut};
use std::slice::SliceIndex;

/// Emulates a SSZ `List`.
Expand Down Expand Up @@ -41,16 +41,21 @@ use std::slice::SliceIndex;
#[serde(transparent)]
pub struct RuntimeVariableList<T> {
vec: Vec<T>,
/// A `None` here indicates an uninitialized `Self`.
/// No mutating operation will be allowed until `max_len` is Some
#[serde(skip)]
max_len: usize,
max_len: Option<usize>,
}

impl<T> RuntimeVariableList<T> {
/// Returns `Ok` if the given `vec` equals the fixed length of `Self`. Otherwise returns
/// `Err(OutOfBounds { .. })`.
pub fn new(vec: Vec<T>, max_len: usize) -> Result<Self, Error> {
if vec.len() <= max_len {
Ok(Self { vec, max_len })
Ok(Self {
vec,
max_len: Some(max_len),
})
} else {
Err(Error::OutOfBounds {
i: vec.len(),
Expand All @@ -62,21 +67,46 @@ impl<T> RuntimeVariableList<T> {
pub fn from_vec(mut vec: Vec<T>, max_len: usize) -> Self {
vec.truncate(max_len);

Self { vec, max_len }
Self {
vec,
max_len: Some(max_len),
}
}

/// Create an empty list.
pub fn empty(max_len: usize) -> Self {
Self {
vec: vec![],
max_len,
max_len: Some(max_len),
}
}

pub fn as_slice(&self) -> &[T] {
self.vec.as_slice()
}

pub fn as_mut_slice(&mut self) -> Option<&mut [T]> {
if self.max_len.is_none() {
return None;
};
Some(self.vec.as_mut_slice())
}

/// Returns an instance of `Self` with max_len = None.
///
/// No mutating operation can be performed on an uninitialized instance
/// without first setting max_len.
pub fn empty_uninitialized() -> Self {
Self {
vec: vec![],
max_len: None,
}
}

pub fn set_max_len(&mut self, max_len: usize) {
self.max_len = Some(max_len);
}

/// Returns the number of values presently in `self`.
pub fn len(&self) -> usize {
self.vec.len()
Expand All @@ -88,21 +118,27 @@ impl<T> RuntimeVariableList<T> {
}

/// Returns the type-level maximum length.
pub fn max_len(&self) -> usize {
///
/// Returns `None` if self is uninitialized with a max_len.
pub fn max_len(&self) -> Option<usize> {
self.max_len
}

/// Appends `value` to the back of `self`.
///
/// Returns `Err(())` when appending `value` would exceed the maximum length.
pub fn push(&mut self, value: T) -> Result<(), Error> {
if self.vec.len() < self.max_len {
let Some(max_len) = self.max_len else {
// TODO(pawan): set a better error
return Err(Error::MissingLengthInformation);
};
if self.vec.len() < max_len {
self.vec.push(value);
Ok(())
} else {
Err(Error::OutOfBounds {
i: self.vec.len().saturating_add(1),
len: self.max_len,
len: max_len,
})
}
}
Expand Down Expand Up @@ -135,7 +171,10 @@ impl<T: Decode> RuntimeVariableList<T> {
} else {
ssz::decode_list_of_variable_length_items(bytes, Some(max_len))?
};
Ok(Self { vec, max_len })
Ok(Self {
vec,
max_len: Some(max_len),
})
}
}

Expand Down Expand Up @@ -169,12 +208,6 @@ impl<T> Deref for RuntimeVariableList<T> {
}
}

impl<T> DerefMut for RuntimeVariableList<T> {
fn deref_mut(&mut self) -> &mut [T] {
&mut self.vec[..]
}
}

impl<'a, T> IntoIterator for &'a RuntimeVariableList<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
Expand Down Expand Up @@ -221,7 +254,6 @@ pub struct RuntimeFixedList<T> {
}

impl<T: Clone> RuntimeFixedList<T> {
// TODO(pawan): no need to take len
pub fn new(vec: Vec<T>) -> Self {
let len = vec.len();
Self { vec, len }
Expand Down Expand Up @@ -280,6 +312,7 @@ mod test {
use super::*;
use ssz::*;
use std::fmt::Debug;
use tree_hash::TreeHash;

#[test]
fn new() {
Expand Down Expand Up @@ -358,4 +391,12 @@ mod test {
round_trip::<u16>(RuntimeVariableList::from_vec(vec![42; 8], 8));
round_trip::<u16>(RuntimeVariableList::from_vec(vec![0; 8], 8));
}

#[test]
fn test_empty_list_encoding() {
use ssz_types::{typenum::U16, VariableList};

let a: RuntimeVariableList<u64> = RuntimeVariableList::from_vec(vec![], 16);
dbg!(a.tree_hash_root());
}
}

0 comments on commit 4dc6e65

Please sign in to comment.