@@ -2,30 +2,85 @@ use alloy::primitives::U256;
2
2
3
3
use crate :: core:: opcodes:: opcode_name;
4
4
5
- /// A WrappedInput can contain either a raw U256 value or a WrappedOpcode
5
+ /// A [`WrappedInput`] can contain either a raw [`U256`] value or a [`WrappedOpcode`].
6
+ ///
7
+ /// This enum is used to represent inputs to EVM opcodes, allowing inputs to be
8
+ /// either constant values or the results of previous operations in the execution flow.
6
9
#[ derive( Clone , Debug , PartialEq , Eq , Hash ) ]
7
10
pub enum WrappedInput {
8
- /// A raw value input
11
+ /// A raw value input (typically from a PUSH instruction)
9
12
Raw ( U256 ) ,
10
- /// An opcode input
13
+ /// An opcode result as input (indicating data dependency)
11
14
Opcode ( WrappedOpcode ) ,
12
15
}
13
16
14
- /// A WrappedOpcode is an Opcode with its inputs wrapped in a WrappedInput
17
+ /// A [`WrappedOpcode`] is an EVM opcode with its inputs wrapped in a [`WrappedInput`].
18
+ ///
19
+ /// This structure is used to represent opcodes and their arguments in a way
20
+ /// that can capture the relationships between operations, allowing for analysis
21
+ /// of execution flow and dependencies.
15
22
#[ derive( Clone , Debug , PartialEq , Eq , Hash , Default ) ]
16
23
pub struct WrappedOpcode {
24
+ /// The opcode value as a byte.
25
+ ///
26
+ /// This corresponds to the actual EVM opcode (e.g., 0x01 for ADD).
17
27
pub opcode : u8 ,
28
+
29
+ /// The inputs for this opcode, wrapped to preserve their source context.
30
+ ///
31
+ /// For example, an ADD opcode would typically have two inputs, which could be
32
+ /// either raw values or the results of other operations.
18
33
pub inputs : Vec < WrappedInput > ,
19
34
}
20
35
21
36
impl WrappedOpcode {
22
- /// Returns the maximum recursion depth of its inputs
37
+ /// Returns the maximum recursion depth of its inputs.
38
+ ///
39
+ /// The depth is calculated as the maximum depth of any input plus 1.
40
+ /// A depth of 1 means the opcode has only raw inputs (or no inputs).
41
+ /// Greater depths indicate a chain of operations.
42
+ ///
43
+ /// ```
44
+ /// use heimdall_vm::core::opcodes::wrapped::{WrappedOpcode, WrappedInput};
45
+ /// use alloy::primitives::U256;
46
+ /// use heimdall_vm::ext::lexers::solidity::WrappedOpcode;
47
+ ///
48
+ /// // Create a PUSH1 0x01 operation
49
+ /// let push1 = WrappedOpcode::new(0x60, vec![WrappedInput::Raw(U256::from(1))]);
50
+ /// assert_eq!(push1.depth(), 1); // Depth is 1 because it has only raw inputs
51
+ ///
52
+ /// // Create an ADD operation that takes the result of two PUSH operations
53
+ /// let add = WrappedOpcode::new(0x01, vec![
54
+ /// WrappedInput::Opcode(push1.clone()),
55
+ /// WrappedInput::Opcode(push1.clone())
56
+ /// ]);
57
+ /// assert_eq!(add.depth(), 2); // Depth is 2 because it contains operations with depth 1
58
+ /// ```
23
59
pub fn depth ( & self ) -> u32 {
24
60
self . inputs . iter ( ) . map ( |x| x. depth ( ) ) . max ( ) . unwrap_or ( 0 ) + 1
25
61
}
26
62
}
27
63
28
64
impl std:: fmt:: Display for WrappedOpcode {
65
+ /// Formats the [`WrappedOpcode`] as a string.
66
+ ///
67
+ /// The format is: `OPCODENAME(input1, input2, ...)` where each input is
68
+ /// formatted according to its own [`Display`] implementation.
69
+ ///
70
+ /// ```
71
+ /// use heimdall_vm::core::opcodes::wrapped::{WrappedOpcode, WrappedInput};
72
+ /// use heimdall_vm::ext::lexers::solidity::WrappedOpcode;
73
+ /// use alloy::primitives::U256;
74
+ ///
75
+ /// let push1 = WrappedOpcode::new(0x60, vec![WrappedInput::Raw(U256::from(1))]);
76
+ /// assert_eq!(push1.to_string(), "PUSH1(1)");
77
+ ///
78
+ /// let add = WrappedOpcode::new(0x01, vec![
79
+ /// WrappedInput::Opcode(push1.clone()),
80
+ /// WrappedInput::Opcode(push1.clone())
81
+ /// ]);
82
+ /// assert_eq!(add.to_string(), "ADD(PUSH1(1), PUSH1(1))");
83
+ /// ```
29
84
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
30
85
write ! (
31
86
f,
@@ -37,9 +92,28 @@ impl std::fmt::Display for WrappedOpcode {
37
92
}
38
93
39
94
impl WrappedInput {
40
- /// Returns the depth of the input \
95
+ /// Returns the depth of the input.
96
+ ///
97
+ /// - 0 for a raw [`U256`] value
98
+ /// - The depth of the contained [`WrappedOpcode`] for an opcode input
99
+ ///
100
+ /// This method is used to calculate the recursive depth of operations
101
+ /// for analysis and optimization purposes.
102
+ ///
103
+ /// ```
104
+ /// use heimdall_vm::core::opcodes::wrapped::WrappedInput;
105
+ /// use heimdall_vm::ext::lexers::solidity::WrappedOpcode;
106
+ /// use alloy::primitives::U256;
41
107
///
42
- /// i.e. 0 for a raw U256 and the maximum recursion depth for a WrappedOpcode
108
+ /// // Raw inputs have depth 0
109
+ /// let raw = WrappedInput::Raw(U256::from(42));
110
+ /// assert_eq!(raw.depth(), 0);
111
+ ///
112
+ /// // Opcode inputs have the depth of the operation they contain
113
+ /// let push1 = WrappedOpcode::new(0x60, vec![WrappedInput::Raw(U256::from(1))]);
114
+ /// let op_input = WrappedInput::Opcode(push1);
115
+ /// assert_eq!(op_input.depth(), 1);
116
+ /// ```
43
117
pub fn depth ( & self ) -> u32 {
44
118
match self {
45
119
WrappedInput :: Raw ( _) => 0 ,
@@ -49,6 +123,23 @@ impl WrappedInput {
49
123
}
50
124
51
125
impl std:: fmt:: Display for WrappedInput {
126
+ /// Formats the [`WrappedInput`] as a string.
127
+ ///
128
+ /// - For [`Raw`] inputs, displays the contained [`U256`] value.
129
+ /// - For [`Opcode`] inputs, recursively formats the contained [`WrappedOpcode`].
130
+ ///
131
+ /// ```
132
+ /// use heimdall_vm::core::opcodes::wrapped::WrappedInput;
133
+ /// use heimdall_vm::ext::lexers::solidity::WrappedOpcode;
134
+ /// use alloy::primitives::U256;
135
+ ///
136
+ /// let raw = WrappedInput::Raw(U256::from(42));
137
+ /// assert_eq!(raw.to_string(), "42");
138
+ ///
139
+ /// let push1 = WrappedOpcode::new(0x60, vec![WrappedInput::Raw(U256::from(1))]);
140
+ /// let op_input = WrappedInput::Opcode(push1);
141
+ /// assert_eq!(op_input.to_string(), "PUSH1(1)");
142
+ /// ```
52
143
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
53
144
match self {
54
145
WrappedInput :: Raw ( u256) => write ! ( f, "{u256}" ) ,
@@ -58,12 +149,47 @@ impl std::fmt::Display for WrappedInput {
58
149
}
59
150
60
151
impl From < U256 > for WrappedInput {
152
+ /// Converts a [`U256`] value into a [`WrappedInput::Raw`].
153
+ ///
154
+ /// This implementation allows for more ergonomic code when creating
155
+ /// [`WrappedInput`]s from raw values.
156
+ ///
157
+ /// ```
158
+ /// use heimdall_vm::core::opcodes::wrapped::WrappedInput;
159
+ /// use alloy::primitives::U256;
160
+ ///
161
+ /// let u256_val = U256::from(42);
162
+ /// let input: WrappedInput = u256_val.into();
163
+ ///
164
+ /// match input {
165
+ /// WrappedInput::Raw(val) => assert_eq!(val, U256::from(42)),
166
+ /// _ => panic!("Expected Raw variant"),
167
+ /// }
168
+ /// ```
61
169
fn from ( val : U256 ) -> Self {
62
170
WrappedInput :: Raw ( val)
63
171
}
64
172
}
65
173
66
174
impl From < WrappedOpcode > for WrappedInput {
175
+ /// Converts a [`WrappedOpcode`] into a [`WrappedInput::Opcode`].
176
+ ///
177
+ /// This implementation allows for more ergonomic code when creating
178
+ /// [`WrappedInput`]s from operations.
179
+ ///
180
+ /// ```
181
+ /// use heimdall_vm::core::opcodes::wrapped::WrappedInput;
182
+ /// use heimdall_vm::ext::lexers::solidity::WrappedOpcode;
183
+ /// use alloy::primitives::U256;
184
+ ///
185
+ /// let push1 = WrappedOpcode::new(0x60, vec![WrappedInput::Raw(U256::from(1))]);
186
+ /// let input: WrappedInput = push1.clone().into();
187
+ ///
188
+ /// match input {
189
+ /// WrappedInput::Opcode(op) => assert_eq!(op, push1),
190
+ /// _ => panic!("Expected Opcode variant"),
191
+ /// }
192
+ /// ```
67
193
fn from ( val : WrappedOpcode ) -> Self {
68
194
WrappedInput :: Opcode ( val)
69
195
}
0 commit comments