revm_interpreter/interpreter/
ext_bytecode.rs

1use super::{Immediates, Jumps, LegacyBytecode};
2use crate::{interpreter_types::LoopControl, InterpreterAction};
3use bytecode::{utils::read_u16, Bytecode};
4use core::ops::Deref;
5use primitives::B256;
6
7#[cfg(feature = "serde")]
8mod serde;
9
10/// Extended bytecode structure that wraps base bytecode with additional execution metadata.
11#[derive(Debug)]
12pub struct ExtBytecode {
13    /// The current instruction pointer.
14    instruction_pointer: *const u8,
15    /// Whether the execution should continue.
16    continue_execution: bool,
17    /// Bytecode Keccak-256 hash.
18    /// This is `None` if it hasn't been calculated yet.
19    /// Since it's not necessary for execution, it's not calculated by default.
20    bytecode_hash: Option<B256>,
21    /// Actions that the EVM should do. It contains return value of the Interpreter or inputs for `CALL` or `CREATE` instructions.
22    /// For `RETURN` or `REVERT` instructions it contains the result of the instruction.
23    pub action: Option<InterpreterAction>,
24    /// The base bytecode.
25    base: Bytecode,
26}
27
28impl Deref for ExtBytecode {
29    type Target = Bytecode;
30
31    fn deref(&self) -> &Self::Target {
32        &self.base
33    }
34}
35
36impl Default for ExtBytecode {
37    #[inline]
38    fn default() -> Self {
39        Self::new(Bytecode::default())
40    }
41}
42
43impl ExtBytecode {
44    /// Create new extended bytecode and set the instruction pointer to the start of the bytecode.
45    ///
46    /// The bytecode hash will not be calculated.
47    #[inline]
48    pub fn new(base: Bytecode) -> Self {
49        Self::new_with_optional_hash(base, None)
50    }
51
52    /// Creates new `ExtBytecode` with the given hash.
53    #[inline]
54    pub fn new_with_hash(base: Bytecode, hash: B256) -> Self {
55        Self::new_with_optional_hash(base, Some(hash))
56    }
57
58    /// Creates new `ExtBytecode` with the given hash.
59    #[inline]
60    pub fn new_with_optional_hash(base: Bytecode, hash: Option<B256>) -> Self {
61        let instruction_pointer = base.bytecode_ptr();
62        Self {
63            base,
64            instruction_pointer,
65            bytecode_hash: hash,
66            action: None,
67            continue_execution: true,
68        }
69    }
70
71    /// Regenerates the bytecode hash.
72    #[inline]
73    #[deprecated(note = "use `get_or_calculate_hash` or `calculate_hash` instead")]
74    #[doc(hidden)]
75    pub fn regenerate_hash(&mut self) -> B256 {
76        self.calculate_hash()
77    }
78
79    /// Re-calculates the bytecode hash.
80    ///
81    /// Prefer [`get_or_calculate_hash`](Self::get_or_calculate_hash) if you just need to get the hash.
82    #[inline]
83    pub fn calculate_hash(&mut self) -> B256 {
84        let hash = self.base.hash_slow();
85        self.bytecode_hash = Some(hash);
86        hash
87    }
88
89    /// Returns the bytecode hash.
90    #[inline]
91    pub fn hash(&mut self) -> Option<B256> {
92        self.bytecode_hash
93    }
94
95    /// Returns the bytecode hash or calculates it if it is not set.
96    #[inline]
97    pub fn get_or_calculate_hash(&mut self) -> B256 {
98        *self.bytecode_hash.get_or_insert_with(
99            #[cold]
100            || self.base.hash_slow(),
101        )
102    }
103}
104
105impl LoopControl for ExtBytecode {
106    #[inline]
107    fn is_not_end(&self) -> bool {
108        self.continue_execution
109    }
110
111    #[inline]
112    fn reset_action(&mut self) {
113        self.continue_execution = true;
114    }
115
116    #[inline]
117    fn set_action(&mut self, action: InterpreterAction) {
118        debug_assert_eq!(
119            !self.continue_execution,
120            self.action.is_some(),
121            "has_set_action out of sync"
122        );
123        debug_assert!(
124            self.continue_execution,
125            "action already set;\nold: {:#?}\nnew: {:#?}",
126            self.action, action,
127        );
128        self.continue_execution = false;
129        self.action = Some(action);
130    }
131
132    #[inline]
133    fn action(&mut self) -> &mut Option<InterpreterAction> {
134        &mut self.action
135    }
136}
137
138impl Jumps for ExtBytecode {
139    #[inline]
140    fn relative_jump(&mut self, offset: isize) {
141        self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) };
142    }
143
144    #[inline]
145    fn absolute_jump(&mut self, offset: usize) {
146        self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) };
147    }
148
149    #[inline]
150    fn is_valid_legacy_jump(&mut self, offset: usize) -> bool {
151        self.base
152            .legacy_jump_table()
153            .expect("Panic if not legacy")
154            .is_valid(offset)
155    }
156
157    #[inline]
158    fn opcode(&self) -> u8 {
159        // SAFETY: `instruction_pointer` always point to bytecode.
160        unsafe { *self.instruction_pointer }
161    }
162
163    #[inline]
164    fn pc(&self) -> usize {
165        // SAFETY: `instruction_pointer` should be at an offset from the start of the bytes.
166        // In practice this is always true unless a caller modifies the `instruction_pointer` field manually.
167        unsafe {
168            self.instruction_pointer
169                .offset_from(self.base.bytes_ref().as_ptr()) as usize
170        }
171    }
172}
173
174impl Immediates for ExtBytecode {
175    #[inline]
176    fn read_u16(&self) -> u16 {
177        unsafe { read_u16(self.instruction_pointer) }
178    }
179
180    #[inline]
181    fn read_u8(&self) -> u8 {
182        unsafe { *self.instruction_pointer }
183    }
184
185    #[inline]
186    fn read_slice(&self, len: usize) -> &[u8] {
187        unsafe { core::slice::from_raw_parts(self.instruction_pointer, len) }
188    }
189
190    #[inline]
191    fn read_offset_u16(&self, offset: isize) -> u16 {
192        unsafe {
193            read_u16(
194                self.instruction_pointer
195                    // Offset for max_index that is one byte
196                    .offset(offset),
197            )
198        }
199    }
200}
201
202impl LegacyBytecode for ExtBytecode {
203    fn bytecode_len(&self) -> usize {
204        self.base.len()
205    }
206
207    fn bytecode_slice(&self) -> &[u8] {
208        self.base.original_byte_slice()
209    }
210}
211
212#[cfg(test)]
213mod tests {
214    use super::*;
215    use primitives::Bytes;
216
217    #[test]
218    fn test_with_hash_constructor() {
219        let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..]));
220        let hash = bytecode.hash_slow();
221        let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash);
222        assert_eq!(ext_bytecode.bytecode_hash, Some(hash));
223    }
224}