diff --git a/interpreter/src/cursor.rs b/interpreter/src/cursor.rs index 26d2ec531f..391777ba80 100644 --- a/interpreter/src/cursor.rs +++ b/interpreter/src/cursor.rs @@ -256,7 +256,7 @@ pub struct Cursor<'a> { pub signer: SvmAddress, - rng: ChaCha20Rng, + pub rng: ChaCha20Rng, pub block_height: u32, @@ -322,14 +322,14 @@ impl<'a> Cursor<'a> { self.globals.get(&GlobalId { program: context.program, name }).cloned() } - fn lookup_mapping(&self, program: Option, name: Symbol) -> Option<&HashMap> { + pub fn lookup_mapping(&self, program: Option, name: Symbol) -> Option<&HashMap> { let Some(program) = program.or(self.contexts.last().map(|c| c.program)) else { panic!("no program for mapping lookup"); }; self.mappings.get(&GlobalId { program, name }) } - fn lookup_mapping_mut(&mut self, program: Option, name: Symbol) -> Option<&mut HashMap> { + pub fn lookup_mapping_mut(&mut self, program: Option, name: Symbol) -> Option<&mut HashMap> { let Some(program) = program.or(self.contexts.last().map(|c| c.program)) else { panic!("no program for mapping lookup"); }; diff --git a/interpreter/src/cursor_aleo.rs b/interpreter/src/cursor_aleo.rs index bbb13a3836..98d7e7477a 100644 --- a/interpreter/src/cursor_aleo.rs +++ b/interpreter/src/cursor_aleo.rs @@ -19,14 +19,39 @@ use super::*; use leo_ast::{BinaryOperation, CoreFunction, IntegerType, Type, UnaryOperation}; use snarkvm::{ - prelude::{Boolean, Identifier, Literal, LiteralType, PlaintextType, Register, TestnetV0, integers::Integer}, + prelude::{ + Boolean, + Field, + Identifier, + Literal, + LiteralType, + Network as _, + PlaintextType, + Register, + TestnetV0, + ToBits as _, + ToBytes as _, + integers::Integer, + }, synthesizer::{Command, Instruction}, }; use snarkvm_synthesizer_program::{CallOperator, CastType, Operand}; +use rand::Rng as _; +use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng}; use std::mem; impl Cursor<'_> { + fn mapping_by_call_operator(&self, operator: &CallOperator) -> Option<&HashMap> { + let (program, name) = match operator { + CallOperator::Locator(locator) => { + (Some(snarkvm_identifier_to_symbol(locator.name())), snarkvm_identifier_to_symbol(locator.resource())) + } + CallOperator::Resource(id) => (None, snarkvm_identifier_to_symbol(id)), + }; + self.lookup_mapping(program, name) + } + fn get_register(&self, reg: Register) -> &Value { let Some(Frame { element: Element::AleoExecution { registers, .. }, .. }) = self.frames.last() else { panic!(); @@ -742,21 +767,108 @@ impl Cursor<'_> { fn step_aleo_command(&mut self, command: Command) -> Result<()> { use Command::*; - match command { - Instruction(instruction) => self.step_aleo_instruction(instruction)?, + + let (value, destination) = match command { + Instruction(instruction) => { + self.step_aleo_instruction(instruction)?; + return Ok(()); + } Await(await_) => { let Value::Future(future) = self.get_register(await_.register().clone()) else { halt_no_span!("attempted to await a non-future"); }; self.contexts.add_future(future.clone()); self.increment_instruction_index(); + return Ok(()); + } + Contains(contains) => { + let mapping = self.mapping_by_call_operator(contains.mapping()).expect("mapping should be present"); + let key = self.operand_value(contains.key()); + let result = Value::Bool(mapping.contains_key(&key)); + self.increment_instruction_index(); + (result, contains.destination().clone()) + } + Get(get) => { + let key = self.operand_value(get.key()); + let value = self.mapping_by_call_operator(get.mapping()).and_then(|mapping| mapping.get(&key)).cloned(); + self.increment_instruction_index(); + + match value { + Some(v) => (v, get.destination().clone()), + None => halt_no_span!("map access failure: {key}"), + } + } + GetOrUse(get_or_use) => { + let key = self.operand_value(get_or_use.key()); + let value = + self.mapping_by_call_operator(get_or_use.mapping()).and_then(|mapping| mapping.get(&key)).cloned(); + + let use_value = value.unwrap_or_else(|| self.operand_value(get_or_use.default())); + self.increment_instruction_index(); + + (use_value, get_or_use.destination().clone()) + } + Remove(remove) => { + let key = self.operand_value(remove.key()); + let mapping_name = snarkvm_identifier_to_symbol(remove.mapping_name()); + let maybe_mapping = self.lookup_mapping_mut(None, mapping_name); + match maybe_mapping { + None => halt_no_span!("no such mapping {mapping_name}"), + Some(mapping) => { + mapping.remove(&key); + } + } + self.increment_instruction_index(); + return Ok(()); + } + Set(set) => { + let key = self.operand_value(set.key()); + let value = self.operand_value(set.value()); + let mapping_name = snarkvm_identifier_to_symbol(set.mapping_name()); + let maybe_mapping = self.lookup_mapping_mut(None, mapping_name); + match maybe_mapping { + None => halt_no_span!("no such mapping {mapping_name}"), + Some(mapping) => { + mapping.insert(key, value); + } + } + self.increment_instruction_index(); + return Ok(()); + } + RandChaCha(rand) => { + // If there are operands, they are additional seeds. + let mut bits = Vec::new(); + for value in rand.operands().iter().map(|op| self.operand_value(op)) { + value.write_bits_le(&mut bits); + } + let field: Field = self.rng.gen(); + field.write_bits_le(&mut bits); + let seed_vec = TestnetV0::hash_bhp1024(&bits)?.to_bytes_le()?; + let mut seed = [0u8; 32]; + seed.copy_from_slice(&seed_vec[..32]); + let mut rng = ChaCha20Rng::from_seed(seed); + let value = match rand.destination_type() { + LiteralType::Address => Value::Address(rng.gen()), + LiteralType::Boolean => Value::Bool(rng.gen()), + LiteralType::Field => Value::Field(rng.gen()), + LiteralType::Group => Value::Group(rng.gen()), + LiteralType::I8 => Value::I8(rng.gen()), + LiteralType::I16 => Value::I16(rng.gen()), + LiteralType::I32 => Value::I32(rng.gen()), + LiteralType::I64 => Value::I64(rng.gen()), + LiteralType::I128 => Value::I128(rng.gen()), + LiteralType::U8 => Value::U8(rng.gen()), + LiteralType::U16 => Value::U16(rng.gen()), + LiteralType::U32 => Value::U32(rng.gen()), + LiteralType::U64 => Value::U64(rng.gen()), + LiteralType::U128 => Value::U128(rng.gen()), + LiteralType::Scalar => Value::Scalar(rng.gen()), + LiteralType::Signature => halt_no_span!("Cannot create a random signature"), + LiteralType::String => halt_no_span!("Cannot create a random string"), + }; + self.increment_instruction_index(); + (value, rand.destination().clone()) } - Contains(_) => todo!(), - Get(_) => todo!(), - GetOrUse(_) => todo!(), - RandChaCha(_) => todo!(), - Remove(_) => todo!(), - Set(_) => todo!(), BranchEq(branch_eq) => { let first = self.operand_value(branch_eq.first()); let second = self.operand_value(branch_eq.second()); @@ -765,6 +877,7 @@ impl Cursor<'_> { } else { self.increment_instruction_index(); } + return Ok(()); } BranchNeq(branch_neq) => { let first = self.operand_value(branch_neq.first()); @@ -774,9 +887,13 @@ impl Cursor<'_> { } else { self.increment_instruction_index(); } + return Ok(()); } - Position(_) => {} - } + Position(_) => return Ok(()), + }; + + self.set_register(destination, value); + Ok(()) }