From cf22cf51af10d9931b551f34c885a72b4bcedb62 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 11 Dec 2024 14:35:59 +1000 Subject: [PATCH 1/2] Document piece index conversion panics --- crates/subspace-core-primitives/src/pieces.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/subspace-core-primitives/src/pieces.rs b/crates/subspace-core-primitives/src/pieces.rs index 2fbc6c2785..556ff0b0e0 100644 --- a/crates/subspace-core-primitives/src/pieces.rs +++ b/crates/subspace-core-primitives/src/pieces.rs @@ -145,7 +145,7 @@ impl PieceIndex { } /// Returns the piece index for a source position and segment index. - /// Panics if the piece is not a source piece. + /// Overflows to the next segment if the position is greater than the last source position. #[inline] pub const fn from_source_position( source_position: u32, @@ -167,7 +167,8 @@ impl PieceIndex { < (RecordedHistorySegment::ERASURE_CODING_RATE.0 as u64) } - /// Returns the next source piece index + /// Returns the next source piece index. + /// Panics if the piece is not a source piece. #[inline] pub const fn next_source_index(&self) -> PieceIndex { PieceIndex::from_source_position(self.source_position() + 1, self.segment_index()) From 85005b594ee50605c0a799c1e485cc4048f19613 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 11 Dec 2024 14:36:21 +1000 Subject: [PATCH 2/2] Add tests for piece index conversions --- crates/subspace-core-primitives/src/tests.rs | 153 +++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/crates/subspace-core-primitives/src/tests.rs b/crates/subspace-core-primitives/src/tests.rs index 5e86aae379..c8a7e4433e 100644 --- a/crates/subspace-core-primitives/src/tests.rs +++ b/crates/subspace-core-primitives/src/tests.rs @@ -1,6 +1,159 @@ +use crate::pieces::PieceIndex; +use crate::segments::{ArchivedHistorySegment, RecordedHistorySegment, SegmentIndex}; use crate::U256; #[test] fn piece_distance_middle() { assert_eq!(U256::MIDDLE, U256::MAX / 2); } + +/// piece index, piece position, source position, segment index, next source index +const SOURCE_PIECE_INDEX_TEST_CASES: &[(u64, u32, u32, u64, u64)] = &[ + (0, 0, 0, 0, 2), + (2, 2, 1, 0, 4), + (126, 126, 63, 0, 128), + (128, 128, 64, 0, 130), + (252, 252, 126, 0, 254), + (254, 254, 127, 0, 256), + (256, 0, 0, 1, 258), + (510, 254, 127, 1, 512), + (512, 0, 0, 2, 514), + // Extreme values + ( + u64::MAX / 4 - 1, + 254, + 127, + u64::MAX / 1024, + u64::MAX / 4 + 1, + ), + // Overflows + //(u64::MAX - 3, 252, 126, u64::MAX / 256, u64::MAX - 1), + //(u64::MAX - 1, 254, 127, u64::MAX/256, overflows), +]; + +/// piece index, piece position, segment index +const PARITY_PIECE_INDEX_TEST_CASES: &[(u64, u32, u64)] = &[ + (1, 1, 0), + (3, 3, 0), + (127, 127, 0), + (129, 129, 0), + (253, 253, 0), + (255, 255, 0), + (257, 1, 1), + (511, 255, 1), + (513, 1, 2), + // Extreme values + (u64::MAX / 4, 255, u64::MAX / 1024), + // Overflows + //(u64::MAX - 2, 253, u64::MAX / 256), + //(u64::MAX, 255, u64::MAX / 256), +]; + +#[test] +fn source_piece_index_conversion() { + for &(piece_index, piece_position, source_position, segment_index, next_source_piece_index) in + SOURCE_PIECE_INDEX_TEST_CASES + { + let piece_index = PieceIndex::new(piece_index); + let segment_index = SegmentIndex::new(segment_index); + let next_source_piece_index = PieceIndex::new(next_source_piece_index); + + println!( + "{:?} {:?} {:?} {:?} {:?}", + piece_index, piece_position, source_position, segment_index, next_source_piece_index + ); + + assert_eq!(piece_index.position(), piece_position); + + assert_eq!(piece_index.source_position(), source_position); + assert_eq!( + PieceIndex::from_source_position(source_position, segment_index), + piece_index + ); + + assert_eq!(piece_index.segment_index(), segment_index); + assert_eq!(piece_index.next_source_index(), next_source_piece_index); + assert!(piece_index.is_source(), "{:?}", piece_index); + + if piece_position == 0 { + assert_eq!(segment_index.first_piece_index(), piece_index); + } + + // Is at piece_position index in SegmentIndex::segment_piece_indexes() + assert_eq!( + segment_index + .segment_piece_indexes() + .get(piece_position as usize), + Some(&piece_index) + ); + + // Is at source_position index in SegmentIndex::segment_piece_indexes_source_first() + assert_eq!( + segment_index + .segment_piece_indexes_source_first() + .get(source_position as usize), + Some(&piece_index) + ); + } +} + +#[test] +fn parity_piece_index_conversion() { + for &(piece_index, piece_position, segment_index) in PARITY_PIECE_INDEX_TEST_CASES { + let piece_index = PieceIndex::new(piece_index); + let segment_index = SegmentIndex::new(segment_index); + + println!("{:?} {:?} {:?}", piece_index, piece_position, segment_index,); + + assert_eq!(piece_index.position(), piece_position); + + assert_eq!(piece_index.segment_index(), segment_index); + assert!(!piece_index.is_source(), "{:?}", piece_index); + + if piece_position as usize == ArchivedHistorySegment::NUM_PIECES - 1 { + assert_eq!(segment_index.last_piece_index(), piece_index); + } + + // Is at piece_position index in SegmentIndex::segment_piece_indexes() + assert_eq!( + segment_index + .segment_piece_indexes() + .get(piece_position as usize), + Some(&piece_index) + ); + + // Is at the corresponding index in the second half of SegmentIndex::segment_piece_indexes_source_first() + assert_eq!( + segment_index + .segment_piece_indexes_source_first() + .get(piece_position as usize / 2 + RecordedHistorySegment::NUM_RAW_RECORDS), + Some(&piece_index) + ); + } +} + +#[test] +#[should_panic] +fn parity_piece_index_position_panic() { + for &(piece_index, piece_position, segment_index) in PARITY_PIECE_INDEX_TEST_CASES { + let piece_index = PieceIndex::new(piece_index); + + println!("{:?} {:?} {:?}", piece_index, piece_position, segment_index); + + // Always panics + piece_index.source_position(); + } +} + +#[test] +#[should_panic] +fn parity_piece_index_next_source_panic() { + for &(piece_index, piece_position, segment_index) in PARITY_PIECE_INDEX_TEST_CASES { + let piece_index = PieceIndex::new(piece_index); + + println!("{:?} {:?} {:?}", piece_index, piece_position, segment_index); + + // Always panics + piece_index.next_source_index(); + } +}