revm_bytecode/eof/
header.rs

1use super::{
2    decode_helpers::{consume_u16, consume_u8},
3    EofDecodeError,
4};
5use std::vec::Vec;
6
7/// EOF header structure that contains section sizes and metadata
8#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct EofHeader {
11    /// Size of EOF types section
12    ///
13    /// Types section includes num of input and outputs and max stack size.
14    pub types_size: u16,
15    /// Sizes of EOF code section
16    ///
17    /// Code size can't be zero.
18    pub code_sizes: Vec<u16>,
19    /// EOF Container size
20    ///
21    /// Container size can be zero.
22    pub container_sizes: Vec<u32>,
23    /// EOF data size
24    pub data_size: u16,
25    /// Sum of code sizes
26    pub sum_code_sizes: usize,
27    /// Sum of container sizes
28    pub sum_container_sizes: usize,
29}
30
31/// EOF header terminal kind, marking end of header.
32pub const KIND_TERMINAL: u8 = 0;
33/// EOF header code info kind, marking code info section.
34pub const KIND_CODE_INFO: u8 = 1;
35/// EOF header code kind, marking code section.
36pub const KIND_CODE: u8 = 2;
37/// EOF header container kind, marking container section.
38pub const KIND_CONTAINER: u8 = 3;
39/// EOF header data kind, marking data section.
40pub const KIND_DATA: u8 = 0xff;
41/// EOF header code section size length.
42pub const CODE_SECTION_SIZE: usize = 2;
43/// EOF header container section size length.
44pub const CONTAINER_SECTION_SIZE: usize = 4;
45
46/// Consumes code section from Header.
47///
48/// It returns rest of the input, list of sizes and sum of all sizes.
49#[inline]
50fn consume_header_code_section(input: &[u8]) -> Result<(&[u8], Vec<u16>, usize), EofDecodeError> {
51    // `num_sections`   2 bytes 0x0001-0xFFFF
52    // 16-bit unsigned big-endian integer denoting the number of the sections
53    let (input, num_sections) = consume_u16(input)?;
54    if num_sections == 0 {
55        return Err(EofDecodeError::NonSizes);
56    }
57    let num_sections = num_sections as usize;
58    let byte_size = num_sections * CODE_SECTION_SIZE;
59    if input.len() < byte_size {
60        return Err(EofDecodeError::ShortInputForSizes);
61    }
62    let mut sizes = Vec::with_capacity(num_sections);
63    let mut sum = 0;
64    for i in 0..num_sections {
65        // `code_size`  2 bytes 0x0001-0xFFFF
66        // 16-bit unsigned big-endian integer denoting the length of the section content
67        let code_size = u16::from_be_bytes([
68            input[i * CODE_SECTION_SIZE],
69            input[i * CODE_SECTION_SIZE + 1],
70        ]);
71        if code_size == 0 {
72            return Err(EofDecodeError::ZeroSize);
73        }
74        sum += code_size as usize;
75        sizes.push(code_size);
76    }
77
78    Ok((&input[byte_size..], sizes, sum))
79}
80
81/// Consumes container section from Header.
82///
83/// Similar to [`consume_header_code_section`] but it takes u32 bytes for containers size.
84#[inline]
85fn consume_header_container_section(
86    input: &[u8],
87) -> Result<(&[u8], Vec<u32>, usize), EofDecodeError> {
88    // `num_sections`   2 bytes 0x0001-0xFFFF
89    // 16-bit unsigned big-endian integer denoting the number of the sections
90    let (input, num_sections) = consume_u16(input)?;
91    if num_sections == 0 {
92        return Err(EofDecodeError::NonSizes);
93    }
94    let num_sections = num_sections as usize;
95    let byte_size = num_sections * CONTAINER_SECTION_SIZE;
96    if input.len() < byte_size {
97        return Err(EofDecodeError::ShortInputForSizes);
98    }
99    let mut sizes = Vec::with_capacity(num_sections);
100    let mut sum = 0;
101    for i in 0..num_sections {
102        // `section_size` is 4 bytes 0x00000001-0xFFFFFFFF
103        // 32-bit unsigned big-endian integer denoting the length of the section content
104        let container_size = u32::from_be_bytes(
105            input[i * CONTAINER_SECTION_SIZE..(i + 1) * CONTAINER_SECTION_SIZE]
106                .try_into()
107                .unwrap(),
108        );
109
110        if container_size == 0 {
111            return Err(EofDecodeError::ZeroSize);
112        }
113        sum += container_size as usize;
114        sizes.push(container_size);
115    }
116
117    Ok((&input[byte_size..], sizes, sum))
118}
119
120impl EofHeader {
121    /// Gets the length of the header in bytes.
122    ///
123    /// It is minimum 15 bytes (there is at least one code section).
124    pub fn size(&self) -> usize {
125        2 + // Magic
126        1 + // Version
127        3 + // Types section
128        3 + // Code section
129        CODE_SECTION_SIZE * self.code_sizes.len() + // `num_code_sections`
130        if self.container_sizes.is_empty() { 0 } else { 3 + CONTAINER_SECTION_SIZE * self.container_sizes.len() } + // Container
131        3 + // Data section.
132        1 // Terminator
133    }
134
135    /// Returns index where data size starts.
136    ///
137    /// Data size is two bytes long.
138    pub fn data_size_raw_i(&self) -> usize {
139        // termination(1byte) + code size(2) bytes.
140        self.size() - 3
141    }
142
143    /// Returns number of types.
144    pub fn types_count(&self) -> usize {
145        self.types_size as usize / 4
146    }
147
148    /// Returns body size.
149    ///
150    /// It is sum of code sizes, container sizes and data size.
151    pub fn body_size(&self) -> usize {
152        self.types_size as usize
153            + self.sum_code_sizes
154            + self.sum_container_sizes
155            + self.data_size as usize
156    }
157
158    /// Returns raw size of the EOF.
159    pub fn eof_size(&self) -> usize {
160        self.size() + self.body_size()
161    }
162
163    /// Encodes EOF header into binary form.
164    pub fn encode(&self, buffer: &mut Vec<u8>) {
165        // `magic`	2 bytes	0xEF00	EOF prefix
166        buffer.extend_from_slice(&0xEF00u16.to_be_bytes());
167        // `version`	1 byte	0x01	EOF version
168        buffer.push(0x01);
169        // `kind_types`	1 byte	0x01	kind marker for types size section
170        buffer.push(KIND_CODE_INFO);
171        // `types_size`	2 bytes	0x0004-0xFFFF
172        buffer.extend_from_slice(&self.types_size.to_be_bytes());
173        // `kind_code`	1 byte	0x02	kind marker for code size section
174        buffer.push(KIND_CODE);
175        // `code_sections_sizes`
176        buffer.extend_from_slice(&(self.code_sizes.len() as u16).to_be_bytes());
177        for size in &self.code_sizes {
178            buffer.extend_from_slice(&size.to_be_bytes());
179        }
180        // `kind_container_or_data`	1 byte	0x03 or 0xff kind marker for container size section or data size section
181        if !self.container_sizes.is_empty() {
182            buffer.push(KIND_CONTAINER);
183            // `container_sections_sizes`
184            buffer.extend_from_slice(&(self.container_sizes.len() as u16).to_be_bytes());
185            for size in &self.container_sizes {
186                buffer.extend_from_slice(&size.to_be_bytes());
187            }
188        }
189
190        // `kind_data`	1 byte	0xff	kind marker for data size section
191        buffer.push(KIND_DATA);
192        // `data_size`	2 bytes	0x0000-0xFFFF	16-bit unsigned big-endian integer denoting the length of the data section content
193        buffer.extend_from_slice(&self.data_size.to_be_bytes());
194        // `terminator`	1 byte	0x00	marks the end of the EofHeader
195        buffer.push(KIND_TERMINAL);
196    }
197
198    /// Decodes EOF header from binary form.
199    /// Format of the code section is:
200    /// 0xEF000101 | u16  | 0x02 | u16 | u16 * cnum | 0x03 | u16 | cnum* u32 | 0xff | u16 | 0x00
201    pub fn decode(input: &[u8]) -> Result<(Self, &[u8]), EofDecodeError> {
202        let mut header = EofHeader::default();
203
204        // `magic`	2 bytes	0xEF00	EOF prefix
205        let (input, kind) = consume_u16(input)?;
206        if kind != 0xEF00 {
207            return Err(EofDecodeError::InvalidEOFMagicNumber);
208        }
209
210        // `version`	1 byte	0x01	EOF version
211        let (input, version) = consume_u8(input)?;
212        if version != 0x01 {
213            return Err(EofDecodeError::InvalidEOFVersion);
214        }
215
216        // `kind_types`	1 byte	0x01	kind marker for types size section
217        let (input, kind_code_info) = consume_u8(input)?;
218        if kind_code_info != KIND_CODE_INFO {
219            return Err(EofDecodeError::InvalidTypesKind);
220        }
221
222        // `types_size`	2 bytes	0x0004-0xFFFF
223        // 16-bit unsigned big-endian integer denoting the length of the type section content
224        let (input, types_size) = consume_u16(input)?;
225        header.types_size = types_size;
226
227        // types size
228        if header.types_size % CODE_SECTION_SIZE as u16 != 0 {
229            return Err(EofDecodeError::InvalidCodeInfo);
230        }
231
232        // `kind_code`	1 byte	0x02	kind marker for code size section
233        let (input, kind_code) = consume_u8(input)?;
234        if kind_code != KIND_CODE {
235            return Err(EofDecodeError::InvalidCodeKind);
236        }
237
238        // `code_sections_sizes`
239        let (input, sizes, sum) = consume_header_code_section(input)?;
240
241        // more than 1024 code sections are not allowed
242        if sizes.len() > 0x0400 {
243            return Err(EofDecodeError::TooManyCodeSections);
244        }
245
246        if sizes.is_empty() {
247            return Err(EofDecodeError::ZeroCodeSections);
248        }
249
250        if sizes.len() != (types_size / 4) as usize {
251            return Err(EofDecodeError::MismatchCodeAndInfoSize);
252        }
253
254        header.code_sizes = sizes;
255        header.sum_code_sizes = sum;
256
257        let (input, kind_container_or_data) = consume_u8(input)?;
258
259        let input = match kind_container_or_data {
260            KIND_CONTAINER => {
261                // container_sections_sizes
262                let (input, sizes, sum) = consume_header_container_section(input)?;
263                // the number of container sections may not exceed 256
264                if sizes.len() > 0x0100 {
265                    return Err(EofDecodeError::TooManyContainerSections);
266                }
267                header.container_sizes = sizes;
268                header.sum_container_sizes = sum;
269                let (input, kind_data) = consume_u8(input)?;
270                if kind_data != KIND_DATA {
271                    return Err(EofDecodeError::InvalidDataKind);
272                }
273                input
274            }
275            KIND_DATA => input,
276            invalid_kind => return Err(EofDecodeError::InvalidKindAfterCode { invalid_kind }),
277        };
278
279        // `data_size`	2 bytes	0x0000-0xFFFF	16-bit
280        // unsigned big-endian integer denoting the length
281        // of the data section content (for not yet deployed
282        // containers this can be more than the actual content, see Data Section Lifecycle)
283        let (input, data_size) = consume_u16(input)?;
284        header.data_size = data_size;
285
286        // `terminator`	1 byte	0x00	marks the end of the EofHeader
287        let (input, terminator) = consume_u8(input)?;
288        if terminator != KIND_TERMINAL {
289            return Err(EofDecodeError::InvalidTerminalByte);
290        }
291
292        Ok((header, input))
293    }
294}
295
296#[cfg(test)]
297mod tests {
298    use super::*;
299    use primitives::hex;
300    use std::vec;
301
302    #[test]
303    fn sanity_header_decode() {
304        let input = hex!("ef00010100040200010001ff00000000800000fe");
305        let (header, _) = EofHeader::decode(&input).unwrap();
306        assert_eq!(header.types_size, 4);
307        assert_eq!(header.code_sizes, vec![1]);
308        assert_eq!(header.container_sizes, Vec::new());
309        assert_eq!(header.data_size, 0);
310    }
311
312    #[test]
313    fn decode_header_not_terminated() {
314        let input = hex!("ef0001010004");
315        assert_eq!(EofHeader::decode(&input), Err(EofDecodeError::MissingInput));
316    }
317
318    #[test]
319    fn failing_test() {
320        let input = hex!("ef0001010004020001000603000100000014ff000200008000016000e0000000ef000101000402000100010400000000800000fe");
321        let _ = EofHeader::decode(&input).unwrap();
322    }
323
324    #[test]
325    fn cut_header() {
326        let input = hex!("ef0001010000028000");
327        assert_eq!(
328            EofHeader::decode(&input),
329            Err(EofDecodeError::ShortInputForSizes)
330        );
331    }
332
333    #[test]
334    fn short_input() {
335        let input = hex!("ef0001010000028000");
336        assert_eq!(
337            EofHeader::decode(&input),
338            Err(EofDecodeError::ShortInputForSizes)
339        );
340    }
341}