revm_bytecode/
eof.rs

1mod body;
2mod code_info;
3mod decode_helpers;
4mod header;
5pub mod printer;
6pub mod verification;
7
8pub use body::EofBody;
9pub use code_info::CodeInfo;
10pub use header::EofHeader;
11pub use verification::*;
12
13use core::cmp::min;
14use primitives::{b256, bytes, Bytes, B256};
15use std::{fmt, vec, vec::Vec};
16
17/// Hash of EF00 bytes that is used for EXTCODEHASH when called from legacy bytecode
18pub const EOF_MAGIC_HASH: B256 =
19    b256!("0x9dbf3648db8210552e9c4f75c6a1c3057c0ca432043bd648be15fe7be05646f5");
20
21/// EOF Magic in [u16] form
22pub const EOF_MAGIC: u16 = 0xEF00;
23
24/// EOF magic number in array form
25pub static EOF_MAGIC_BYTES: Bytes = bytes!("ef00");
26
27/// EVM Object Format (EOF) container
28///
29/// It consists of a header, body and the raw original bytes.
30#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct Eof {
33    pub header: EofHeader,
34    pub body: EofBody,
35    pub raw: Bytes,
36}
37
38impl Default for Eof {
39    fn default() -> Self {
40        let body = EofBody {
41            // Types section with zero inputs, zero outputs and zero max stack size.
42            code_info: vec![CodeInfo::default()],
43            code_section: vec![1],
44            // One code section with a STOP byte.
45            code: Bytes::from_static(&[0x00]),
46            code_offset: 0,
47            container_section: vec![],
48            data_section: Bytes::new(),
49            is_data_filled: true,
50        };
51        body.into_eof()
52    }
53}
54
55impl Eof {
56    /// Creates a new EOF container from the given body.
57    pub fn new(body: EofBody) -> Self {
58        body.into_eof()
59    }
60
61    /// Validates the EOF container.
62    pub fn validate(&self) -> Result<(), EofError> {
63        validate_eof(self)
64    }
65
66    /// Validates the raw EOF bytes.
67    pub fn validate_raw(bytes: Bytes) -> Result<Eof, EofError> {
68        validate_raw_eof(bytes)
69    }
70
71    /// Validates the EOF container with the given code type.   
72    pub fn validate_mode(&self, mode: CodeType) -> Result<(), EofError> {
73        validate_eof_inner(self, Some(mode))
74    }
75
76    /// Returns len of the header and body in bytes.
77    pub fn size(&self) -> usize {
78        self.header.size() + self.header.body_size()
79    }
80
81    /// Returns raw EOF bytes.
82    pub fn raw(&self) -> &Bytes {
83        &self.raw
84    }
85
86    /// Returns a slice of the raw bytes.
87    /// If offset is greater than the length of the raw bytes, an empty slice is returned.
88    /// If len is greater than the length of the raw bytes, the slice is truncated to the length of the raw bytes.
89    pub fn data_slice(&self, offset: usize, len: usize) -> &[u8] {
90        self.body
91            .data_section
92            .get(offset..)
93            .and_then(|bytes| bytes.get(..min(len, bytes.len())))
94            .unwrap_or(&[])
95    }
96
97    /// Returns a slice of the data section.
98    pub fn data(&self) -> &[u8] {
99        &self.body.data_section
100    }
101
102    /// Slow encodes EOF bytes.
103    pub fn encode_slow(&self) -> Bytes {
104        let mut buffer: Vec<u8> = Vec::with_capacity(self.size());
105        self.header.encode(&mut buffer);
106        self.body.encode(&mut buffer);
107        buffer.into()
108    }
109
110    /// Decodes EOF that have additional dangling bytes.
111    ///
112    /// Assume that data section is fully filled.
113    pub fn decode_dangling(mut raw: Bytes) -> Result<(Self, Bytes), EofDecodeError> {
114        let (header, _) = EofHeader::decode(&raw)?;
115        let eof_size = header.body_size() + header.size();
116        if eof_size > raw.len() {
117            return Err(EofDecodeError::MissingInput);
118        }
119        let dangling_data = raw.split_off(eof_size);
120        let body = EofBody::decode(&raw, &header)?;
121        Ok((Self { header, body, raw }, dangling_data))
122    }
123
124    /// Decodes EOF from raw bytes.
125    pub fn decode(raw: Bytes) -> Result<Self, EofDecodeError> {
126        let (header, _) = EofHeader::decode(&raw)?;
127        let body = EofBody::decode(&raw, &header)?;
128        Ok(Self { header, body, raw })
129    }
130}
131
132/// EOF decode errors
133#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
134#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
135pub enum EofDecodeError {
136    /// Short input while processing EOF
137    MissingInput,
138    /// Short body while processing EOF
139    MissingBodyWithoutData,
140    /// Body size is more than specified in the header
141    DanglingData,
142    /// Invalid code info data
143    InvalidCodeInfo,
144    /// Invalid code info size
145    InvalidCodeInfoSize,
146    /// Invalid EOF magic number
147    InvalidEOFMagicNumber,
148    /// Invalid EOF version
149    InvalidEOFVersion,
150    /// Invalid number for types kind
151    InvalidTypesKind,
152    /// Invalid number for code kind
153    InvalidCodeKind,
154    /// Invalid terminal code
155    InvalidTerminalByte,
156    /// Invalid data kind
157    InvalidDataKind,
158    /// Invalid kind after code
159    InvalidKindAfterCode,
160    /// Mismatch of code and info sizes
161    MismatchCodeAndInfoSize,
162    /// There should be at least one size
163    NonSizes,
164    /// Missing size
165    ShortInputForSizes,
166    /// Size cant be zero
167    ZeroSize,
168    /// Invalid code number
169    TooManyCodeSections,
170    /// Invalid number of code sections
171    ZeroCodeSections,
172    /// Invalid container number
173    TooManyContainerSections,
174    /// Invalid initcode size
175    InvalidEOFSize,
176}
177
178impl fmt::Display for EofDecodeError {
179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180        let s = match self {
181            Self::MissingInput => "Short input while processing EOF",
182            Self::MissingBodyWithoutData => "Short body while processing EOF",
183            Self::DanglingData => "Body size is more than specified in the header",
184            Self::InvalidCodeInfo => "Invalid types section data",
185            Self::InvalidCodeInfoSize => "Invalid types section size",
186            Self::InvalidEOFMagicNumber => "Invalid EOF magic number",
187            Self::InvalidEOFVersion => "Invalid EOF version",
188            Self::InvalidTypesKind => "Invalid number for types kind",
189            Self::InvalidCodeKind => "Invalid number for code kind",
190            Self::InvalidTerminalByte => "Invalid terminal code",
191            Self::InvalidDataKind => "Invalid data kind",
192            Self::InvalidKindAfterCode => "Invalid kind after code",
193            Self::MismatchCodeAndInfoSize => "Mismatch of code and types sizes",
194            Self::NonSizes => "There should be at least one size",
195            Self::ShortInputForSizes => "Missing size",
196            Self::ZeroSize => "Size cant be zero",
197            Self::TooManyCodeSections => "Invalid code number",
198            Self::ZeroCodeSections => "Invalid number of code sections",
199            Self::TooManyContainerSections => "Invalid container number",
200            Self::InvalidEOFSize => "Invalid initcode size",
201        };
202        f.write_str(s)
203    }
204}
205
206impl core::error::Error for EofDecodeError {}
207
208#[cfg(test)]
209mod test {
210
211    use super::*;
212    use primitives::bytes;
213
214    #[test]
215    fn decode_eof() {
216        let bytes = bytes!("ef000101000402000100010400000000800000fe");
217        let eof = Eof::decode(bytes.clone()).unwrap();
218        assert_eq!(bytes, eof.encode_slow());
219    }
220
221    #[test]
222    fn decode_eof_dangling() {
223        let test_cases = [
224            (
225                bytes!("ef000101000402000100010400000000800000fe"),
226                bytes!("010203"),
227                false,
228            ),
229            (
230                bytes!("ef000101000402000100010400000000800000fe"),
231                bytes!(""),
232                false,
233            ),
234            (
235                bytes!("ef000101000402000100010400000000800000"),
236                bytes!(""),
237                true,
238            ),
239        ];
240
241        for (eof_bytes, dangling_data, is_err) in test_cases {
242            let mut raw = eof_bytes.to_vec();
243            raw.extend(&dangling_data);
244            let raw = Bytes::from(raw);
245
246            let result = Eof::decode_dangling(raw.clone());
247            assert_eq!(result.is_err(), is_err);
248            if is_err {
249                continue;
250            }
251            let (decoded_eof, decoded_dangling) = result.unwrap();
252            assert_eq!(eof_bytes, decoded_eof.encode_slow());
253            assert_eq!(decoded_dangling, dangling_data);
254        }
255    }
256
257    #[test]
258    fn data_slice() {
259        let bytes = bytes!("ef000101000402000100010400000000800000fe");
260        let mut eof = Eof::decode(bytes.clone()).unwrap();
261        eof.body.data_section = bytes!("01020304");
262        assert_eq!(eof.data_slice(0, 1), &[0x01]);
263        assert_eq!(eof.data_slice(0, 4), &[0x01, 0x02, 0x03, 0x04]);
264        assert_eq!(eof.data_slice(0, 5), &[0x01, 0x02, 0x03, 0x04]);
265        assert_eq!(eof.data_slice(1, 2), &[0x02, 0x03]);
266
267        const EMPTY: &[u8] = &[];
268        assert_eq!(eof.data_slice(10, 2), EMPTY);
269        assert_eq!(eof.data_slice(1, 0), EMPTY);
270        assert_eq!(eof.data_slice(10, 0), EMPTY);
271    }
272}