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