leo_interpreter/
cursor_aleo.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use super::*;
18
19use leo_ast::{
20    BinaryOperation,
21    CoreFunction,
22    IntegerType,
23    Location,
24    Type,
25    UnaryOperation,
26    interpreter_value::{self, AsyncExecution, Value},
27};
28
29use snarkvm::{
30    prelude::{Identifier, LiteralType, PlaintextType, Register, TestnetV0},
31    synthesizer::{
32        Command,
33        Instruction,
34        program::{CallOperator, CastType, Operand},
35    },
36};
37
38use std::mem;
39
40impl Cursor {
41    fn mapping_by_call_operator(&self, operator: &CallOperator<TestnetV0>) -> Option<&HashMap<Value, Value>> {
42        let (program, name) = match operator {
43            CallOperator::Locator(locator) => {
44                (Some(snarkvm_identifier_to_symbol(locator.name())), snarkvm_identifier_to_symbol(locator.resource()))
45            }
46            CallOperator::Resource(id) => (None, snarkvm_identifier_to_symbol(id)),
47        };
48        self.lookup_mapping(program, name)
49    }
50
51    fn get_register(&self, reg: &Register<TestnetV0>) -> Value {
52        let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.frames.last() else {
53            panic!();
54        };
55        match reg {
56            Register::Locator(index) => {
57                registers.get(index).expect("valid .aleo code doesn't access undefined registers").clone()
58            }
59            Register::Access(index, accesses) => {
60                let value = registers.get(index).expect("valid .aleo code doesn't access undefined registers");
61                value.accesses(accesses.iter().cloned()).expect("Accesses should work.")
62            }
63        }
64    }
65
66    fn set_register(&mut self, reg: Register<TestnetV0>, value: Value) {
67        let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.frames.last_mut() else {
68            panic!();
69        };
70
71        match reg {
72            Register::Locator(index) => {
73                registers.insert(index, value);
74            }
75            Register::Access(_, _) => panic!("Can't happen"),
76        }
77    }
78
79    fn instructions_len(&self) -> usize {
80        let Some(Frame { element: Element::AleoExecution { context, .. }, .. }) = self.frames.last() else {
81            panic!();
82        };
83        match &**context {
84            AleoContext::Closure(closure) => closure.instructions().len(),
85            AleoContext::Function(function) => function.instructions().len(),
86            AleoContext::Finalize(finalize) => finalize.commands().len(),
87        }
88    }
89
90    fn increment_instruction_index(&mut self) {
91        let Some(Frame { element: Element::AleoExecution { instruction_index, .. }, .. }) = self.frames.last_mut()
92        else {
93            panic!();
94        };
95        *instruction_index += 1;
96    }
97
98    fn execution_complete(&self) -> bool {
99        let Some(Frame { element: Element::AleoExecution { instruction_index, .. }, .. }) = self.frames.last() else {
100            panic!();
101        };
102        *instruction_index >= self.instructions_len()
103    }
104
105    fn next_instruction(&self) -> Option<&Instruction<TestnetV0>> {
106        let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) = self.frames.last()
107        else {
108            panic!();
109        };
110        match &**context {
111            AleoContext::Closure(closure) => closure.instructions().get(*instruction_index),
112            AleoContext::Function(function) => function.instructions().get(*instruction_index),
113            AleoContext::Finalize(_) => None,
114        }
115    }
116
117    fn next_command(&self) -> Option<&Command<TestnetV0>> {
118        let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) = self.frames.last()
119        else {
120            panic!();
121        };
122        match &**context {
123            AleoContext::Closure(_) | AleoContext::Function(_) => None,
124            AleoContext::Finalize(finalize) => finalize.commands().get(*instruction_index),
125        }
126    }
127
128    fn operand_value(&self, operand: &Operand<TestnetV0>) -> Value {
129        match operand {
130            Operand::Literal(literal) => literal.clone().into(),
131            Operand::Register(register) => self.get_register(register).clone(),
132            Operand::ProgramID(_) => todo!(),
133            Operand::Signer => self.signer.clone(),
134            Operand::Caller => {
135                if let Some(function_context) = self.contexts.last() {
136                    function_context.caller.clone()
137                } else {
138                    self.signer.clone()
139                }
140            }
141            Operand::BlockHeight => self.block_height.into(),
142            Operand::NetworkID => todo!(),
143            Operand::Checksum(_) => todo!("Look up the program in the global namespace and get its checksum"),
144            Operand::Edition(_) => todo!("Look up the program in the global namespace and get its edition"),
145            Operand::ProgramOwner(_) => todo!("Prompt user if not set"),
146        }
147    }
148
149    fn step_aleo_instruction(&mut self, instruction: Instruction<TestnetV0>) -> Result<()> {
150        // The Aleo VM code is a linear sequence of instructions, so we don't need to keep
151        // a stack of Elements (except for calls). Just run instructions in order.
152        use Instruction::*;
153
154        let Some(Frame { step, .. }) = self.frames.last() else {
155            panic!("frame expected");
156        };
157
158        macro_rules! unary {
159            ($svm_op: expr, $op: ident) => {{
160                let operand = self.operand_value(&$svm_op.operands()[0]);
161                let value =
162                    interpreter_value::evaluate_unary(Default::default(), UnaryOperation::$op, &operand, &None)?;
163                self.increment_instruction_index();
164                (value, $svm_op.destinations()[0].clone())
165            }};
166        }
167
168        macro_rules! binary {
169            ($svm_op: expr, $op: ident) => {{
170                let operand0 = self.operand_value(&$svm_op.operands()[0]);
171                let operand1 = self.operand_value(&$svm_op.operands()[1]);
172                let value = interpreter_value::evaluate_binary(
173                    Default::default(),
174                    BinaryOperation::$op,
175                    &operand0,
176                    &operand1,
177                    &None,
178                )?;
179                self.increment_instruction_index();
180                (value, $svm_op.destinations()[0].clone())
181            }};
182        }
183
184        macro_rules! commit_function {
185            ($commit: expr,
186             $to_address: ident,
187             $to_field: ident,
188             $to_group: ident,
189            ) => {{
190                let core_function = match $commit.destination_type() {
191                    LiteralType::Address => CoreFunction::$to_address,
192                    LiteralType::Field => CoreFunction::$to_field,
193                    LiteralType::Group => CoreFunction::$to_group,
194                    _ => panic!("invalid commit destination type"),
195                };
196
197                let randomizer_value = self.operand_value(&$commit.operands()[0]);
198                let operand_value = self.operand_value(&$commit.operands()[1]);
199                self.values.push(randomizer_value);
200                self.values.push(operand_value);
201                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
202                self.increment_instruction_index();
203                (value.expect("Evaluation should work"), $commit.destinations()[0].clone())
204            }};
205        }
206
207        macro_rules! hash_function {
208            ($hash: expr,
209             $to_address: ident,
210             $to_field: ident,
211             $to_group: ident,
212             $to_i8: ident,
213             $to_i16: ident,
214             $to_i32: ident,
215             $to_i64: ident,
216             $to_i128: ident,
217             $to_u8: ident,
218             $to_u16: ident,
219             $to_u32: ident,
220             $to_u64: ident,
221             $to_u128: ident,
222             $to_scalar: ident,
223            ) => {{
224                let core_function = match $hash.destination_type() {
225                    PlaintextType::Literal(LiteralType::Address) => CoreFunction::$to_address,
226                    PlaintextType::Literal(LiteralType::Field) => CoreFunction::$to_field,
227                    PlaintextType::Literal(LiteralType::Group) => CoreFunction::$to_group,
228                    PlaintextType::Literal(LiteralType::I8) => CoreFunction::$to_i8,
229                    PlaintextType::Literal(LiteralType::I16) => CoreFunction::$to_i16,
230                    PlaintextType::Literal(LiteralType::I32) => CoreFunction::$to_i32,
231                    PlaintextType::Literal(LiteralType::I64) => CoreFunction::$to_i64,
232                    PlaintextType::Literal(LiteralType::I128) => CoreFunction::$to_i128,
233                    PlaintextType::Literal(LiteralType::U8) => CoreFunction::$to_u8,
234                    PlaintextType::Literal(LiteralType::U16) => CoreFunction::$to_u16,
235                    PlaintextType::Literal(LiteralType::U32) => CoreFunction::$to_u32,
236                    PlaintextType::Literal(LiteralType::U64) => CoreFunction::$to_u64,
237                    PlaintextType::Literal(LiteralType::U128) => CoreFunction::$to_u128,
238                    PlaintextType::Literal(LiteralType::Scalar) => CoreFunction::$to_scalar,
239                    _ => panic!("invalid hash destination type"),
240                };
241                let operand_value = self.operand_value(&$hash.operands()[0]);
242                self.values.push(operand_value);
243                let value = interpreter_value::evaluate_core_function(self, core_function, &[], Span::default())?;
244                self.increment_instruction_index();
245                (value.expect("Evaluation should work"), $hash.destinations()[0].clone())
246            }};
247        }
248
249        let (value, destination) = match instruction {
250            Abs(abs) => unary!(abs, Abs),
251            AbsWrapped(abs_wrapped) => unary!(abs_wrapped, AbsWrapped),
252            Add(add) => binary!(add, Add),
253            AddWrapped(add_wrapped) => binary!(add_wrapped, AddWrapped),
254            And(and) => binary!(and, BitwiseAnd),
255            AssertEq(assert_eq) => {
256                let operand0 = self.operand_value(&assert_eq.operands()[0]);
257                let operand1 = self.operand_value(&assert_eq.operands()[1]);
258                if !operand0.eq(&operand1)? {
259                    halt_no_span!("assertion failure: {operand0} != {operand1}");
260                }
261                self.increment_instruction_index();
262                return Ok(());
263            }
264            AssertNeq(assert_neq) => {
265                let operand0 = self.operand_value(&assert_neq.operands()[0]);
266                let operand1 = self.operand_value(&assert_neq.operands()[1]);
267                if operand0.eq(&operand1)? {
268                    halt_no_span!("assertion failure: {operand0} != {operand1}");
269                }
270                self.increment_instruction_index();
271                return Ok(());
272            }
273            Async(async_) if *step == 0 => {
274                let program = self.contexts.current_program().expect("there should be a program");
275                let name = snarkvm_identifier_to_symbol(async_.function_name());
276                let arguments: Vec<Value> = async_.operands().iter().map(|op| self.operand_value(op)).collect();
277                if self.really_async {
278                    self.increment_instruction_index();
279                    let async_ex =
280                        AsyncExecution::AsyncFunctionCall { function: Location::new(program, vec![name]), arguments };
281                    (vec![async_ex].into(), async_.destinations()[0].clone())
282                } else {
283                    self.do_call(
284                        program,
285                        &[name],
286                        arguments.into_iter(),
287                        true, // finalize
288                        Span::default(),
289                    )?;
290                    self.increment_step();
291                    return Ok(());
292                }
293            }
294            Call(call) if *step == 0 => {
295                let (program, name) = match call.operator() {
296                    CallOperator::Locator(locator) => (
297                        snarkvm_identifier_to_symbol(locator.resource()),
298                        snarkvm_identifier_to_symbol(locator.program_id().name()),
299                    ),
300                    CallOperator::Resource(id) => (
301                        snarkvm_identifier_to_symbol(id),
302                        self.contexts.current_program().expect("there should be a program"),
303                    ),
304                };
305                let arguments: Vec<Value> = call.operands().iter().map(|op| self.operand_value(op)).collect();
306                self.do_call(
307                    program,
308                    &[name],
309                    arguments.into_iter(),
310                    false, // finalize
311                    Span::default(),
312                )?;
313                self.increment_step();
314                return Ok(());
315            }
316            Async(async_) if *step == 1 => {
317                // We've done a call, and the result is on the value stack.
318                self.values.pop();
319                self.set_register(async_.destinations()[0].clone(), Vec::<AsyncExecution>::new().into());
320                self.increment_instruction_index();
321                return Ok(());
322            }
323            Call(call) if *step == 1 => {
324                // We've done a call, and the result is on the value stack.
325                let Some(result) = self.values.pop() else {
326                    panic!("should have a result");
327                };
328                if call.destinations().len() == 1 {
329                    self.set_register(call.destinations()[0].clone(), result);
330                } else {
331                    for (i, dest) in call.destinations().iter().enumerate() {
332                        self.set_register(
333                            dest.clone(),
334                            result.tuple_index(i).expect("Function returning multiple values should create a tuple."),
335                        );
336                    }
337                }
338                self.increment_instruction_index();
339                return Ok(());
340            }
341            Call(_) | Async(_) => unreachable!("all cases covered above"),
342            Cast(cast) => {
343                let destination = cast.destinations()[0].clone();
344
345                self.increment_instruction_index();
346
347                match cast.cast_type() {
348                    CastType::GroupXCoordinate => {
349                        let value = self.operand_value(&cast.operands()[0]);
350                        let mut values = vec![value];
351                        let Some(result_value) = interpreter_value::evaluate_core_function(
352                            &mut values,
353                            CoreFunction::GroupToXCoordinate,
354                            &[],
355                            Default::default(),
356                        )?
357                        else {
358                            halt_no_span!("GroupToXCoordinate didn't produce a value.");
359                        };
360                        (result_value, destination)
361                    }
362                    CastType::GroupYCoordinate => {
363                        let value = self.operand_value(&cast.operands()[0]);
364                        let mut values = vec![value];
365                        let Some(result_value) = interpreter_value::evaluate_core_function(
366                            &mut values,
367                            CoreFunction::GroupToYCoordinate,
368                            &[],
369                            Default::default(),
370                        )?
371                        else {
372                            halt_no_span!("GroupToYCoordinate didn't produce a value.");
373                        };
374                        (result_value, destination)
375                    }
376                    CastType::Plaintext(PlaintextType::Array(_array)) => {
377                        let value = Value::make_array(cast.operands().iter().map(|op| self.operand_value(op)));
378                        (value, destination)
379                    }
380                    CastType::Plaintext(PlaintextType::Literal(literal_type)) => {
381                        let operand = self.operand_value(&cast.operands()[0]);
382                        let Some(value) = operand.cast(&snarkvm_literal_type_to_type(*literal_type)) else {
383                            halt_no_span!("cast failure");
384                        };
385                        (value, destination)
386                    }
387                    CastType::Plaintext(PlaintextType::Struct(struct_name)) => {
388                        let name = Symbol::intern(&struct_name.to_string());
389                        let struct_type = self.structs.get([name].as_slice()).expect("struct type should exist");
390                        let operands = cast.operands().iter().map(|op| self.operand_value(op));
391                        let value = Value::make_struct(
392                            struct_type.keys().cloned().zip(operands),
393                            self.current_program().unwrap(),
394                            vec![name],
395                        );
396                        (value, destination)
397                    }
398                    CastType::Record(record_name) => {
399                        let program = self.current_program().unwrap();
400                        let name = Symbol::intern(&record_name.to_string());
401                        let path = vec![name];
402                        let record_type = self.records.get(&(program, path.clone())).expect("record type should exist");
403                        let operands = cast.operands().iter().map(|op| self.operand_value(op));
404                        let value =
405                            Value::make_record(record_type.keys().cloned().zip(operands), program, path.clone());
406                        (value, destination)
407                    }
408                    CastType::ExternalRecord(locator) => {
409                        let program = Symbol::intern(&locator.program_id().name().to_string());
410                        let name = Symbol::intern(&locator.resource().to_string());
411                        let path = vec![name];
412                        let record_type = self.records.get(&(program, path.clone())).expect("record type should exist");
413                        let operands = cast.operands().iter().map(|op| self.operand_value(op));
414                        let value =
415                            Value::make_record(record_type.keys().cloned().zip(operands), program, path.clone());
416                        (value, destination)
417                    }
418                }
419            }
420            CastLossy(cast_lossy) => {
421                match cast_lossy.cast_type() {
422                    CastType::Plaintext(PlaintextType::Literal(literal_type)) => {
423                        // This is the only variant supported for lossy casts.
424                        let operand = self.operand_value(&cast_lossy.operands()[0]);
425                        let Some(value) = operand.cast_lossy(literal_type) else {
426                            halt_no_span!("Cast failure");
427                        };
428                        let destination = cast_lossy.destinations()[0].clone();
429                        (value, destination)
430                    }
431                    _ => tc_fail!(),
432                }
433            }
434            CommitBHP256(commit) => {
435                commit_function!(commit, BHP256CommitToAddress, BHP256CommitToField, BHP256CommitToGroup,)
436            }
437            CommitBHP512(commit) => {
438                commit_function!(commit, BHP512CommitToAddress, BHP512CommitToField, BHP512CommitToGroup,)
439            }
440            CommitBHP768(commit) => {
441                commit_function!(commit, BHP768CommitToAddress, BHP768CommitToField, BHP768CommitToGroup,)
442            }
443            CommitBHP1024(commit) => {
444                commit_function!(commit, BHP1024CommitToAddress, BHP1024CommitToField, BHP1024CommitToGroup,)
445            }
446            CommitPED64(commit) => {
447                commit_function!(commit, Pedersen64CommitToAddress, Pedersen64CommitToField, Pedersen64CommitToGroup,)
448            }
449            CommitPED128(commit) => {
450                commit_function!(commit, Pedersen128CommitToAddress, Pedersen128CommitToField, Pedersen128CommitToGroup,)
451            }
452            Div(div) => binary!(div, Div),
453            DivWrapped(div_wrapped) => binary!(div_wrapped, DivWrapped),
454            Double(double) => unary!(double, Double),
455            GreaterThan(gt) => binary!(gt, Gt),
456            GreaterThanOrEqual(gte) => binary!(gte, Gte),
457            HashBHP256(hash) => hash_function!(
458                hash,
459                BHP256HashToAddress,
460                BHP256HashToField,
461                BHP256HashToGroup,
462                BHP256HashToI8,
463                BHP256HashToI16,
464                BHP256HashToI32,
465                BHP256HashToI64,
466                BHP256HashToI128,
467                BHP256HashToU8,
468                BHP256HashToU16,
469                BHP256HashToU32,
470                BHP256HashToU64,
471                BHP256HashToU128,
472                BHP256HashToScalar,
473            ),
474            HashBHP512(hash) => hash_function!(
475                hash,
476                BHP512HashToAddress,
477                BHP512HashToField,
478                BHP512HashToGroup,
479                BHP512HashToI8,
480                BHP512HashToI16,
481                BHP512HashToI32,
482                BHP512HashToI64,
483                BHP512HashToI128,
484                BHP512HashToU8,
485                BHP512HashToU16,
486                BHP512HashToU32,
487                BHP512HashToU64,
488                BHP512HashToU128,
489                BHP512HashToScalar,
490            ),
491            HashBHP768(hash) => hash_function!(
492                hash,
493                BHP768HashToAddress,
494                BHP768HashToField,
495                BHP768HashToGroup,
496                BHP768HashToI8,
497                BHP768HashToI16,
498                BHP768HashToI32,
499                BHP768HashToI64,
500                BHP768HashToI128,
501                BHP768HashToU8,
502                BHP768HashToU16,
503                BHP768HashToU32,
504                BHP768HashToU64,
505                BHP768HashToU128,
506                BHP768HashToScalar,
507            ),
508            HashBHP1024(hash) => hash_function!(
509                hash,
510                BHP1024HashToAddress,
511                BHP1024HashToField,
512                BHP1024HashToGroup,
513                BHP1024HashToI8,
514                BHP1024HashToI16,
515                BHP1024HashToI32,
516                BHP1024HashToI64,
517                BHP1024HashToI128,
518                BHP1024HashToU8,
519                BHP1024HashToU16,
520                BHP1024HashToU32,
521                BHP1024HashToU64,
522                BHP1024HashToU128,
523                BHP1024HashToScalar,
524            ),
525            HashKeccak256(hash) => hash_function!(
526                hash,
527                Keccak256HashToAddress,
528                Keccak256HashToField,
529                Keccak256HashToGroup,
530                Keccak256HashToI8,
531                Keccak256HashToI16,
532                Keccak256HashToI32,
533                Keccak256HashToI64,
534                Keccak256HashToI128,
535                Keccak256HashToU8,
536                Keccak256HashToU16,
537                Keccak256HashToU32,
538                Keccak256HashToU64,
539                Keccak256HashToU128,
540                Keccak256HashToScalar,
541            ),
542            HashKeccak384(hash) => hash_function!(
543                hash,
544                Keccak384HashToAddress,
545                Keccak384HashToField,
546                Keccak384HashToGroup,
547                Keccak384HashToI8,
548                Keccak384HashToI16,
549                Keccak384HashToI32,
550                Keccak384HashToI64,
551                Keccak384HashToI128,
552                Keccak384HashToU8,
553                Keccak384HashToU16,
554                Keccak384HashToU32,
555                Keccak384HashToU64,
556                Keccak384HashToU128,
557                Keccak384HashToScalar,
558            ),
559            HashKeccak512(hash) => hash_function!(
560                hash,
561                Keccak512HashToAddress,
562                Keccak512HashToField,
563                Keccak512HashToGroup,
564                Keccak512HashToI8,
565                Keccak512HashToI16,
566                Keccak512HashToI32,
567                Keccak512HashToI64,
568                Keccak512HashToI128,
569                Keccak512HashToU8,
570                Keccak512HashToU16,
571                Keccak512HashToU32,
572                Keccak512HashToU64,
573                Keccak512HashToU128,
574                Keccak512HashToScalar,
575            ),
576            HashPED64(hash) => hash_function!(
577                hash,
578                Pedersen64HashToAddress,
579                Pedersen64HashToField,
580                Pedersen64HashToGroup,
581                Pedersen64HashToI8,
582                Pedersen64HashToI16,
583                Pedersen64HashToI32,
584                Pedersen64HashToI64,
585                Pedersen64HashToI128,
586                Pedersen64HashToU8,
587                Pedersen64HashToU16,
588                Pedersen64HashToU32,
589                Pedersen64HashToU64,
590                Pedersen64HashToU128,
591                Pedersen64HashToScalar,
592            ),
593            HashPED128(hash) => hash_function!(
594                hash,
595                Pedersen128HashToAddress,
596                Pedersen128HashToField,
597                Pedersen128HashToGroup,
598                Pedersen128HashToI8,
599                Pedersen128HashToI16,
600                Pedersen128HashToI32,
601                Pedersen128HashToI64,
602                Pedersen128HashToI128,
603                Pedersen128HashToU8,
604                Pedersen128HashToU16,
605                Pedersen128HashToU32,
606                Pedersen128HashToU64,
607                Pedersen128HashToU128,
608                Pedersen128HashToScalar,
609            ),
610            HashPSD2(hash) => hash_function!(
611                hash,
612                Poseidon2HashToAddress,
613                Poseidon2HashToField,
614                Poseidon2HashToGroup,
615                Poseidon2HashToI8,
616                Poseidon2HashToI16,
617                Poseidon2HashToI32,
618                Poseidon2HashToI64,
619                Poseidon2HashToI128,
620                Poseidon2HashToU8,
621                Poseidon2HashToU16,
622                Poseidon2HashToU32,
623                Poseidon2HashToU64,
624                Poseidon2HashToU128,
625                Poseidon2HashToScalar,
626            ),
627            HashPSD4(hash) => hash_function!(
628                hash,
629                Poseidon4HashToAddress,
630                Poseidon4HashToField,
631                Poseidon4HashToGroup,
632                Poseidon4HashToI8,
633                Poseidon4HashToI16,
634                Poseidon4HashToI32,
635                Poseidon4HashToI64,
636                Poseidon4HashToI128,
637                Poseidon4HashToU8,
638                Poseidon4HashToU16,
639                Poseidon4HashToU32,
640                Poseidon4HashToU64,
641                Poseidon4HashToU128,
642                Poseidon4HashToScalar,
643            ),
644            HashPSD8(hash) => hash_function!(
645                hash,
646                Poseidon8HashToAddress,
647                Poseidon8HashToField,
648                Poseidon8HashToGroup,
649                Poseidon8HashToI8,
650                Poseidon8HashToI16,
651                Poseidon8HashToI32,
652                Poseidon8HashToI64,
653                Poseidon8HashToI128,
654                Poseidon8HashToU8,
655                Poseidon8HashToU16,
656                Poseidon8HashToU32,
657                Poseidon8HashToU64,
658                Poseidon8HashToU128,
659                Poseidon8HashToScalar,
660            ),
661            HashSha3_256(hash) => hash_function!(
662                hash,
663                SHA3_256HashToAddress,
664                SHA3_256HashToField,
665                SHA3_256HashToGroup,
666                SHA3_256HashToI8,
667                SHA3_256HashToI16,
668                SHA3_256HashToI32,
669                SHA3_256HashToI64,
670                SHA3_256HashToI128,
671                SHA3_256HashToU8,
672                SHA3_256HashToU16,
673                SHA3_256HashToU32,
674                SHA3_256HashToU64,
675                SHA3_256HashToU128,
676                SHA3_256HashToScalar,
677            ),
678            HashSha3_384(hash) => hash_function!(
679                hash,
680                SHA3_384HashToAddress,
681                SHA3_384HashToField,
682                SHA3_384HashToGroup,
683                SHA3_384HashToI8,
684                SHA3_384HashToI16,
685                SHA3_384HashToI32,
686                SHA3_384HashToI64,
687                SHA3_384HashToI128,
688                SHA3_384HashToU8,
689                SHA3_384HashToU16,
690                SHA3_384HashToU32,
691                SHA3_384HashToU64,
692                SHA3_384HashToU128,
693                SHA3_384HashToScalar,
694            ),
695            HashSha3_512(hash) => hash_function!(
696                hash,
697                SHA3_512HashToAddress,
698                SHA3_512HashToField,
699                SHA3_512HashToGroup,
700                SHA3_512HashToI8,
701                SHA3_512HashToI16,
702                SHA3_512HashToI32,
703                SHA3_512HashToI64,
704                SHA3_512HashToI128,
705                SHA3_512HashToU8,
706                SHA3_512HashToU16,
707                SHA3_512HashToU32,
708                SHA3_512HashToU64,
709                SHA3_512HashToU128,
710                SHA3_512HashToScalar,
711            ),
712            HashManyPSD2(_) | HashManyPSD4(_) | HashManyPSD8(_) => panic!("these instructions don't exist yet"),
713            Inv(inv) => unary!(inv, Inverse),
714            IsEq(eq) => binary!(eq, Eq),
715            IsNeq(neq) => binary!(neq, Neq),
716            LessThan(lt) => binary!(lt, Lt),
717            LessThanOrEqual(lte) => binary!(lte, Lte),
718            Modulo(modulo) => binary!(modulo, Mod),
719            Mul(mul) => binary!(mul, Mul),
720            MulWrapped(mul_wrapped) => binary!(mul_wrapped, MulWrapped),
721            Nand(nand) => binary!(nand, Nand),
722            Neg(neg) => unary!(neg, Negate),
723            Nor(nor) => binary!(nor, Nor),
724            Not(not) => unary!(not, Not),
725            Or(or) => binary!(or, BitwiseOr),
726            Pow(pow) => binary!(pow, Pow),
727            PowWrapped(pow_wrapped) => binary!(pow_wrapped, PowWrapped),
728            Rem(rem) => binary!(rem, Rem),
729            RemWrapped(rem_wrapped) => binary!(rem_wrapped, RemWrapped),
730            Shl(shl) => binary!(shl, Shl),
731            ShlWrapped(shl_wrapped) => binary!(shl_wrapped, ShlWrapped),
732            Shr(shr) => binary!(shr, Shr),
733            ShrWrapped(shr_wrapped) => binary!(shr_wrapped, ShrWrapped),
734            SignVerify(_) => todo!(),
735            Square(square) => unary!(square, Square),
736            SquareRoot(sqrt) => unary!(sqrt, SquareRoot),
737            Sub(sub) => binary!(sub, Sub),
738            SubWrapped(sub_wrapped) => binary!(sub_wrapped, SubWrapped),
739            Ternary(ternary) => {
740                let condition = self.operand_value(&ternary.operands()[0]);
741                let result = match condition.try_into() {
742                    Ok(true) => &ternary.operands()[1],
743                    Ok(false) => &ternary.operands()[2],
744                    _ => tc_fail!(),
745                };
746                self.increment_instruction_index();
747                (self.operand_value(result), ternary.destinations()[0].clone())
748            }
749            Xor(xor) => binary!(xor, Xor),
750        };
751
752        self.set_register(destination, value);
753
754        Ok(())
755    }
756
757    fn outputs(&self) -> Vec<Value> {
758        let Some(Frame { element, .. }) = self.frames.last() else {
759            panic!("frame expected");
760        };
761        let Element::AleoExecution { context, .. } = element else {
762            panic!("aleo execution expected");
763        };
764
765        let mut result = match &**context {
766            AleoContext::Closure(closure) => {
767                closure.outputs().iter().map(|output| self.operand_value(output.operand())).collect()
768            }
769            AleoContext::Function(function) => {
770                function.outputs().iter().map(|output| self.operand_value(output.operand())).collect()
771            }
772            AleoContext::Finalize(_finalize) => Vec::new(),
773        };
774
775        if result.is_empty() {
776            result.push(Value::make_unit());
777        }
778        result
779    }
780
781    fn step_aleo_command(&mut self, command: Command<TestnetV0>) -> Result<()> {
782        use Command::*;
783
784        let (value, destination) = match command {
785            Instruction(instruction) => {
786                self.step_aleo_instruction(instruction)?;
787                return Ok(());
788            }
789            Await(await_) => {
790                let value = self.get_register(await_.register());
791                let Some(asyncs) = value.as_future() else {
792                    halt_no_span!("attempted to await a non-future");
793                };
794                self.contexts.add_future(asyncs.to_vec());
795                self.increment_instruction_index();
796                return Ok(());
797            }
798            Contains(contains) => {
799                // Value has interior mutability, since SnarkVM's value does, but this is okay - it's just the OnceCell which houses its bits.
800                #[allow(clippy::mutable_key_type)]
801                let mapping = self.mapping_by_call_operator(contains.mapping()).expect("mapping should be present");
802                let key = self.operand_value(contains.key());
803                let result = mapping.contains_key(&key).into();
804                self.increment_instruction_index();
805                (result, contains.destination().clone())
806            }
807            Get(get) => {
808                let key = self.operand_value(get.key());
809                let value = self.mapping_by_call_operator(get.mapping()).and_then(|mapping| mapping.get(&key)).cloned();
810                self.increment_instruction_index();
811
812                match value {
813                    Some(v) => (v, get.destination().clone()),
814                    None => halt_no_span!("map access failure: {key}"),
815                }
816            }
817            GetOrUse(get_or_use) => {
818                let key = self.operand_value(get_or_use.key());
819                let value =
820                    self.mapping_by_call_operator(get_or_use.mapping()).and_then(|mapping| mapping.get(&key)).cloned();
821
822                let use_value = value.unwrap_or_else(|| self.operand_value(get_or_use.default()));
823                self.increment_instruction_index();
824
825                (use_value, get_or_use.destination().clone())
826            }
827            Remove(remove) => {
828                let key = self.operand_value(remove.key());
829                let mapping_name = snarkvm_identifier_to_symbol(remove.mapping_name());
830                let maybe_mapping = self.lookup_mapping_mut(None, mapping_name);
831                match maybe_mapping {
832                    None => halt_no_span!("no such mapping {mapping_name}"),
833                    Some(mapping) => {
834                        mapping.remove(&key);
835                    }
836                }
837                self.increment_instruction_index();
838                return Ok(());
839            }
840            Set(set) => {
841                let key = self.operand_value(set.key());
842                let value = self.operand_value(set.value());
843                let mapping_name = snarkvm_identifier_to_symbol(set.mapping_name());
844                let maybe_mapping = self.lookup_mapping_mut(None, mapping_name);
845                match maybe_mapping {
846                    None => halt_no_span!("no such mapping {mapping_name}"),
847                    Some(mapping) => {
848                        mapping.insert(key, value);
849                    }
850                }
851                self.increment_instruction_index();
852                return Ok(());
853            }
854            RandChaCha(rand) => {
855                // TODO - this is not using the other operands which are supposed to seed the RNG.
856                use CoreFunction::*;
857                let function = match rand.destination_type() {
858                    LiteralType::Address => ChaChaRandAddress,
859                    LiteralType::Boolean => ChaChaRandBool,
860                    LiteralType::Field => ChaChaRandField,
861                    LiteralType::Group => ChaChaRandGroup,
862                    LiteralType::I8 => ChaChaRandI8,
863                    LiteralType::I16 => ChaChaRandI16,
864                    LiteralType::I32 => ChaChaRandI32,
865                    LiteralType::I64 => ChaChaRandI64,
866                    LiteralType::I128 => ChaChaRandI128,
867                    LiteralType::U8 => ChaChaRandU8,
868                    LiteralType::U16 => ChaChaRandU16,
869                    LiteralType::U32 => ChaChaRandU32,
870                    LiteralType::U64 => ChaChaRandU64,
871                    LiteralType::U128 => ChaChaRandU128,
872                    LiteralType::Scalar => ChaChaRandScalar,
873                    LiteralType::Signature => todo!(),
874                    LiteralType::String => todo!(),
875                };
876                let value =
877                    interpreter_value::evaluate_core_function(self, function, &[], Default::default())?.unwrap();
878                self.increment_instruction_index();
879                (value, rand.destination().clone())
880            }
881            BranchEq(branch_eq) => {
882                let first = self.operand_value(branch_eq.first());
883                let second = self.operand_value(branch_eq.second());
884                if first.eq(&second)? {
885                    self.branch(branch_eq.position());
886                } else {
887                    self.increment_instruction_index();
888                }
889                return Ok(());
890            }
891            BranchNeq(branch_neq) => {
892                let first = self.operand_value(branch_neq.first());
893                let second = self.operand_value(branch_neq.second());
894                if !first.eq(&second)? {
895                    self.branch(branch_neq.position());
896                } else {
897                    self.increment_instruction_index();
898                }
899                return Ok(());
900            }
901            Position(_) => {
902                self.increment_instruction_index();
903                return Ok(());
904            }
905        };
906
907        self.set_register(destination, value);
908
909        Ok(())
910    }
911
912    fn branch(&mut self, label: &Identifier<TestnetV0>) {
913        let Some(Frame { element: Element::AleoExecution { instruction_index, context, .. }, .. }) =
914            self.frames.last_mut()
915        else {
916            panic!();
917        };
918        let AleoContext::Finalize(finalize) = &mut **context else {
919            panic!();
920        };
921        for (i, cmd) in finalize.commands().iter().enumerate() {
922            if let Command::Position(position) = cmd {
923                if position.name() == label {
924                    *instruction_index = i;
925                    return;
926                }
927            }
928        }
929        panic!("branch to nonexistent label {label}");
930    }
931
932    pub fn step_aleo(&mut self) -> Result<()> {
933        if let Some(command) = self.next_command().cloned() {
934            self.step_aleo_command(command)?;
935        } else if let Some(instruction) = self.next_instruction().cloned() {
936            self.step_aleo_instruction(instruction)?;
937        }
938
939        if self.execution_complete() {
940            let mut outputs = self.outputs();
941            self.frames.pop();
942            self.contexts.pop();
943            if outputs.len() > 1 {
944                self.values.push(Value::make_tuple(outputs));
945            } else {
946                self.values.push(mem::take(&mut outputs[0]));
947            }
948        }
949
950        Ok(())
951    }
952}
953
954fn snarkvm_literal_type_to_type(snarkvm_type: LiteralType) -> Type {
955    use Type::*;
956    match snarkvm_type {
957        LiteralType::Address => Address,
958        LiteralType::Boolean => Boolean,
959        LiteralType::Field => Field,
960        LiteralType::Group => Group,
961        LiteralType::I8 => Integer(IntegerType::I8),
962        LiteralType::I16 => Integer(IntegerType::I16),
963        LiteralType::I32 => Integer(IntegerType::I32),
964        LiteralType::I64 => Integer(IntegerType::I64),
965        LiteralType::I128 => Integer(IntegerType::I128),
966        LiteralType::U8 => Integer(IntegerType::U8),
967        LiteralType::U16 => Integer(IntegerType::U16),
968        LiteralType::U32 => Integer(IntegerType::U32),
969        LiteralType::U64 => Integer(IntegerType::U64),
970        LiteralType::U128 => Integer(IntegerType::U128),
971        LiteralType::Scalar => Scalar,
972        LiteralType::Signature => todo!(),
973        LiteralType::String => todo!(),
974    }
975}