revm_bytecode/
bytecode.rs

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