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    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    pub const fn is_eip7702(&self) -> bool {
58        matches!(self, Self::Eip7702(_))
59    }
60
61    /// Creates a new legacy [`Bytecode`].
62    #[inline]
63    pub fn new_legacy(raw: Bytes) -> Self {
64        Self::LegacyAnalyzed(LegacyRawBytecode(raw).into_analyzed())
65    }
66
67    /// Creates a new raw [`Bytecode`].
68    ///
69    /// # Panics
70    ///
71    /// Panics if bytecode is in incorrect format. If you want to handle errors use [`Self::new_raw_checked`].
72    #[inline]
73    pub fn new_raw(bytecode: Bytes) -> Self {
74        Self::new_raw_checked(bytecode).expect("Expect correct bytecode")
75    }
76
77    /// Creates a new EIP-7702 [`Bytecode`] from [`Address`].
78    #[inline]
79    pub fn new_eip7702(address: Address) -> Self {
80        Self::Eip7702(Eip7702Bytecode::new(address))
81    }
82
83    /// Creates a new raw [`Bytecode`].
84    ///
85    /// Returns an error on incorrect bytecode format.
86    #[inline]
87    pub fn new_raw_checked(bytes: Bytes) -> Result<Self, BytecodeDecodeError> {
88        let prefix = bytes.get(..2);
89        match prefix {
90            Some(prefix) if prefix == &EIP7702_MAGIC_BYTES => {
91                let eip7702 = Eip7702Bytecode::new_raw(bytes)?;
92                Ok(Self::Eip7702(eip7702))
93            }
94            _ => Ok(Self::new_legacy(bytes)),
95        }
96    }
97
98    /// Create new checked bytecode.
99    ///
100    /// # Panics
101    ///
102    /// For possible panics see [`LegacyAnalyzedBytecode::new`].
103    pub fn new_analyzed(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self {
104        Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new(
105            bytecode,
106            original_len,
107            jump_table,
108        ))
109    }
110
111    /// Returns a reference to the bytecode.
112    #[inline]
113    pub fn bytecode(&self) -> &Bytes {
114        match self {
115            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
116            Self::Eip7702(code) => code.raw(),
117        }
118    }
119
120    /// Pointer to the executable bytecode.
121    pub fn bytecode_ptr(&self) -> *const u8 {
122        self.bytecode().as_ptr()
123    }
124
125    /// Returns bytes.
126    #[inline]
127    pub fn bytes(&self) -> Bytes {
128        self.bytes_ref().clone()
129    }
130
131    /// Returns raw bytes reference.
132    #[inline]
133    pub fn bytes_ref(&self) -> &Bytes {
134        match self {
135            Self::LegacyAnalyzed(analyzed) => analyzed.bytecode(),
136            Self::Eip7702(code) => code.raw(),
137        }
138    }
139
140    /// Returns raw bytes slice.
141    #[inline]
142    pub fn bytes_slice(&self) -> &[u8] {
143        self.bytes_ref()
144    }
145
146    /// Returns the original bytecode.
147    #[inline]
148    pub fn original_bytes(&self) -> Bytes {
149        match self {
150            Self::LegacyAnalyzed(analyzed) => analyzed.original_bytes(),
151            Self::Eip7702(eip7702) => eip7702.raw().clone(),
152        }
153    }
154
155    /// Returns the original bytecode as a byte slice.
156    #[inline]
157    pub fn original_byte_slice(&self) -> &[u8] {
158        match self {
159            Self::LegacyAnalyzed(analyzed) => analyzed.original_byte_slice(),
160            Self::Eip7702(eip7702) => eip7702.raw(),
161        }
162    }
163
164    /// Returns the length of the original bytes.
165    #[inline]
166    pub fn len(&self) -> usize {
167        self.original_byte_slice().len()
168    }
169
170    /// Returns whether the bytecode is empty.
171    #[inline]
172    pub fn is_empty(&self) -> bool {
173        self.len() == 0
174    }
175
176    /// Returns an iterator over the opcodes in this bytecode, skipping immediates.
177    /// This is useful if you want to ignore immediates and just see what opcodes are inside.
178    #[inline]
179    pub fn iter_opcodes(&self) -> crate::BytecodeIterator<'_> {
180        crate::BytecodeIterator::new(self)
181    }
182}