revm_primitives/
bytecode.rs

1pub mod eof;
2pub mod legacy;
3
4pub use eof::{Eof, EOF_MAGIC, EOF_MAGIC_BYTES, EOF_MAGIC_HASH};
5pub use legacy::{JumpTable, LegacyAnalyzedBytecode};
6
7use crate::{
8    eip7702::bytecode::Eip7702DecodeError, keccak256, Bytes, Eip7702Bytecode, B256,
9    EIP7702_MAGIC_BYTES, KECCAK_EMPTY,
10};
11use alloy_primitives::Address;
12use core::fmt::Debug;
13use eof::EofDecodeError;
14use std::{fmt, sync::Arc};
15
16/// State of the [`Bytecode`] analysis.
17#[derive(Clone, Debug, PartialEq, Eq, Hash)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub enum Bytecode {
20    /// No analysis has been performed.
21    LegacyRaw(Bytes),
22    /// The bytecode has been analyzed for valid jump destinations.
23    LegacyAnalyzed(LegacyAnalyzedBytecode),
24    /// Ethereum Object Format
25    Eof(Arc<Eof>),
26    /// EIP-7702 delegated bytecode
27    Eip7702(Eip7702Bytecode),
28}
29
30impl Default for Bytecode {
31    #[inline]
32    fn default() -> Self {
33        // Creates a new legacy analyzed [`Bytecode`] with exactly one STOP opcode.
34        Self::new()
35    }
36}
37
38impl Bytecode {
39    // Creates a new legacy analyzed [`Bytecode`] with exactly one STOP opcode.
40    #[inline]
41    pub fn new() -> Self {
42        Self::LegacyAnalyzed(LegacyAnalyzedBytecode::default())
43    }
44
45    /// Return jump table if bytecode is analyzed
46    #[inline]
47    pub fn legacy_jump_table(&self) -> Option<&JumpTable> {
48        match &self {
49            Self::LegacyAnalyzed(analyzed) => Some(analyzed.jump_table()),
50            _ => None,
51        }
52    }
53
54    /// Calculate hash of the bytecode.
55    pub fn hash_slow(&self) -> B256 {
56        if self.is_empty() {
57            KECCAK_EMPTY
58        } else {
59            keccak256(self.original_byte_slice())
60        }
61    }
62
63    /// Return reference to the EOF if bytecode is EOF.
64    #[inline]
65    pub const fn eof(&self) -> Option<&Arc<Eof>> {
66        match self {
67            Self::Eof(eof) => Some(eof),
68            _ => None,
69        }
70    }
71
72    /// Returns true if bytecode is EOF.
73    #[inline]
74    pub const fn is_eof(&self) -> bool {
75        matches!(self, Self::Eof(_))
76    }
77
78    /// Returns true if bytecode is EIP-7702.
79    pub const fn is_eip7702(&self) -> bool {
80        matches!(self, Self::Eip7702(_))
81    }
82
83    /// Creates a new legacy [`Bytecode`].
84    #[inline]
85    pub fn new_legacy(raw: Bytes) -> Self {
86        Self::LegacyRaw(raw)
87    }
88
89    /// Creates a new raw [`Bytecode`].
90    ///
91    /// # Panics
92    ///
93    /// Panics if bytecode is in incorrect format.
94    #[inline]
95    pub fn new_raw(bytecode: Bytes) -> Self {
96        Self::new_raw_checked(bytecode).expect("Expect correct EOF bytecode")
97    }
98
99    /// Creates a new EIP-7702 [`Bytecode`] from [`Address`].
100    #[inline]
101    pub fn new_eip7702(address: Address) -> Self {
102        Self::Eip7702(Eip7702Bytecode::new(address))
103    }
104
105    /// Creates a new raw [`Bytecode`].
106    ///
107    /// Returns an error on incorrect Bytecode format.
108    #[inline]
109    pub fn new_raw_checked(bytecode: Bytes) -> Result<Self, BytecodeDecodeError> {
110        let prefix = bytecode.get(..2);
111        match prefix {
112            Some(prefix) if prefix == &EOF_MAGIC_BYTES => {
113                let eof = Eof::decode(bytecode)?;
114                Ok(Self::Eof(Arc::new(eof)))
115            }
116            Some(prefix) if prefix == &EIP7702_MAGIC_BYTES => {
117                let eip7702 = Eip7702Bytecode::new_raw(bytecode)?;
118                Ok(Self::Eip7702(eip7702))
119            }
120            _ => Ok(Self::LegacyRaw(bytecode)),
121        }
122    }
123
124    /// Create new checked bytecode.
125    ///
126    /// # Safety
127    ///
128    /// Bytecode needs to end with STOP (0x00) opcode as checked bytecode assumes
129    /// that it is safe to iterate over bytecode without checking lengths.
130    pub unsafe fn new_analyzed(
131        bytecode: Bytes,
132        original_len: usize,
133        jump_table: JumpTable,
134    ) -> Self {
135        Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
136            bytecode,
137            original_len,
138            jump_table,
139        ))
140    }
141
142    /// Returns a reference to the bytecode.
143    ///
144    /// In case of EOF this will be the first code section.
145    #[inline]
146    pub fn bytecode(&self) -> &Bytes {
147        match self {
148            Self::LegacyRaw(bytes) => bytes,
149            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
150            Self::Eof(eof) => eof
151                .body
152                .code(0)
153                .expect("Valid EOF has at least one code section"),
154            Self::Eip7702(code) => code.raw(),
155        }
156    }
157
158    /// Returns false if bytecode can't be executed in Interpreter.
159    pub fn is_execution_ready(&self) -> bool {
160        !matches!(self, Self::LegacyRaw(_))
161    }
162
163    /// Returns bytes
164    #[inline]
165    pub fn bytes(&self) -> Bytes {
166        match self {
167            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode().clone(),
168            _ => self.original_bytes(),
169        }
170    }
171
172    /// Returns bytes slice
173    #[inline]
174    pub fn bytes_slice(&self) -> &[u8] {
175        match self {
176            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
177            _ => self.original_byte_slice(),
178        }
179    }
180
181    /// Returns a reference to the original bytecode.
182    #[inline]
183    pub fn original_bytes(&self) -> Bytes {
184        match self {
185            Self::LegacyRaw(bytes) => bytes.clone(),
186            Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(),
187            Self::Eof(eof) => eof.raw().clone(),
188            Self::Eip7702(eip7702) => eip7702.raw().clone(),
189        }
190    }
191
192    /// Returns the original bytecode as a byte slice.
193    #[inline]
194    pub fn original_byte_slice(&self) -> &[u8] {
195        match self {
196            Self::LegacyRaw(bytes) => bytes,
197            Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(),
198            Self::Eof(eof) => eof.raw(),
199            Self::Eip7702(eip7702) => eip7702.raw(),
200        }
201    }
202
203    /// Returns the length of the original bytes.
204    #[inline]
205    pub fn len(&self) -> usize {
206        self.original_byte_slice().len()
207    }
208
209    /// Returns whether the bytecode is empty.
210    #[inline]
211    pub fn is_empty(&self) -> bool {
212        self.len() == 0
213    }
214}
215
216/// EOF decode errors.
217#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
218#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
219pub enum BytecodeDecodeError {
220    /// EOF decode error
221    Eof(EofDecodeError),
222    /// EIP-7702 decode error
223    Eip7702(Eip7702DecodeError),
224}
225
226impl From<EofDecodeError> for BytecodeDecodeError {
227    fn from(error: EofDecodeError) -> Self {
228        Self::Eof(error)
229    }
230}
231
232impl From<Eip7702DecodeError> for BytecodeDecodeError {
233    fn from(error: Eip7702DecodeError) -> Self {
234        Self::Eip7702(error)
235    }
236}
237
238#[cfg(feature = "std")]
239impl std::error::Error for BytecodeDecodeError {}
240
241impl fmt::Display for BytecodeDecodeError {
242    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243        match self {
244            Self::Eof(e) => fmt::Display::fmt(e, f),
245            Self::Eip7702(e) => fmt::Display::fmt(e, f),
246        }
247    }
248}
249
250#[cfg(test)]
251mod tests {
252    use super::{Bytecode, Eof};
253    use std::sync::Arc;
254
255    #[test]
256    fn eof_arc_clone() {
257        let eof = Arc::new(Eof::default());
258        let bytecode = Bytecode::Eof(Arc::clone(&eof));
259
260        // Cloning the Bytecode should not clone the underlying Eof
261        let cloned_bytecode = bytecode.clone();
262        if let Bytecode::Eof(original_arc) = bytecode {
263            if let Bytecode::Eof(cloned_arc) = cloned_bytecode {
264                assert!(Arc::ptr_eq(&original_arc, &cloned_arc));
265            } else {
266                panic!("Cloned bytecode is not Eof");
267            }
268        } else {
269            panic!("Original bytecode is not Eof");
270        }
271    }
272}