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    /// Re-calculates the bytecode hash.
72    ///
73    /// Prefer [`get_or_calculate_hash`](Self::get_or_calculate_hash) if you just need to get the hash.
74    #[inline]
75    pub fn calculate_hash(&mut self) -> B256 {
76        let hash = self.base.hash_slow();
77        self.bytecode_hash = Some(hash);
78        hash
79    }
80
81    /// Returns the bytecode hash.
82    #[inline]
83    pub fn hash(&mut self) -> Option<B256> {
84        self.bytecode_hash
85    }
86
87    /// Returns the bytecode hash or calculates it if it is not set.
88    #[inline]
89    pub fn get_or_calculate_hash(&mut self) -> B256 {
90        *self.bytecode_hash.get_or_insert_with(
91            #[cold]
92            || self.base.hash_slow(),
93        )
94    }
95}
96
97impl LoopControl for ExtBytecode {
98    #[inline]
99    fn is_not_end(&self) -> bool {
100        self.continue_execution
101    }
102
103    #[inline]
104    fn reset_action(&mut self) {
105        self.continue_execution = true;
106    }
107
108    #[inline]
109    fn set_action(&mut self, action: InterpreterAction) {
110        debug_assert_eq!(
111            !self.continue_execution,
112            self.action.is_some(),
113            "has_set_action out of sync"
114        );
115        debug_assert!(
116            self.continue_execution,
117            "action already set;\nold: {:#?}\nnew: {:#?}",
118            self.action, action,
119        );
120        self.continue_execution = false;
121        self.action = Some(action);
122    }
123
124    #[inline]
125    fn action(&mut self) -> &mut Option<InterpreterAction> {
126        &mut self.action
127    }
128}
129
130impl Jumps for ExtBytecode {
131    #[inline]
132    fn relative_jump(&mut self, offset: isize) {
133        self.instruction_pointer = unsafe { self.instruction_pointer.offset(offset) };
134    }
135
136    #[inline]
137    fn absolute_jump(&mut self, offset: usize) {
138        self.instruction_pointer = unsafe { self.base.bytes_ref().as_ptr().add(offset) };
139    }
140
141    #[inline]
142    fn is_valid_legacy_jump(&mut self, offset: usize) -> bool {
143        self.base
144            .legacy_jump_table()
145            .expect("Panic if not legacy")
146            .is_valid(offset)
147    }
148
149    #[inline]
150    fn opcode(&self) -> u8 {
151        // SAFETY: `instruction_pointer` always point to bytecode.
152        unsafe { *self.instruction_pointer }
153    }
154
155    #[inline]
156    fn pc(&self) -> usize {
157        // SAFETY: `instruction_pointer` should be at an offset from the start of the bytes.
158        // In practice this is always true unless a caller modifies the `instruction_pointer` field manually.
159        unsafe {
160            self.instruction_pointer
161                .offset_from_unsigned(self.base.bytes_ref().as_ptr())
162        }
163    }
164}
165
166impl Immediates for ExtBytecode {
167    #[inline]
168    fn read_u16(&self) -> u16 {
169        unsafe { read_u16(self.instruction_pointer) }
170    }
171
172    #[inline]
173    fn read_u8(&self) -> u8 {
174        unsafe { *self.instruction_pointer }
175    }
176
177    #[inline]
178    fn read_slice(&self, len: usize) -> &[u8] {
179        unsafe { core::slice::from_raw_parts(self.instruction_pointer, len) }
180    }
181
182    #[inline]
183    fn read_offset_u16(&self, offset: isize) -> u16 {
184        unsafe {
185            read_u16(
186                self.instruction_pointer
187                    // Offset for max_index that is one byte
188                    .offset(offset),
189            )
190        }
191    }
192}
193
194impl LegacyBytecode for ExtBytecode {
195    fn bytecode_len(&self) -> usize {
196        self.base.len()
197    }
198
199    fn bytecode_slice(&self) -> &[u8] {
200        self.base.original_byte_slice()
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207    use primitives::Bytes;
208
209    #[test]
210    fn test_with_hash_constructor() {
211        let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..]));
212        let hash = bytecode.hash_slow();
213        let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash);
214        assert_eq!(ext_bytecode.bytecode_hash, Some(hash));
215    }
216}