revm_bytecode/eof/
body.rs

1use super::{CodeInfo, Eof, EofDecodeError, EofHeader};
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 code_info: Vec<CodeInfo>,
15    /// Index of the last byte of each code section
16    pub code_section: Vec<usize>,
17    /// Code byte, it is a concatenation of all code sections.
18    /// Interpreter uses this bytecode to execute the opcodes.
19    pub code: Bytes,
20    /// Offset of the code section in the bytecode.
21    pub code_offset: usize,
22    /// Container sections
23    pub container_section: Vec<Bytes>,
24    /// Data section
25    pub data_section: Bytes,
26    /// Indicates if the data section is filled.
27    ///
28    /// Unfilled data section are used in EOFCREATE/TXCREATE to
29    /// append data before deploying that contract to state.
30    ///
31    /// EOF containers that are in state and can be executed are required to have filled data section.
32    pub is_data_filled: bool,
33}
34
35impl EofBody {
36    /// Returns the code section at the given index.
37    pub fn code(&self, index: usize) -> Option<Bytes> {
38        if index == 0 {
39            // There should be at least one code section.
40            return Some(self.code.slice(..self.code_section[0]));
41        }
42        self.code_section
43            .get(index)
44            .map(|end| self.code.slice(self.code_section[index - 1]..*end))
45    }
46
47    /// Creates an EOF container from this body.
48    pub fn into_eof(self) -> Eof {
49        let mut prev_value = 0;
50        let header = EofHeader {
51            types_size: self.code_info.len() as u16 * 4,
52            code_sizes: self
53                .code_section
54                .iter()
55                .map(|x| {
56                    let ret = (x - prev_value) as u16;
57                    prev_value = *x;
58                    ret
59                })
60                .collect(),
61            container_sizes: self
62                .container_section
63                .iter()
64                .map(|x| x.len() as u32)
65                .collect(),
66            data_size: self.data_section.len() as u16,
67            sum_code_sizes: self.code.len(),
68            sum_container_sizes: self.container_section.iter().map(|x| x.len()).sum(),
69        };
70        let mut buffer = Vec::new();
71        header.encode(&mut buffer);
72        self.encode(&mut buffer);
73        Eof::decode(buffer.into()).expect("Failed to encode EOF")
74    }
75
76    /// Returns offset of the start of indexed code section.
77    ///
78    /// First code section starts at 0.
79    pub fn eof_code_section_start(&self, idx: usize) -> Option<usize> {
80        // Starting code section start with 0.
81        let code_offset = self.code_offset;
82        if idx == 0 {
83            return Some(code_offset);
84        }
85        self.code_section.get(idx - 1).map(|i| i + code_offset)
86    }
87
88    /// Encodes this body into the given buffer.
89    pub fn encode(&self, buffer: &mut Vec<u8>) {
90        for code_info in &self.code_info {
91            code_info.encode(buffer);
92        }
93
94        buffer.extend_from_slice(&self.code);
95
96        for container_section in &self.container_section {
97            buffer.extend_from_slice(container_section);
98        }
99
100        buffer.extend_from_slice(&self.data_section);
101    }
102
103    /// Decodes an EOF container body from the given buffer and header.
104    pub fn decode(input: &Bytes, header: &EofHeader) -> Result<Self, EofDecodeError> {
105        let header_len = header.size();
106        let partial_body_len = header
107            .sum_code_sizes
108            .saturating_add(header.sum_container_sizes)
109            .saturating_add(header.types_size as usize);
110        let full_body_len = partial_body_len.saturating_add(header.data_size as usize);
111
112        if input.len() < header_len.saturating_add(partial_body_len) {
113            return Err(EofDecodeError::MissingBodyWithoutData);
114        }
115
116        if input.len() > header_len.saturating_add(full_body_len) {
117            return Err(EofDecodeError::DanglingData);
118        }
119
120        let mut body = EofBody::default();
121
122        let mut types_input = &input[header_len..];
123        for _ in 0..header.types_count() {
124            let (code_info, local_input) = CodeInfo::decode(types_input)?;
125            types_input = local_input;
126            body.code_info.push(code_info);
127        }
128
129        // Extract code section
130        let start = header_len + header.types_size as usize;
131        body.code_offset = start;
132        let mut code_end = 0;
133        for size in header.code_sizes.iter().map(|x| *x as usize) {
134            code_end += size;
135            body.code_section.push(code_end);
136        }
137        body.code = input.slice(start..start + header.sum_code_sizes);
138
139        // Extract container section
140        let mut start = start + header.sum_code_sizes;
141        for size in header.container_sizes.iter().map(|x| *x as usize) {
142            body.container_section
143                .push(input.slice(start..start + size));
144            start += size;
145        }
146
147        body.data_section = input.slice(start..);
148        body.is_data_filled = body.data_section.len() == header.data_size as usize;
149
150        Ok(body)
151    }
152}