revm_bytecode/
bytecode.rs

1//! Module that contains the bytecode enum with all variants supported by Ethereum mainnet.
2//!
3//! Those are:
4//! - Legacy bytecode with jump table analysis. Found in [`LegacyAnalyzedBytecode`]
5//! - EOF ( EMV Object Format) bytecode introduced in Osaka that.
6//! - EIP-7702 bytecode, introduces in Prague and contains address to delegated account.
7
8use crate::{
9    eip7702::{Eip7702Bytecode, EIP7702_MAGIC_BYTES},
10    BytecodeDecodeError, Eof, JumpTable, LegacyAnalyzedBytecode, LegacyRawBytecode,
11    EOF_MAGIC_BYTES,
12};
13use core::fmt::Debug;
14use primitives::{keccak256, Address, Bytes, B256, KECCAK_EMPTY};
15use std::sync::Arc;
16
17/// Main bytecode structure with all variants.
18#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub enum Bytecode {
21    /// The bytecode has been analyzed for valid jump destinations.
22    LegacyAnalyzed(LegacyAnalyzedBytecode),
23    /// Ethereum Object Format
24    Eof(Arc<Eof>),
25    /// EIP-7702 delegated bytecode
26    Eip7702(Eip7702Bytecode),
27}
28
29impl Default for Bytecode {
30    #[inline]
31    fn default() -> Self {
32        Self::new()
33    }
34}
35
36impl Bytecode {
37    /// Creates a new legacy analyzed [`Bytecode`] with exactly one STOP opcode.
38    #[inline]
39    pub fn new() -> Self {
40        Self::LegacyAnalyzed(LegacyAnalyzedBytecode::default())
41    }
42
43    /// Returns jump table if bytecode is analyzed.
44    #[inline]
45    pub fn legacy_jump_table(&self) -> Option<&JumpTable> {
46        match &self {
47            Self::LegacyAnalyzed(analyzed) => Some(analyzed.jump_table()),
48            _ => None,
49        }
50    }
51
52    /// Calculates hash of the bytecode.
53    pub fn hash_slow(&self) -> B256 {
54        if self.is_empty() {
55            KECCAK_EMPTY
56        } else {
57            keccak256(self.original_byte_slice())
58        }
59    }
60
61    /// Returns reference to the EOF if bytecode is EOF.
62    #[inline]
63    pub const fn eof(&self) -> Option<&Arc<Eof>> {
64        match self {
65            Self::Eof(eof) => Some(eof),
66            _ => None,
67        }
68    }
69
70    /// Returns `true` if bytecode is EOF.
71    #[inline]
72    pub const fn is_eof(&self) -> bool {
73        matches!(self, Self::Eof(_))
74    }
75
76    /// Returns `true` if bytecode is EIP-7702.
77    pub const fn is_eip7702(&self) -> bool {
78        matches!(self, Self::Eip7702(_))
79    }
80
81    /// Creates a new legacy [`Bytecode`].
82    #[inline]
83    pub fn new_legacy(raw: Bytes) -> Self {
84        Self::LegacyAnalyzed(LegacyRawBytecode(raw).into_analyzed())
85    }
86
87    /// Creates a new raw [`Bytecode`].
88    ///
89    /// # Panics
90    ///
91    /// Panics if bytecode is in incorrect format. If you want to handle errors use [`Self::new_raw_checked`].
92    #[inline]
93    pub fn new_raw(bytecode: Bytes) -> Self {
94        Self::new_raw_checked(bytecode).expect("Expect correct EOF bytecode")
95    }
96
97    /// Creates a new EIP-7702 [`Bytecode`] from [`Address`].
98    #[inline]
99    pub fn new_eip7702(address: Address) -> Self {
100        Self::Eip7702(Eip7702Bytecode::new(address))
101    }
102
103    /// Creates a new raw [`Bytecode`].
104    ///
105    /// Returns an error on incorrect bytecode format.
106    #[inline]
107    pub fn new_raw_checked(bytes: Bytes) -> Result<Self, BytecodeDecodeError> {
108        let prefix = bytes.get(..2);
109        match prefix {
110            Some(prefix) if prefix == &EOF_MAGIC_BYTES => {
111                let eof = Eof::decode(bytes)?;
112                Ok(Self::Eof(Arc::new(eof)))
113            }
114            Some(prefix) if prefix == &EIP7702_MAGIC_BYTES => {
115                let eip7702 = Eip7702Bytecode::new_raw(bytes)?;
116                Ok(Self::Eip7702(eip7702))
117            }
118            _ => Ok(Self::new_legacy(bytes)),
119        }
120    }
121
122    /// Create new checked bytecode.
123    ///
124    /// # Panics
125    ///
126    /// For possible panics see [`LegacyAnalyzedBytecode::new`].
127    pub fn new_analyzed(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self {
128        Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
129            bytecode,
130            original_len,
131            jump_table,
132        ))
133    }
134
135    /// Returns a reference to the bytecode.
136    ///
137    /// In case of EOF this will be the all code sections.
138    #[inline]
139    pub fn bytecode(&self) -> &Bytes {
140        match self {
141            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
142            Self::Eof(eof) => &eof.body.code,
143            Self::Eip7702(code) => code.raw(),
144        }
145    }
146
147    /// Pointer to the executable bytecode.
148    ///
149    /// Note: EOF will return the pointer to the start of the code section.
150    /// while legacy bytecode will point to the start of the bytes.
151    pub fn bytecode_ptr(&self) -> *const u8 {
152        self.bytecode().as_ptr()
153    }
154
155    /// Returns bytes.
156    #[inline]
157    pub fn bytes(&self) -> Bytes {
158        self.bytes_ref().clone()
159    }
160
161    /// Returns raw bytes reference.
162    #[inline]
163    pub fn bytes_ref(&self) -> &Bytes {
164        match self {
165            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
166            Self::Eof(eof) => &eof.raw,
167            Self::Eip7702(code) => code.raw(),
168        }
169    }
170
171    /// Returns raw bytes slice.
172    #[inline]
173    pub fn bytes_slice(&self) -> &[u8] {
174        self.bytes_ref()
175    }
176
177    /// Returns the original bytecode.
178    #[inline]
179    pub fn original_bytes(&self) -> Bytes {
180        match self {
181            Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(),
182            Self::Eof(eof) => eof.raw().clone(),
183            Self::Eip7702(eip7702) => eip7702.raw().clone(),
184        }
185    }
186
187    /// Returns the original bytecode as a byte slice.
188    #[inline]
189    pub fn original_byte_slice(&self) -> &[u8] {
190        match self {
191            Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(),
192            Self::Eof(eof) => eof.raw(),
193            Self::Eip7702(eip7702) => eip7702.raw(),
194        }
195    }
196
197    /// Returns the length of the original bytes.
198    #[inline]
199    pub fn len(&self) -> usize {
200        self.original_byte_slice().len()
201    }
202
203    /// Returns whether the bytecode is empty.
204    #[inline]
205    pub fn is_empty(&self) -> bool {
206        self.len() == 0
207    }
208
209    /// Returns an iterator over the opcodes in this bytecode, skipping immediates.
210    /// This is useful if you want to ignore immediates and just see what opcodes are inside.
211    #[inline]
212    pub fn iter_opcodes(&self) -> crate::iterator::BytecodeIterator<'_> {
213        crate::iterator::BytecodeIterator::new(self)
214    }
215}
216
217#[cfg(test)]
218mod tests {
219    use super::{Bytecode, Eof};
220    use std::sync::Arc;
221
222    #[test]
223    fn eof_arc_clone() {
224        let eof = Arc::new(Eof::default());
225        let bytecode = Bytecode::Eof(Arc::clone(&eof));
226
227        // Cloning the Bytecode should not clone the underlying Eof
228        let cloned_bytecode = bytecode.clone();
229        if let Bytecode::Eof(original_arc) = bytecode {
230            if let Bytecode::Eof(cloned_arc) = cloned_bytecode {
231                assert!(Arc::ptr_eq(&original_arc, &cloned_arc));
232            } else {
233                panic!("Cloned bytecode is not Eof");
234            }
235        } else {
236            panic!("Original bytecode is not Eof");
237        }
238    }
239}