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