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