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/// Main bytecode structure with all variants.
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. If you want to handle errors use [`Self::new_raw_checked`].
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    /// # Panics
118    ///
119    /// For possible panics see [`LegacyAnalyzedBytecode::new`].
120    pub fn new_analyzed(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self {
121        Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
122            bytecode,
123            original_len,
124            jump_table,
125        ))
126    }
127
128    /// Returns a reference to the bytecode.
129    ///
130    /// In case of EOF this will be the all code sections.
131    #[inline]
132    pub fn bytecode(&self) -> &Bytes {
133        match self {
134            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
135            Self::Eof(eof) => &eof.body.code,
136            Self::Eip7702(code) => code.raw(),
137        }
138    }
139
140    /// Pointer to the executable bytecode.
141    ///
142    /// Note: EOF will return the pointer to the start of the code section.
143    /// while legacy bytecode will point to the start of the bytes.
144    pub fn bytecode_ptr(&self) -> *const u8 {
145        self.bytecode().as_ptr()
146    }
147
148    /// Returns bytes.
149    #[inline]
150    pub fn bytes(&self) -> Bytes {
151        self.bytes_ref().clone()
152    }
153
154    /// Returns raw bytes reference.
155    #[inline]
156    pub fn bytes_ref(&self) -> &Bytes {
157        match self {
158            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
159            Self::Eof(eof) => &eof.raw,
160            Self::Eip7702(code) => code.raw(),
161        }
162    }
163
164    /// Returns raw bytes slice.
165    #[inline]
166    pub fn bytes_slice(&self) -> &[u8] {
167        self.bytes_ref()
168    }
169
170    /// Returns the original bytecode.
171    #[inline]
172    pub fn original_bytes(&self) -> Bytes {
173        match self {
174            Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(),
175            Self::Eof(eof) => eof.raw().clone(),
176            Self::Eip7702(eip7702) => eip7702.raw().clone(),
177        }
178    }
179
180    /// Returns the original bytecode as a byte slice.
181    #[inline]
182    pub fn original_byte_slice(&self) -> &[u8] {
183        match self {
184            Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(),
185            Self::Eof(eof) => eof.raw(),
186            Self::Eip7702(eip7702) => eip7702.raw(),
187        }
188    }
189
190    /// Returns the length of the original bytes.
191    #[inline]
192    pub fn len(&self) -> usize {
193        self.original_byte_slice().len()
194    }
195
196    /// Returns whether the bytecode is empty.
197    #[inline]
198    pub fn is_empty(&self) -> bool {
199        self.len() == 0
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    use super::{Bytecode, Eof};
206    use std::sync::Arc;
207
208    #[test]
209    fn eof_arc_clone() {
210        let eof = Arc::new(Eof::default());
211        let bytecode = Bytecode::Eof(Arc::clone(&eof));
212
213        // Cloning the Bytecode should not clone the underlying Eof
214        let cloned_bytecode = bytecode.clone();
215        if let Bytecode::Eof(original_arc) = bytecode {
216            if let Bytecode::Eof(cloned_arc) = cloned_bytecode {
217                assert!(Arc::ptr_eq(&original_arc, &cloned_arc));
218            } else {
219                panic!("Cloned bytecode is not Eof");
220            }
221        } else {
222            panic!("Original bytecode is not Eof");
223        }
224    }
225}