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//! - EIP-7702 bytecode, introduces in Prague and contains address to delegated account.
6
7use crate::{
8    eip7702::{Eip7702Bytecode, EIP7702_MAGIC_BYTES},
9    BytecodeDecodeError, JumpTable, LegacyAnalyzedBytecode, LegacyRawBytecode,
10};
11use primitives::{
12    alloy_primitives::Sealable, keccak256, Address, Bytes, OnceLock, B256, KECCAK_EMPTY,
13};
14use std::sync::Arc;
15
16/// Main bytecode structure with all variants.
17#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub enum Bytecode {
20    /// EIP-7702 delegated bytecode
21    Eip7702(Arc<Eip7702Bytecode>),
22    /// The bytecode has been analyzed for valid jump destinations.
23    LegacyAnalyzed(Arc<LegacyAnalyzedBytecode>),
24}
25
26impl Default for Bytecode {
27    #[inline]
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33impl Sealable for Bytecode {
34    #[inline]
35    fn hash_slow(&self) -> B256 {
36        self.hash_slow()
37    }
38}
39
40impl Bytecode {
41    /// Creates a new legacy analyzed [`Bytecode`] with exactly one STOP opcode.
42    #[inline]
43    pub fn new() -> Self {
44        static DEFAULT_BYTECODE: OnceLock<Bytecode> = OnceLock::new();
45        DEFAULT_BYTECODE
46            .get_or_init(|| Self::LegacyAnalyzed(Arc::new(LegacyAnalyzedBytecode::default())))
47            .clone()
48    }
49
50    /// Returns jump table if bytecode is analyzed.
51    #[inline]
52    pub fn legacy_jump_table(&self) -> Option<&JumpTable> {
53        match &self {
54            Self::LegacyAnalyzed(analyzed) => Some(analyzed.jump_table()),
55            _ => None,
56        }
57    }
58
59    /// Calculates hash of the bytecode.
60    #[inline]
61    pub fn hash_slow(&self) -> B256 {
62        if self.is_empty() {
63            KECCAK_EMPTY
64        } else {
65            keccak256(self.original_byte_slice())
66        }
67    }
68
69    /// Returns `true` if bytecode is EIP-7702.
70    #[inline]
71    pub const fn is_eip7702(&self) -> bool {
72        matches!(self, Self::Eip7702(_))
73    }
74
75    /// Creates a new legacy [`Bytecode`].
76    #[inline]
77    pub fn new_legacy(raw: Bytes) -> Self {
78        Self::LegacyAnalyzed(Arc::new(LegacyRawBytecode(raw).into_analyzed()))
79    }
80
81    /// Creates a new raw [`Bytecode`].
82    ///
83    /// # Panics
84    ///
85    /// Panics if bytecode is in incorrect format. If you want to handle errors use [`Self::new_raw_checked`].
86    #[inline]
87    pub fn new_raw(bytecode: Bytes) -> Self {
88        Self::new_raw_checked(bytecode).expect("Expect correct bytecode")
89    }
90
91    /// Creates a new EIP-7702 [`Bytecode`] from [`Address`].
92    #[inline]
93    pub fn new_eip7702(address: Address) -> Self {
94        Self::Eip7702(Arc::new(Eip7702Bytecode::new(address)))
95    }
96
97    /// Creates a new raw [`Bytecode`].
98    ///
99    /// Returns an error on incorrect bytecode format.
100    #[inline]
101    pub fn new_raw_checked(bytes: Bytes) -> Result<Self, BytecodeDecodeError> {
102        let prefix = bytes.get(..2);
103        match prefix {
104            Some(prefix) if prefix == &EIP7702_MAGIC_BYTES => {
105                let eip7702 = Eip7702Bytecode::new_raw(bytes)?;
106                Ok(Self::Eip7702(Arc::new(eip7702)))
107            }
108            _ => Ok(Self::new_legacy(bytes)),
109        }
110    }
111
112    /// Create new checked bytecode.
113    ///
114    /// # Panics
115    ///
116    /// For possible panics see [`LegacyAnalyzedBytecode::new`].
117    #[inline]
118    pub fn new_analyzed(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self {
119        Self::LegacyAnalyzed(Arc::new(LegacyAnalyzedBytecode::new(
120            bytecode,
121            original_len,
122            jump_table,
123        )))
124    }
125
126    /// Returns a reference to the bytecode.
127    #[inline]
128    pub fn bytecode(&self) -> &Bytes {
129        match self {
130            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
131            Self::Eip7702(code) => code.raw(),
132        }
133    }
134
135    /// Pointer to the executable bytecode.
136    #[inline]
137    pub fn bytecode_ptr(&self) -> *const u8 {
138        self.bytecode().as_ptr()
139    }
140
141    /// Returns bytes.
142    #[inline]
143    pub fn bytes(&self) -> Bytes {
144        self.bytes_ref().clone()
145    }
146
147    /// Returns raw bytes reference.
148    #[inline]
149    pub fn bytes_ref(&self) -> &Bytes {
150        match self {
151            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
152            Self::Eip7702(code) => code.raw(),
153        }
154    }
155
156    /// Returns raw bytes slice.
157    #[inline]
158    pub fn bytes_slice(&self) -> &[u8] {
159        self.bytes_ref()
160    }
161
162    /// Returns the original bytecode.
163    #[inline]
164    pub fn original_bytes(&self) -> Bytes {
165        match self {
166            Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(),
167            Self::Eip7702(eip7702) => eip7702.raw().clone(),
168        }
169    }
170
171    /// Returns the original bytecode as a byte slice.
172    #[inline]
173    pub fn original_byte_slice(&self) -> &[u8] {
174        match self {
175            Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(),
176            Self::Eip7702(eip7702) => eip7702.raw(),
177        }
178    }
179
180    /// Returns the length of the original bytes.
181    #[inline]
182    pub fn len(&self) -> usize {
183        self.original_byte_slice().len()
184    }
185
186    /// Returns whether the bytecode is empty.
187    #[inline]
188    pub fn is_empty(&self) -> bool {
189        self.len() == 0
190    }
191
192    /// Returns an iterator over the opcodes in this bytecode, skipping immediates.
193    /// This is useful if you want to ignore immediates and just see what opcodes are inside.
194    #[inline]
195    pub fn iter_opcodes(&self) -> crate::BytecodeIterator<'_> {
196        crate::BytecodeIterator::new(self)
197    }
198}