subspace_data_retrieval/object_fetcher/
segment_header.rs1use crate::object_fetcher::{decode_data_length, Error};
7use parity_scale_codec::{Decode, Encode, Input, IoReader};
8use std::io::Cursor;
9use subspace_archiving::archiver::SegmentItem;
10use subspace_core_primitives::hashes::Blake3Hash;
11use subspace_core_primitives::objects::GlobalObject;
12use subspace_core_primitives::segments::{
13 ArchivedBlockProgress, LastArchivedBlock, SegmentCommitment, SegmentHeader, SegmentIndex,
14};
15
16pub const MAX_SEGMENT_PADDING: usize = 3;
23
24pub const MAX_BLOCK_LENGTH: u32 = 5 * 1024 * 1024;
27
28const SEGMENT_VERSION_VARIANT: u8 = 0;
30
31const BLOCK_CONTINUATION_VARIANT: u8 = 3;
33
34#[inline]
36pub fn min_segment_header_encoded_size() -> usize {
37 let min_segment_header = SegmentHeader::V0 {
38 segment_index: 0.into(),
39 segment_commitment: SegmentCommitment::default(),
40 prev_segment_header_hash: Blake3Hash::default(),
41 last_archived_block: LastArchivedBlock {
42 number: 0,
43 archived_progress: ArchivedBlockProgress::Complete,
44 },
45 };
46
47 min_segment_header.encoded_size()
48}
49
50#[inline]
52pub fn max_segment_header_encoded_size() -> usize {
53 let max_segment_header = SegmentHeader::V0 {
54 segment_index: u64::MAX.into(),
55 segment_commitment: SegmentCommitment::default(),
56 prev_segment_header_hash: Blake3Hash::default(),
57 last_archived_block: LastArchivedBlock {
58 number: u32::MAX,
59 archived_progress: ArchivedBlockProgress::Partial(u32::MAX),
60 },
61 };
62
63 max_segment_header.encoded_size()
64}
65
66pub fn strip_segment_header(
78 piece_data: Vec<u8>,
79 segment_index: SegmentIndex,
80 mapping: GlobalObject,
81) -> Result<(Vec<u8>, usize), Error> {
82 let mut piece_data = IoReader(Cursor::new(piece_data));
83
84 let segment_variant = piece_data
87 .read_byte()
88 .map_err(|source| Error::SegmentDecoding {
89 source,
90 segment_index,
91 mapping,
92 })?;
93 if segment_variant != SEGMENT_VERSION_VARIANT {
95 return Err(Error::UnknownSegmentVariant {
96 segment_variant,
97 segment_index,
98 mapping,
99 });
100 }
101
102 let segment_item =
104 SegmentItem::decode(&mut piece_data).map_err(|source| Error::SegmentDecoding {
105 source,
106 segment_index,
107 mapping,
108 })?;
109
110 let SegmentItem::ParentSegmentHeader(_) = segment_item else {
112 return Err(Error::UnexpectedSegmentItem {
113 segment_progress: piece_data.0.position() as usize,
114 segment_index,
115 segment_item: Box::new(segment_item),
116 mapping,
117 });
118 };
119
120 let segment_item_variant = piece_data
124 .read_byte()
125 .map_err(|source| Error::SegmentDecoding {
126 source,
127 segment_index,
128 mapping,
129 })?;
130
131 let header_bytes = piece_data.0.position() as usize;
133 let mut piece_data = piece_data.0.into_inner().split_off(header_bytes);
134 let segment_item_lengths = decode_data_length(&piece_data, MAX_BLOCK_LENGTH as usize, mapping)?;
135
136 if segment_item_variant != BLOCK_CONTINUATION_VARIANT || segment_item_lengths.is_none() {
138 return Err(Error::UnexpectedSegmentItemVariant {
139 segment_progress: header_bytes,
140 segment_index,
141 segment_item_variant,
142 segment_item_lengths,
143 mapping,
144 });
145 }
146
147 let (segment_item_prefix_len, segment_item_data_len) =
148 segment_item_lengths.expect("just checked length is Some; qed");
149 let mut piece_data = piece_data.split_off(segment_item_prefix_len);
151 piece_data.truncate(segment_item_data_len);
152
153 Ok((piece_data, segment_item_data_len))
154}
155
156#[cfg(test)]
157mod test {
158 use super::*;
159 use parity_scale_codec::{Compact, CompactLen};
160 use subspace_archiving::archiver::Segment;
161 use subspace_core_primitives::objects::BlockObjectMapping;
162
163 #[test]
164 fn max_segment_padding_constant() {
165 assert_eq!(
166 MAX_SEGMENT_PADDING,
167 Compact::compact_len(&MAX_BLOCK_LENGTH) - Compact::<u32>::compact_len(&1)
168 );
169 }
170
171 #[test]
172 fn segment_header_length_constants() {
173 assert!(
174 min_segment_header_encoded_size() < max_segment_header_encoded_size(),
175 "min_segment_header_encoded_size: {} must be less than max_segment_header_encoded_size: {}",
176 min_segment_header_encoded_size(),
177 max_segment_header_encoded_size()
178 );
179 }
180
181 #[test]
182 fn segment_version_variant_constant() {
183 let segment = Segment::V0 { items: Vec::new() };
184 let segment = segment.encode();
185
186 assert_eq!(segment[0], SEGMENT_VERSION_VARIANT);
187 }
188
189 #[test]
190 fn block_continuation_variant_constant() {
191 let block_continuation = SegmentItem::BlockContinuation {
192 bytes: Vec::new(),
193 object_mapping: BlockObjectMapping::default(),
194 };
195 let block_continuation = block_continuation.encode();
196
197 assert_eq!(block_continuation[0], BLOCK_CONTINUATION_VARIANT);
198 }
199}