kona_protocol/
frame.rs

1//! Frame Types
2
3use crate::ChannelId;
4use alloc::vec::Vec;
5
6/// The version of the derivation pipeline.
7pub const DERIVATION_VERSION_0: u8 = 0;
8
9/// Count the tagging info as 200 in terms of buffer size.
10pub const FRAME_OVERHEAD: usize = 200;
11
12/// Frames cannot be larger than 1MB.
13///
14/// Data transactions that carry frames are generally not larger than 128 KB due to L1 network
15/// conditions, but we leave space to grow larger anyway (gas limit allows for more data).
16pub const MAX_FRAME_LEN: usize = 1_000_000;
17
18/// A frame decoding error.
19#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum FrameDecodingError {
21    /// The frame data is too large.
22    #[error("Frame data too large: {0} bytes")]
23    DataTooLarge(usize),
24    /// The frame data is too short.
25    #[error("Frame data too short: {0} bytes")]
26    DataTooShort(usize),
27    /// Error decoding the frame id.
28    #[error("Invalid frame id")]
29    InvalidId,
30    /// Error decoding the frame number.
31    #[error("Invalid frame number")]
32    InvalidNumber,
33    /// Error decoding the frame data length.
34    #[error("Invalid frame data length")]
35    InvalidDataLength,
36}
37
38/// Frame parsing error.
39#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq, Hash)]
40pub enum FrameParseError {
41    /// Error parsing the frame data.
42    #[error("Frame decoding error: {0}")]
43    FrameDecodingError(FrameDecodingError),
44    /// No frames to parse.
45    #[error("No frames to parse")]
46    NoFrames,
47    /// Unsupported derivation version.
48    #[error("Unsupported derivation version")]
49    UnsupportedVersion,
50    /// Frame data length mismatch.
51    #[error("Frame data length mismatch")]
52    DataLengthMismatch,
53    /// No frames decoded.
54    #[error("No frames decoded")]
55    NoFramesDecoded,
56}
57
58/// A channel frame is a segment of a channel's data.
59///
60/// *Encoding*
61/// frame = `channel_id ++ frame_number ++ frame_data_length ++ frame_data ++ is_last`
62/// * channel_id        = bytes16
63/// * frame_number      = uint16
64/// * frame_data_length = uint32
65/// * frame_data        = bytes
66/// * is_last           = bool
67#[derive(Debug, Clone, PartialEq, Eq, Default)]
68pub struct Frame {
69    /// The unique idetifier for the frame.
70    pub id: ChannelId,
71    /// The number of the frame.
72    pub number: u16,
73    /// The data within the frame.
74    pub data: Vec<u8>,
75    /// Whether or not the frame is the last in the sequence.
76    pub is_last: bool,
77}
78
79impl Frame {
80    /// Creates a new [Frame].
81    pub const fn new(id: ChannelId, number: u16, data: Vec<u8>, is_last: bool) -> Self {
82        Self { id, number, data, is_last }
83    }
84
85    /// Encode the frame into a byte vector.
86    pub fn encode(&self) -> Vec<u8> {
87        let mut encoded = Vec::with_capacity(16 + 2 + 4 + self.data.len() + 1);
88        encoded.extend_from_slice(&self.id);
89        encoded.extend_from_slice(&self.number.to_be_bytes());
90        encoded.extend_from_slice(&(self.data.len() as u32).to_be_bytes());
91        encoded.extend_from_slice(&self.data);
92        encoded.push(self.is_last as u8);
93        encoded
94    }
95
96    /// Decode a frame from a byte vector.
97    pub fn decode(encoded: &[u8]) -> Result<(usize, Self), FrameDecodingError> {
98        const BASE_FRAME_LEN: usize = 16 + 2 + 4 + 1;
99
100        if encoded.len() < BASE_FRAME_LEN {
101            return Err(FrameDecodingError::DataTooShort(encoded.len()));
102        }
103
104        let id = encoded[..16].try_into().map_err(|_| FrameDecodingError::InvalidId)?;
105        let number = u16::from_be_bytes(
106            encoded[16..18].try_into().map_err(|_| FrameDecodingError::InvalidNumber)?,
107        );
108        let data_len = u32::from_be_bytes(
109            encoded[18..22].try_into().map_err(|_| FrameDecodingError::InvalidDataLength)?,
110        ) as usize;
111
112        if data_len > MAX_FRAME_LEN || data_len >= encoded.len() - (BASE_FRAME_LEN - 1) {
113            return Err(FrameDecodingError::DataTooLarge(data_len));
114        }
115
116        let data = encoded[22..22 + data_len].to_vec();
117        let is_last = encoded[22 + data_len] == 1;
118        Ok((BASE_FRAME_LEN + data_len, Self { id, number, data, is_last }))
119    }
120
121    /// Parses a single frame from the given data at the given starting position,
122    /// returning the frame and the number of bytes consumed.
123    pub fn parse_frame(data: &[u8], start: usize) -> Result<(usize, Self), FrameDecodingError> {
124        let (frame_len, frame) = Self::decode(&data[start..])?;
125        Ok((frame_len, frame))
126    }
127
128    /// Parse the on chain serialization of frame(s) in an L1 transaction. Currently
129    /// only version 0 of the serialization format is supported. All frames must be parsed
130    /// without error and there must not be any left over data and there must be at least one
131    /// frame.
132    ///
133    /// Frames are stored in L1 transactions with the following format:
134    /// * `data = DerivationVersion0 ++ Frame(s)` Where there is one or more frames concatenated
135    ///   together.
136    pub fn parse_frames(encoded: &[u8]) -> Result<Vec<Self>, FrameParseError> {
137        if encoded.is_empty() {
138            return Err(FrameParseError::NoFrames);
139        }
140        if encoded[0] != DERIVATION_VERSION_0 {
141            return Err(FrameParseError::UnsupportedVersion);
142        }
143
144        let data = &encoded[1..];
145        let mut frames = Vec::new();
146        let mut offset = 0;
147        while offset < data.len() {
148            let (frame_length, frame) =
149                Self::decode(&data[offset..]).map_err(FrameParseError::FrameDecodingError)?;
150            frames.push(frame);
151            offset += frame_length;
152        }
153
154        if offset != data.len() {
155            return Err(FrameParseError::DataLengthMismatch);
156        }
157        if frames.is_empty() {
158            return Err(FrameParseError::NoFramesDecoded);
159        }
160
161        Ok(frames)
162    }
163
164    /// Calculates the size of the frame + overhead for storing the frame. The sum of the frame size
165    /// of each frame in a channel determines the channel's size. The sum of the channel sizes
166    /// is used for pruning & compared against the max channel bank size.
167    pub fn size(&self) -> usize {
168        self.data.len() + FRAME_OVERHEAD
169    }
170}
171
172#[cfg(test)]
173mod test {
174    use super::*;
175    use alloc::vec;
176
177    #[test]
178    fn test_encode_frame_roundtrip() {
179        let frame = Frame { id: [0xFF; 16], number: 0xEE, data: vec![0xDD; 50], is_last: true };
180
181        let (_, frame_decoded) = Frame::decode(&frame.encode()).unwrap();
182        assert_eq!(frame, frame_decoded);
183    }
184
185    #[test]
186    fn test_data_too_short() {
187        let frame = Frame { id: [0xFF; 16], number: 0xEE, data: vec![0xDD; 22], is_last: true };
188        let err = Frame::decode(&frame.encode()[..22]).unwrap_err();
189        assert_eq!(err, FrameDecodingError::DataTooShort(22));
190    }
191
192    #[test]
193    fn test_decode_exceeds_max_data_len() {
194        let frame = Frame {
195            id: [0xFF; 16],
196            number: 0xEE,
197            data: vec![0xDD; MAX_FRAME_LEN + 1],
198            is_last: true,
199        };
200        let err = Frame::decode(&frame.encode()).unwrap_err();
201        assert_eq!(err, FrameDecodingError::DataTooLarge(MAX_FRAME_LEN + 1));
202    }
203
204    #[test]
205    fn test_decode_malicious_data_len() {
206        let frame = Frame { id: [0xFF; 16], number: 0xEE, data: vec![0xDD; 50], is_last: true };
207        let mut encoded = frame.encode();
208        let data_len = (encoded.len() - 22) as u32;
209        encoded[18..22].copy_from_slice(&data_len.to_be_bytes());
210
211        let err = Frame::decode(&encoded).unwrap_err();
212        assert_eq!(err, FrameDecodingError::DataTooLarge(encoded.len() - 22_usize));
213
214        let valid_data_len = (encoded.len() - 23) as u32;
215        encoded[18..22].copy_from_slice(&valid_data_len.to_be_bytes());
216        let (_, frame_decoded) = Frame::decode(&encoded).unwrap();
217        assert_eq!(frame, frame_decoded);
218    }
219
220    #[test]
221    fn test_decode_many() {
222        let frame = Frame { id: [0xFF; 16], number: 0xEE, data: vec![0xDD; 50], is_last: true };
223        let mut bytes = Vec::new();
224        bytes.extend_from_slice(&[DERIVATION_VERSION_0]);
225        (0..5).for_each(|_| {
226            bytes.extend_from_slice(&frame.encode());
227        });
228
229        let frames = Frame::parse_frames(bytes.as_slice()).unwrap();
230        assert_eq!(frames.len(), 5);
231        (0..5).for_each(|i| {
232            assert_eq!(frames[i], frame);
233        });
234    }
235}