1use crate::error::{AvmError, AvmResult};
4use crate::types::StackValue;
5use crate::vm::EvalContext;
6
7pub fn op_pop(ctx: &mut EvalContext) -> AvmResult<()> {
9 ctx.pop()?;
10 ctx.advance_pc(1)?;
11 Ok(())
12}
13
14pub fn op_dup(ctx: &mut EvalContext) -> AvmResult<()> {
16 let val = ctx.peek()?.clone();
17 ctx.push(val)?;
18 ctx.advance_pc(1)?;
19 Ok(())
20}
21
22pub fn op_dup2(ctx: &mut EvalContext) -> AvmResult<()> {
24 if ctx.stack_size() < 2 {
25 return Err(AvmError::StackUnderflow);
26 }
27
28 let b = ctx.pop()?; let a = ctx.pop()?; ctx.push(a.clone())?;
35 ctx.push(b.clone())?;
36
37 ctx.push(a)?;
39 ctx.push(b)?;
40
41 ctx.advance_pc(1)?;
42 Ok(())
43}
44
45pub fn op_swap(ctx: &mut EvalContext) -> AvmResult<()> {
47 let b = ctx.pop()?;
48 let a = ctx.pop()?;
49
50 ctx.push(b)?;
51 ctx.push(a)?;
52 ctx.advance_pc(1)?;
53 Ok(())
54}
55
56pub fn op_select(ctx: &mut EvalContext) -> AvmResult<()> {
58 let c = ctx.pop()?;
59 let b = ctx.pop()?;
60 let a = ctx.pop()?;
61
62 let condition = c.as_bool()?;
63 let result = if condition { a } else { b };
64
65 ctx.push(result)?;
66 ctx.advance_pc(1)?;
67 Ok(())
68}
69
70pub fn op_dig(ctx: &mut EvalContext) -> AvmResult<()> {
72 ctx.advance_pc(1)?;
73 let depth = ctx.read_bytes(1)?[0] as usize;
75 ctx.advance_pc(1)?;
76
77 if ctx.stack_size() <= depth {
78 return Err(AvmError::StackUnderflow);
79 }
80
81 let value = ctx.peek_at_depth(depth)?.clone();
83 ctx.push(value)?;
84 Ok(())
85}
86
87pub fn op_bury(ctx: &mut EvalContext) -> AvmResult<()> {
89 ctx.advance_pc(1)?;
90 let depth = ctx.read_bytes(1)?[0] as usize;
92 ctx.advance_pc(1)?;
93
94 if ctx.stack_size() <= depth {
95 return Err(AvmError::StackUnderflow);
96 }
97
98 let value = ctx.pop()?;
100 let _ = ctx.remove_at_depth(depth)?; ctx.insert_at_depth(depth, value)?; Ok(())
103}
104
105pub fn op_cover(ctx: &mut EvalContext) -> AvmResult<()> {
107 ctx.advance_pc(1)?;
108 let n = ctx.read_bytes(1)?[0] as usize;
109 ctx.advance_pc(1)?;
110
111 if ctx.stack_size() <= n {
112 return Err(AvmError::StackUnderflow);
113 }
114
115 let value = ctx.pop()?;
117 ctx.insert_at_depth(n, value)?;
118 Ok(())
119}
120
121pub fn op_uncover(ctx: &mut EvalContext) -> AvmResult<()> {
123 ctx.advance_pc(1)?;
124 let n = ctx.read_bytes(1)?[0] as usize;
125 ctx.advance_pc(1)?;
126
127 if ctx.stack_size() <= n {
128 return Err(AvmError::StackUnderflow);
129 }
130
131 let value = ctx.remove_at_depth(n)?;
133 ctx.push(value)?;
134 Ok(())
135}
136
137pub fn op_load(ctx: &mut EvalContext) -> AvmResult<()> {
139 ctx.advance_pc(1)?; let index = ctx.read_bytes(1)?[0];
141 ctx.advance_pc(1)?; let value = ctx.get_scratch(index)?.clone();
144 ctx.push(value)?;
145 Ok(())
146}
147
148pub fn op_store(ctx: &mut EvalContext) -> AvmResult<()> {
150 ctx.advance_pc(1)?; let index = ctx.read_bytes(1)?[0];
152 ctx.advance_pc(1)?; let value = ctx.pop()?;
155 ctx.set_scratch(index, value)?;
156 Ok(())
157}
158
159pub fn op_len(ctx: &mut EvalContext) -> AvmResult<()> {
161 let val = ctx.pop()?;
162 let len = match val {
163 StackValue::Bytes(bytes) => bytes.len() as u64,
164 StackValue::Uint(_) => 8, };
166
167 ctx.push(StackValue::Uint(len))?;
168 ctx.advance_pc(1)?;
169 Ok(())
170}
171
172pub fn op_itob(ctx: &mut EvalContext) -> AvmResult<()> {
174 let val = ctx.pop()?;
175 let int_val = val.as_uint()?;
176
177 let bytes = int_val.to_be_bytes().to_vec();
178 ctx.push(StackValue::Bytes(bytes))?;
179 ctx.advance_pc(1)?;
180 Ok(())
181}
182
183pub fn op_btoi(ctx: &mut EvalContext) -> AvmResult<()> {
185 let val = ctx.pop()?;
186 let bytes = val.as_bytes()?;
187
188 if bytes.is_empty() {
189 ctx.push(StackValue::Uint(0))?;
190 ctx.advance_pc(1)?;
191 return Ok(());
192 }
193
194 if bytes.len() > 8 {
195 return Err(AvmError::InvalidByteArrayLength {
196 expected: 8,
197 actual: bytes.len(),
198 });
199 }
200
201 let mut padded = vec![0u8; 8];
203 let start_idx = 8 - bytes.len();
204 padded[start_idx..].copy_from_slice(bytes);
205
206 let int_val = u64::from_be_bytes(padded.try_into().unwrap());
207 ctx.push(StackValue::Uint(int_val))?;
208 ctx.advance_pc(1)?;
209 Ok(())
210}
211
212pub fn op_concat(ctx: &mut EvalContext) -> AvmResult<()> {
214 let b = ctx.pop()?;
215 let a = ctx.pop()?;
216
217 let a_bytes = a.as_bytes()?;
218 let b_bytes = b.as_bytes()?;
219
220 let mut result = Vec::with_capacity(a_bytes.len() + b_bytes.len());
221 result.extend_from_slice(a_bytes);
222 result.extend_from_slice(b_bytes);
223
224 ctx.push(StackValue::Bytes(result))?;
225 ctx.advance_pc(1)?;
226 Ok(())
227}
228
229pub fn op_substring(ctx: &mut EvalContext) -> AvmResult<()> {
231 ctx.advance_pc(1)?; let start = ctx.read_bytes(1)?[0] as usize;
233 ctx.advance_pc(1)?; let length = ctx.read_bytes(1)?[0] as usize;
235 ctx.advance_pc(1)?; let val = ctx.pop()?;
238 let bytes = val.as_bytes()?;
239
240 if start >= bytes.len() || start + length > bytes.len() {
241 return Err(AvmError::InvalidByteArrayLength {
242 expected: start + length,
243 actual: bytes.len(),
244 });
245 }
246
247 let result = bytes[start..start + length].to_vec();
248 ctx.push(StackValue::Bytes(result))?;
249 Ok(())
250}
251
252pub fn op_substring3(ctx: &mut EvalContext) -> AvmResult<()> {
254 let end = ctx.pop()?;
255 let start = ctx.pop()?;
256 let val = ctx.pop()?;
257
258 let start_idx = start.as_uint()? as usize;
259 let end_idx = end.as_uint()? as usize;
260 let bytes = val.as_bytes()?;
261
262 if start_idx >= bytes.len() || end_idx > bytes.len() || start_idx > end_idx {
263 return Err(AvmError::InvalidByteArrayLength {
264 expected: end_idx,
265 actual: bytes.len(),
266 });
267 }
268
269 let result = bytes[start_idx..end_idx].to_vec();
270 ctx.push(StackValue::Bytes(result))?;
271 ctx.advance_pc(1)?;
272 Ok(())
273}
274
275pub fn op_dupn(ctx: &mut EvalContext) -> AvmResult<()> {
277 ctx.advance_pc(1)?; let n = ctx.read_bytes(1)?[0] as usize;
279 ctx.advance_pc(1)?; if n == 0 {
282 return Ok(());
283 }
284
285 if ctx.stack_size() < n {
286 return Err(AvmError::StackUnderflow);
287 }
288
289 let mut values = Vec::new();
291 for _ in 0..n {
292 values.push(ctx.pop()?);
293 }
294
295 for val in values.iter().rev() {
297 ctx.push(val.clone())?;
298 }
299
300 for val in values.iter().rev() {
302 ctx.push(val.clone())?;
303 }
304
305 Ok(())
306}
307
308pub fn op_popn(ctx: &mut EvalContext) -> AvmResult<()> {
310 ctx.advance_pc(1)?; let n = ctx.read_bytes(1)?[0] as usize;
312 ctx.advance_pc(1)?; if ctx.stack_size() < n {
315 return Err(AvmError::StackUnderflow);
316 }
317
318 for _ in 0..n {
319 ctx.pop()?;
320 }
321
322 Ok(())
323}