revm_primitives/bytecode/eof/
header.rs

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