revm_bytecode/eof/
body.rs

1use super::{Eof, EofDecodeError, EofHeader, TypesSection};
2use primitives::Bytes;
3use std::vec::Vec;
4
5/// EOF container body
6///
7/// Contains types, code, container and data sections.
8///
9/// Can be used to create a new EOF container using the [`into_eof`](EofBody::into_eof) method.
10#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct EofBody {
13    /// Code information
14    pub types_section: Vec<TypesSection>,
15    /// Index of the last byte of each code section
16    pub code_section: Vec<usize>,
17    pub code: Bytes,
18    pub code_offset: usize,
19    pub container_section: Vec<Bytes>,
20    pub data_section: Bytes,
21    pub is_data_filled: bool,
22}
23
24impl EofBody {
25    /// Returns the code section at the given index.
26    pub fn code(&self, index: usize) -> Option<Bytes> {
27        if index == 0 {
28            // There should be at least one code section.
29            return Some(self.code.slice(..self.code_section[0]));
30        }
31        self.code_section
32            .get(index)
33            .map(|end| self.code.slice(self.code_section[index - 1]..*end))
34    }
35
36    /// Creates an EOF container from this body.
37    pub fn into_eof(self) -> Eof {
38        let mut prev_value = 0;
39        let header = EofHeader {
40            types_size: self.types_section.len() as u16 * 4,
41            code_sizes: self
42                .code_section
43                .iter()
44                .map(|x| {
45                    let ret = (x - prev_value) as u16;
46                    prev_value = *x;
47                    ret
48                })
49                .collect(),
50            container_sizes: self
51                .container_section
52                .iter()
53                .map(|x| x.len() as u16)
54                .collect(),
55            data_size: self.data_section.len() as u16,
56            sum_code_sizes: self.code.len(),
57            sum_container_sizes: self.container_section.iter().map(|x| x.len()).sum(),
58        };
59        let mut buffer = Vec::new();
60        header.encode(&mut buffer);
61        self.encode(&mut buffer);
62        Eof::decode(buffer.into()).expect("Failed to encode EOF")
63    }
64
65    /// Returns offset of the start of indexed code section.
66    ///
67    /// First code section starts at 0.
68    pub fn eof_code_section_start(&self, idx: usize) -> Option<usize> {
69        // Starting code section start with 0.
70        let code_offset = self.code_offset;
71        if idx == 0 {
72            return Some(code_offset);
73        }
74        self.code_section.get(idx - 1).map(|i| i + code_offset)
75    }
76
77    /// Encodes this body into the given buffer.
78    pub fn encode(&self, buffer: &mut Vec<u8>) {
79        for types_section in &self.types_section {
80            types_section.encode(buffer);
81        }
82
83        buffer.extend_from_slice(&self.code);
84
85        for container_section in &self.container_section {
86            buffer.extend_from_slice(container_section);
87        }
88
89        buffer.extend_from_slice(&self.data_section);
90    }
91
92    /// Decodes an EOF container body from the given buffer and header.
93    pub fn decode(input: &Bytes, header: &EofHeader) -> Result<Self, EofDecodeError> {
94        let header_len = header.size();
95        let partial_body_len =
96            header.sum_code_sizes + header.sum_container_sizes + header.types_size as usize;
97        let full_body_len = partial_body_len + header.data_size as usize;
98
99        if input.len() < header_len + partial_body_len {
100            return Err(EofDecodeError::MissingBodyWithoutData);
101        }
102
103        if input.len() > header_len + full_body_len {
104            return Err(EofDecodeError::DanglingData);
105        }
106
107        let mut body = EofBody::default();
108
109        let mut types_input = &input[header_len..];
110        for _ in 0..header.types_count() {
111            let (types_section, local_input) = TypesSection::decode(types_input)?;
112            types_input = local_input;
113            body.types_section.push(types_section);
114        }
115
116        // Extract code section
117        let start = header_len + header.types_size as usize;
118        body.code_offset = start;
119        let mut code_end = 0;
120        for size in header.code_sizes.iter().map(|x| *x as usize) {
121            code_end += size;
122            body.code_section.push(code_end);
123        }
124        body.code = input.slice(start..start + header.sum_code_sizes);
125
126        // Extract container section
127        let mut start = start + header.sum_code_sizes;
128        for size in header.container_sizes.iter().map(|x| *x as usize) {
129            body.container_section
130                .push(input.slice(start..start + size));
131            start += size;
132        }
133
134        body.data_section = input.slice(start..);
135        body.is_data_filled = body.data_section.len() == header.data_size as usize;
136
137        Ok(body)
138    }
139}