From 197efd4409588a46ccffda813ec7d2bc26c726be Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Wed, 14 Feb 2024 16:57:19 -0800 Subject: [PATCH 1/3] Address mainnet TODOs --- .../src/stack/finalize_types/initialize.rs | 10 +- synthesizer/program/src/logic/command/get.rs | 179 ++---------------- .../program/src/logic/command/get_or_use.rs | 80 ++------ 3 files changed, 35 insertions(+), 234 deletions(-) diff --git a/synthesizer/process/src/stack/finalize_types/initialize.rs b/synthesizer/process/src/stack/finalize_types/initialize.rs index 25bb0c7ca9..22ffc10616 100644 --- a/synthesizer/process/src/stack/finalize_types/initialize.rs +++ b/synthesizer/process/src/stack/finalize_types/initialize.rs @@ -17,11 +17,11 @@ use crate::RegisterTypes; use synthesizer_program::{ Await, Branch, + CallOperator, CastType, Contains, Get, GetOrUse, - MappingLocator, RandChaCha, Remove, Set, @@ -291,7 +291,7 @@ impl FinalizeTypes { fn check_get(&mut self, stack: &(impl StackMatches + StackProgram), get: &Get) -> Result<()> { // Retrieve the mapping. let mapping = match get.mapping() { - MappingLocator::Locator(locator) => { + CallOperator::Locator(locator) => { // Retrieve the program ID. let program_id = locator.program_id(); // Retrieve the mapping_name. @@ -314,7 +314,7 @@ impl FinalizeTypes { // Retrieve the mapping from the program. external.get_mapping(mapping_name)? } - MappingLocator::Resource(mapping_name) => { + CallOperator::Resource(mapping_name) => { // Ensure the declared mapping in `get` is defined in the current program. if !stack.program().contains_mapping(mapping_name) { bail!("Mapping '{mapping_name}' in '{}' is not defined.", stack.program_id()) @@ -357,7 +357,7 @@ impl FinalizeTypes { ) -> Result<()> { // Retrieve the mapping. let mapping = match get_or_use.mapping() { - MappingLocator::Locator(locator) => { + CallOperator::Locator(locator) => { // Retrieve the program ID. let program_id = locator.program_id(); // Retrieve the mapping_name. @@ -380,7 +380,7 @@ impl FinalizeTypes { // Retrieve the mapping from the program. external.get_mapping(mapping_name)? } - MappingLocator::Resource(mapping_name) => { + CallOperator::Resource(mapping_name) => { // Ensure the declared mapping in `get.or_use` is defined in the current program. if !stack.program().contains_mapping(mapping_name) { bail!("Mapping '{mapping_name}' in '{}' is not defined.", stack.program_id()) diff --git a/synthesizer/program/src/logic/command/get.rs b/synthesizer/program/src/logic/command/get.rs index 84b355e945..5e87eda426 100644 --- a/synthesizer/program/src/logic/command/get.rs +++ b/synthesizer/program/src/logic/command/get.rs @@ -14,122 +14,21 @@ use crate::{ traits::{FinalizeStoreTrait, RegistersLoad, RegistersStore, StackMatches, StackProgram}, + CallOperator, Opcode, Operand, }; use console::{ network::prelude::*, - program::{Identifier, Locator, Register, Value}, + program::{Register, Value}, }; -use std::io::{BufRead, BufReader}; - -/// The operator references a local or external mapping name. -#[derive(Clone, PartialEq, Eq, Hash)] -pub enum MappingLocator { - /// The reference to a non-local mapping name. - Locator(Locator), - /// The reference to a local mapping name. - Resource(Identifier), -} - -impl Parser for MappingLocator { - /// Parses a string into an operator. - #[inline] - fn parse(string: &str) -> ParserResult { - alt(( - map(Locator::parse, |locator| MappingLocator::Locator(locator)), - map(Identifier::parse, |identifier| MappingLocator::Resource(identifier)), - ))(string) - } -} - -impl FromStr for MappingLocator { - type Err = Error; - - /// Parses a string into an operator. - #[inline] - fn from_str(string: &str) -> Result { - match Self::parse(string) { - Ok((remainder, object)) => { - // Ensure the remainder is empty. - ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); - // Return the object. - Ok(object) - } - Err(error) => bail!("Failed to parse string. {error}"), - } - } -} - -impl Debug for MappingLocator { - /// Prints the operator as a string. - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(self, f) - } -} - -impl Display for MappingLocator { - /// Prints the operator to a string. - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - MappingLocator::Locator(locator) => Display::fmt(locator, f), - MappingLocator::Resource(resource) => Display::fmt(resource, f), - } - } -} - -impl FromBytes for MappingLocator { - /// Reads the operation from a buffer. - fn read_le(mut reader: R) -> IoResult { - // Read the version. - let version = u8::read_le(&mut reader)?; - // Ensure the version is valid. - if version != 0 { - return Err(error("Failed to read MappingLocator. Invalid version.")); - } - // Read the variant. - let variant = u8::read_le(&mut reader)?; - // Match the variant. - match variant { - 0 => Ok(MappingLocator::Locator(Locator::read_le(&mut reader)?)), - 1 => Ok(MappingLocator::Resource(Identifier::read_le(&mut reader)?)), - _ => Err(error("Failed to read MappingLocator. Invalid variant.")), - } - } -} - -impl ToBytes for MappingLocator { - /// Writes the operation to a buffer. - fn write_le(&self, mut writer: W) -> IoResult<()> { - match self { - MappingLocator::Locator(locator) => { - // Write the version. - 0u8.write_le(&mut writer)?; - // Write the variant. - 0u8.write_le(&mut writer)?; - // Write the locator. - locator.write_le(&mut writer) - } - MappingLocator::Resource(resource) => { - // Write the version. - 0u8.write_le(&mut writer)?; - // Write the variant. - 1u8.write_le(&mut writer)?; - // Write the resource. - resource.write_le(&mut writer) - } - } - } -} - /// A get command, e.g. `get accounts[r0] into r1;`. /// Gets the value stored at `operand` in `mapping` and stores the result in `destination`. #[derive(Clone)] pub struct Get { /// The mapping. - // TODO (howardwu): For mainnet - Use `CallOperator`, delete the above `MappingLocator`. - mapping: MappingLocator, + mapping: CallOperator, /// The key to access the mapping. key: Operand, /// The destination register. @@ -171,7 +70,7 @@ impl Get { /// Returns the mapping. #[inline] - pub const fn mapping(&self) -> &MappingLocator { + pub const fn mapping(&self) -> &CallOperator { &self.mapping } @@ -199,8 +98,8 @@ impl Get { ) -> Result<()> { // Determine the program ID and mapping name. let (program_id, mapping_name) = match self.mapping { - MappingLocator::Locator(locator) => (*locator.program_id(), *locator.resource()), - MappingLocator::Resource(mapping_name) => (*stack.program_id(), mapping_name), + CallOperator::Locator(locator) => (*locator.program_id(), *locator.resource()), + CallOperator::Resource(mapping_name) => (*stack.program_id(), mapping_name), }; // Ensure the mapping exists in storage. @@ -239,7 +138,7 @@ impl Parser for Get { let (string, _) = Sanitizer::parse_whitespaces(string)?; // Parse the mapping name from the string. - let (string, mapping) = MappingLocator::parse(string)?; + let (string, mapping) = CallOperator::parse(string)?; // Parse the "[" from the string. let (string, _) = tag("[")(string)?; // Parse the whitespace from the string. @@ -308,22 +207,9 @@ impl Display for Get { impl FromBytes for Get { /// Reads the command from a buffer. - fn read_le(reader: R) -> IoResult { - // Peek at the first byte. - // TODO (howardwu): For mainnet - Read a `MappingLocator`. - let mut reader = BufReader::with_capacity(1, reader); - let first_byte = { - let buffer = reader.fill_buf()?; - match buffer.first() { - Some(byte) => *byte, - None => return Err(error("Failed to read `get`. Expected byte.")), - } - }; - // If the first byte is zero, then read a `MappingLocator`, otherwise read an `Identifier`. - let mapping = match first_byte { - 0u8 => MappingLocator::read_le(&mut reader)?, - _ => MappingLocator::Resource(Identifier::read_le(&mut reader)?), - }; + fn read_le(mut reader: R) -> IoResult { + // Read the mapping name. + let mapping = CallOperator::read_le(&mut reader)?; // Read the key operand. let key = Operand::read_le(&mut reader)?; // Read the destination register. @@ -334,14 +220,10 @@ impl FromBytes for Get { } impl ToBytes for Get { - /// Writes the operation to a buffer. + /// Writes the command to a buffer. fn write_le(&self, mut writer: W) -> IoResult<()> { // Write the mapping name. - // TODO (howardwu): For mainnet - Write `self.mapping` directly, instead of matching on the identifier case. - match &self.mapping { - MappingLocator::Locator(_) => self.mapping.write_le(&mut writer)?, - MappingLocator::Resource(identifier) => identifier.write_le(&mut writer)?, - } + self.mapping.write_le(&mut writer)?; // Write the key operand. self.key.write_le(&mut writer)?; // Write the destination register. @@ -356,38 +238,18 @@ mod tests { type CurrentNetwork = MainnetV0; - struct OldGet { - mapping: Identifier, - key: Operand, - destination: Register, - } - - impl ToBytes for OldGet { - fn write_le(&self, mut writer: W) -> IoResult<()> - where - Self: Sized, - { - // Write the mapping name. - self.mapping.write_le(&mut writer)?; - // Write the key operand. - self.key.write_le(&mut writer)?; - // Write the destination register. - self.destination.write_le(&mut writer) - } - } - #[test] fn test_parse() { let (string, get) = Get::::parse("get account[r0] into r1;").unwrap(); assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); - assert_eq!(get.mapping, MappingLocator::from_str("account").unwrap()); + assert_eq!(get.mapping, CallOperator::from_str("account").unwrap()); assert_eq!(get.operands().len(), 1, "The number of operands is incorrect"); assert_eq!(get.key, Operand::Register(Register::Locator(0)), "The first operand is incorrect"); assert_eq!(get.destination, Register::Locator(1), "The second operand is incorrect"); let (string, get) = Get::::parse("get token.aleo/balances[r0] into r1;").unwrap(); assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); - assert_eq!(get.mapping, MappingLocator::from_str("token.aleo/balances").unwrap()); + assert_eq!(get.mapping, CallOperator::from_str("token.aleo/balances").unwrap()); assert_eq!(get.operands().len(), 1, "The number of operands is incorrect"); assert_eq!(get.key, Operand::Register(Register::Locator(0)), "The first operand is incorrect"); assert_eq!(get.destination, Register::Locator(1), "The second operand is incorrect"); @@ -397,18 +259,9 @@ mod tests { fn test_from_bytes() { let (string, get) = Get::::parse("get account[r0] into r1;").unwrap(); assert!(string.is_empty()); - - let old_get = OldGet:: { - mapping: Identifier::from_str("account").unwrap(), - key: Operand::Register(Register::Locator(0)), - destination: Register::Locator(1), - }; - let get_bytes = get.to_bytes_le().unwrap(); - let old_get_bytes = old_get.to_bytes_le().unwrap(); - let first = Get::::from_bytes_le(&get_bytes[..]).unwrap(); - let second = Get::::from_bytes_le(&old_get_bytes[..]).unwrap(); - assert_eq!(first, second); + let result = Get::::from_bytes_le(&get_bytes[..]); + assert!(result.is_ok()) } } diff --git a/synthesizer/program/src/logic/command/get_or_use.rs b/synthesizer/program/src/logic/command/get_or_use.rs index a4ef7cc080..c86d56f0bd 100644 --- a/synthesizer/program/src/logic/command/get_or_use.rs +++ b/synthesizer/program/src/logic/command/get_or_use.rs @@ -14,7 +14,7 @@ use crate::{ traits::{FinalizeStoreTrait, RegistersLoad, RegistersStore, StackMatches, StackProgram}, - MappingLocator, + CallOperator, Opcode, Operand, }; @@ -23,17 +23,13 @@ use console::{ program::{Register, Value}, }; -use console::program::Identifier; -use std::io::{BufRead, BufReader}; - /// A get command that uses the provided default in case of failure, e.g. `get.or_use accounts[r0] r1 into r2;`. /// Gets the value stored at `operand` in `mapping` and stores the result in `destination`. /// If the key is not present, `default` is stored in `destination`. #[derive(Clone)] pub struct GetOrUse { /// The mapping. - // TODO (howardwu): For mainnet - Use `CallOperator`, delete the above `MappingLocator`. - mapping: MappingLocator, + mapping: CallOperator, /// The key to access the mapping. key: Operand, /// The default value. @@ -79,7 +75,7 @@ impl GetOrUse { /// Returns the mapping. #[inline] - pub const fn mapping(&self) -> &MappingLocator { + pub const fn mapping(&self) -> &CallOperator { &self.mapping } @@ -113,8 +109,8 @@ impl GetOrUse { ) -> Result<()> { // Determine the program ID and mapping name. let (program_id, mapping_name) = match self.mapping { - MappingLocator::Locator(locator) => (*locator.program_id(), *locator.resource()), - MappingLocator::Resource(mapping_name) => (*stack.program_id(), mapping_name), + CallOperator::Locator(locator) => (*locator.program_id(), *locator.resource()), + CallOperator::Resource(mapping_name) => (*stack.program_id(), mapping_name), }; // Ensure the mapping exists in storage. @@ -154,7 +150,7 @@ impl Parser for GetOrUse { let (string, _) = Sanitizer::parse_whitespaces(string)?; // Parse the mapping name from the string. - let (string, mapping) = MappingLocator::parse(string)?; + let (string, mapping) = CallOperator::parse(string)?; // Parse the "[" from the string. let (string, _) = tag("[")(string)?; // Parse the whitespace from the string. @@ -227,22 +223,9 @@ impl Display for GetOrUse { impl FromBytes for GetOrUse { /// Reads the command from a buffer. - fn read_le(reader: R) -> IoResult { - // Peek at the first byte. - // TODO (howardwu): For mainnet - Read a `MappingLocator`. - let mut reader = BufReader::with_capacity(1, reader); - let first_byte = { - let buffer = reader.fill_buf()?; - match buffer.first() { - Some(byte) => *byte, - None => return Err(error("Failed to read `get.or_use`. Expected byte.")), - } - }; - // If the first byte is zero, then read a `MappingLocator`, otherwise read an `Identifier`. - let mapping = match first_byte { - 0u8 => MappingLocator::read_le(&mut reader)?, - _ => MappingLocator::Resource(Identifier::read_le(&mut reader)?), - }; + fn read_le(mut reader: R) -> IoResult { + // Read the mapping name. + let mapping = CallOperator::read_le(&mut reader)?; // Read the key operand. let key = Operand::read_le(&mut reader)?; // Read the default value. @@ -258,11 +241,7 @@ impl ToBytes for GetOrUse { /// Writes the operation to a buffer. fn write_le(&self, mut writer: W) -> IoResult<()> { // Write the mapping name. - // TODO (howardwu): For mainnet - Write the `self.mapping` directly, instead of matching on the identifier case. - match &self.mapping { - MappingLocator::Locator(_) => self.mapping.write_le(&mut writer)?, - MappingLocator::Resource(identifier) => identifier.write_le(&mut writer)?, - } + self.mapping.write_le(&mut writer)?; // Write the key operand. self.key.write_le(&mut writer)?; // Write the default value. @@ -279,31 +258,11 @@ mod tests { type CurrentNetwork = MainnetV0; - pub struct OldGetOrUse { - pub mapping: Identifier, - pub key: Operand, - pub default: Operand, - pub destination: Register, - } - - impl ToBytes for OldGetOrUse { - fn write_le(&self, mut writer: W) -> IoResult<()> { - // Write the mapping name. - self.mapping.write_le(&mut writer)?; - // Write the key operand. - self.key.write_le(&mut writer)?; - // Write the default value. - self.default.write_le(&mut writer)?; - // Write the destination register. - self.destination.write_le(&mut writer) - } - } - #[test] fn test_parse() { let (string, get_or_use) = GetOrUse::::parse("get.or_use account[r0] r1 into r2;").unwrap(); assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); - assert_eq!(get_or_use.mapping, MappingLocator::from_str("account").unwrap()); + assert_eq!(get_or_use.mapping, CallOperator::from_str("account").unwrap()); assert_eq!(get_or_use.operands().len(), 2, "The number of operands is incorrect"); assert_eq!(get_or_use.key, Operand::Register(Register::Locator(0)), "The first operand is incorrect"); assert_eq!(get_or_use.default, Operand::Register(Register::Locator(1)), "The second operand is incorrect"); @@ -312,7 +271,7 @@ mod tests { let (string, get_or_use) = GetOrUse::::parse("get.or_use token.aleo/balances[r0] r1 into r2;").unwrap(); assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); - assert_eq!(get_or_use.mapping, MappingLocator::from_str("token.aleo/balances").unwrap()); + assert_eq!(get_or_use.mapping, CallOperator::from_str("token.aleo/balances").unwrap()); assert_eq!(get_or_use.operands().len(), 2, "The number of operands is incorrect"); assert_eq!(get_or_use.key, Operand::Register(Register::Locator(0)), "The first operand is incorrect"); assert_eq!(get_or_use.default, Operand::Register(Register::Locator(1)), "The second operand is incorrect"); @@ -323,19 +282,8 @@ mod tests { fn test_from_bytes() { let (string, get_or_use) = GetOrUse::::parse("get.or_use account[r0] r1 into r2;").unwrap(); assert!(string.is_empty()); - - let old_get_or_use = OldGetOrUse:: { - mapping: Identifier::from_str("account").unwrap(), - key: Operand::Register(Register::Locator(0)), - default: Operand::Register(Register::Locator(1)), - destination: Register::Locator(2), - }; - let get_or_use_bytes = get_or_use.to_bytes_le().unwrap(); - let old_get_or_use_bytes = old_get_or_use.to_bytes_le().unwrap(); - - let first = GetOrUse::::from_bytes_le(&get_or_use_bytes[..]).unwrap(); - let second = GetOrUse::::from_bytes_le(&old_get_or_use_bytes[..]).unwrap(); - assert_eq!(first, second); + let result = GetOrUse::::from_bytes_le(&get_or_use_bytes[..]); + assert!(result.is_ok()); } } From f2bcc0efdda256719ffc528898c4c9543205e6b2 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Wed, 14 Feb 2024 17:07:04 -0800 Subject: [PATCH 2/3] Use CallOperator for Contains opcode --- .../src/stack/finalize_types/initialize.rs | 45 +++++++++++++++---- .../program/src/logic/command/contains.rs | 44 +++++++++++++----- synthesizer/program/src/logic/command/get.rs | 5 +-- .../program/src/logic/command/get_or_use.rs | 4 +- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/synthesizer/process/src/stack/finalize_types/initialize.rs b/synthesizer/process/src/stack/finalize_types/initialize.rs index 22ffc10616..a87c5b50b1 100644 --- a/synthesizer/process/src/stack/finalize_types/initialize.rs +++ b/synthesizer/process/src/stack/finalize_types/initialize.rs @@ -174,7 +174,7 @@ impl FinalizeTypes { match command { Command::Instruction(instruction) => self.check_instruction(stack, finalize.name(), instruction)?, Command::Await(await_) => self.check_await(stack, await_)?, - Command::Contains(contains) => self.check_contains(stack, finalize.name(), contains)?, + Command::Contains(contains) => self.check_contains(stack, contains)?, Command::Get(get) => self.check_get(stack, get)?, Command::GetOrUse(get_or_use) => self.check_get_or_use(stack, get_or_use)?, Command::RandChaCha(rand_chacha) => self.check_rand_chacha(stack, finalize.name(), rand_chacha)?, @@ -252,16 +252,43 @@ impl FinalizeTypes { fn check_contains( &mut self, stack: &(impl StackMatches + StackProgram), - finalize_name: &Identifier, contains: &Contains, ) -> Result<()> { - // Ensure the declared mapping in `contains` is defined in the program. - if !stack.program().contains_mapping(contains.mapping_name()) { - bail!("Mapping '{}' in '{}/{finalize_name}' is not defined.", contains.mapping_name(), stack.program_id()) - } - // Retrieve the mapping from the program. - // Note that the unwrap is safe, as we have already checked the mapping exists. - let mapping = stack.program().get_mapping(contains.mapping_name()).unwrap(); + // Retrieve the mapping. + let mapping = match contains.mapping() { + CallOperator::Locator(locator) => { + // Retrieve the program ID. + let program_id = locator.program_id(); + // Retrieve the mapping_name. + let mapping_name = locator.resource(); + + // Ensure the locator does not reference the current program. + if stack.program_id() == program_id { + bail!("Locator '{locator}' does not reference an external mapping."); + } + // Ensure the current program contains an import for this external program. + if !stack.program().imports().keys().contains(program_id) { + bail!("External program '{program_id}' is not imported by '{}'.", stack.program_id()); + } + // Retrieve the program. + let external = stack.get_external_program(program_id)?; + // Ensure the mapping exists in the program. + if !external.contains_mapping(mapping_name) { + bail!("Mapping '{mapping_name}' in '{program_id}' is not defined.") + } + // Retrieve the mapping from the program. + external.get_mapping(mapping_name)? + } + CallOperator::Resource(mapping_name) => { + // Ensure the declared mapping in `contains` is defined in the current program. + if !stack.program().contains_mapping(mapping_name) { + bail!("Mapping '{mapping_name}' in '{}' is not defined.", stack.program_id()) + } + // Retrieve the mapping from the program. + stack.program().get_mapping(mapping_name)? + } + }; + // Get the mapping key type. let mapping_key_type = mapping.key().plaintext_type(); // Retrieve the register type of the key. diff --git a/synthesizer/program/src/logic/command/contains.rs b/synthesizer/program/src/logic/command/contains.rs index a3b0479c2e..fca79405d2 100644 --- a/synthesizer/program/src/logic/command/contains.rs +++ b/synthesizer/program/src/logic/command/contains.rs @@ -14,12 +14,13 @@ use crate::{ traits::{FinalizeStoreTrait, RegistersLoad, RegistersStore, StackMatches, StackProgram}, + CallOperator, Opcode, Operand, }; use console::{ network::prelude::*, - program::{Identifier, Literal, Register, Value}, + program::{Literal, Register, Value}, types::Boolean, }; @@ -28,7 +29,7 @@ use console::{ #[derive(Clone, PartialEq, Eq, Hash)] pub struct Contains { /// The mapping name. - mapping: Identifier, + mapping: CallOperator, /// The key to access the mapping. key: Operand, /// The destination register. @@ -48,9 +49,9 @@ impl Contains { vec![self.key.clone()] } - /// Returns the mapping name. + /// Returns the mapping. #[inline] - pub const fn mapping_name(&self) -> &Identifier { + pub const fn mapping(&self) -> &CallOperator { &self.mapping } @@ -76,16 +77,22 @@ impl Contains { store: &impl FinalizeStoreTrait, registers: &mut (impl RegistersLoad + RegistersStore), ) -> Result<()> { + // Determine the program ID and mapping name. + let (program_id, mapping_name) = match self.mapping { + CallOperator::Locator(locator) => (*locator.program_id(), *locator.resource()), + CallOperator::Resource(mapping_name) => (*stack.program_id(), mapping_name), + }; + // Ensure the mapping exists in storage. - if !store.contains_mapping_confirmed(stack.program_id(), &self.mapping)? { - bail!("Mapping '{}/{}' does not exist in storage", stack.program_id(), self.mapping); + if !store.contains_mapping_confirmed(&program_id, &mapping_name)? { + bail!("Mapping '{program_id}/{mapping_name}' does not exist in storage"); } // Load the operand as a plaintext. let key = registers.load_plaintext(stack, &self.key)?; // Determine if the key exists in the mapping. - let contains_key = store.contains_key_speculative(*stack.program_id(), self.mapping, &key)?; + let contains_key = store.contains_key_speculative(program_id, mapping_name, &key)?; // Assign the value to the destination register. registers.store(stack, &self.destination, Value::from(Literal::Boolean(Boolean::new(contains_key))))?; @@ -106,7 +113,7 @@ impl Parser for Contains { let (string, _) = Sanitizer::parse_whitespaces(string)?; // Parse the mapping name from the string. - let (string, mapping) = Identifier::parse(string)?; + let (string, mapping) = CallOperator::parse(string)?; // Parse the "[" from the string. let (string, _) = tag("[")(string)?; // Parse the whitespace from the string. @@ -177,7 +184,7 @@ impl FromBytes for Contains { /// Reads the command from a buffer. fn read_le(mut reader: R) -> IoResult { // Read the mapping name. - let mapping = Identifier::read_le(&mut reader)?; + let mapping = CallOperator::read_le(&mut reader)?; // Read the key operand. let key = Operand::read_le(&mut reader)?; // Read the destination register. @@ -210,9 +217,26 @@ mod tests { fn test_parse() { let (string, contains) = Contains::::parse("contains account[r0] into r1;").unwrap(); assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); - assert_eq!(contains.mapping, Identifier::from_str("account").unwrap()); + assert_eq!(contains.mapping, CallOperator::from_str("account").unwrap()); + assert_eq!(contains.operands().len(), 1, "The number of operands is incorrect"); + assert_eq!(contains.key, Operand::Register(Register::Locator(0)), "The first operand is incorrect"); + assert_eq!(contains.destination, Register::Locator(1), "The second operand is incorrect"); + + let (string, contains) = + Contains::::parse("contains credits.aleo/account[r0] into r1;").unwrap(); + assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); + assert_eq!(contains.mapping, CallOperator::from_str("credits.aleo/account").unwrap()); assert_eq!(contains.operands().len(), 1, "The number of operands is incorrect"); assert_eq!(contains.key, Operand::Register(Register::Locator(0)), "The first operand is incorrect"); assert_eq!(contains.destination, Register::Locator(1), "The second operand is incorrect"); } + + #[test] + fn test_from_bytes() { + let (string, contains) = Contains::::parse("contains account[r0] into r1;").unwrap(); + assert!(string.is_empty()); + let bytes_le = contains.to_bytes_le().unwrap(); + let result = Contains::::from_bytes_le(&bytes_le[..]); + assert!(result.is_ok()) + } } diff --git a/synthesizer/program/src/logic/command/get.rs b/synthesizer/program/src/logic/command/get.rs index 5e87eda426..2526ed7e70 100644 --- a/synthesizer/program/src/logic/command/get.rs +++ b/synthesizer/program/src/logic/command/get.rs @@ -259,9 +259,8 @@ mod tests { fn test_from_bytes() { let (string, get) = Get::::parse("get account[r0] into r1;").unwrap(); assert!(string.is_empty()); - let get_bytes = get.to_bytes_le().unwrap(); - - let result = Get::::from_bytes_le(&get_bytes[..]); + let bytes_le = get.to_bytes_le().unwrap(); + let result = Get::::from_bytes_le(&bytes_le[..]); assert!(result.is_ok()) } } diff --git a/synthesizer/program/src/logic/command/get_or_use.rs b/synthesizer/program/src/logic/command/get_or_use.rs index c86d56f0bd..940694b24d 100644 --- a/synthesizer/program/src/logic/command/get_or_use.rs +++ b/synthesizer/program/src/logic/command/get_or_use.rs @@ -282,8 +282,8 @@ mod tests { fn test_from_bytes() { let (string, get_or_use) = GetOrUse::::parse("get.or_use account[r0] r1 into r2;").unwrap(); assert!(string.is_empty()); - let get_or_use_bytes = get_or_use.to_bytes_le().unwrap(); - let result = GetOrUse::::from_bytes_le(&get_or_use_bytes[..]); + let bytes_le = get_or_use.to_bytes_le().unwrap(); + let result = GetOrUse::::from_bytes_le(&bytes_le[..]); assert!(result.is_ok()); } } From 874c691ffc45a66de87caea41fa4be40bb8178aa Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu <23022326+d0cd@users.noreply.github.com> Date: Wed, 14 Feb 2024 17:22:37 -0800 Subject: [PATCH 3/3] Add tests --- .../read_external_mapping.out | 54 +++++++++++++------ .../read_external_mapping.aleo | 16 ++++++ 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/read_external_mapping.out b/synthesizer/tests/expectations/vm/execute_and_finalize/read_external_mapping.out index 0844e497c6..d0c4d8fdc3 100644 --- a/synthesizer/tests/expectations/vm/execute_and_finalize/read_external_mapping.out +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/read_external_mapping.out @@ -4,70 +4,92 @@ outputs: execute: relay.aleo/send: outputs: - - '{"type":"record","id":"5505341694097720023583674648027312667621444458172921945164834002648638744768field","checksum":"4170712463954366904268628656227022271867279479485549214633981747772705648157field","value":"record1qyqsp358e054av498aavwel28wr36tg0ay27k4fc539ffmwz2nddl8gqqyzxgct5vy3sqqspqpfgwnp3rnwprhd2q3h8gmxcnldlczrvszade4vzxlu7dmfeg6j3rd8mwuzysqtgl6603ey2zzry8hjwmn3pt3twclpkkvssc4l4jzsvd6lxar"}' - - '{"type":"future","id":"5717025369252791268307518245044265589645500853607154349985983366013693165029field","value":"{\n program_id: relay.aleo,\n function_name: send,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' + - '{"type":"record","id":"3516005588956842618039325657183144336836835112376772770027534922591833057274field","checksum":"6210818386171269355708023008843251667562533143005976215346548674400037301137field","value":"record1qyqsqt7kuqj4ztmngchze9wlxjshk58pr52cvhqcnrsg6n0agzqtcsctqyzxgct5vy3sqqspqpr5mmj65yd4wfs8fmlmcuy6f5mgufdd7rvxmcq3ttxtgnuca3jqdrzp5glsjvfuv5wn57t5ljq0cc2q730335nv6gh2x3sjdnsjk4cpah854l"}' + - '{"type":"future","id":"3361027566039000326532636996547384998281625372954756951941108923279619886587field","value":"{\n program_id: relay.aleo,\n function_name: send,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' speculate: the execution was rejected add_next_block: succeeded. - verified: true execute: relay.aleo/send_without_check: outputs: - - '{"type":"record","id":"4755207731349921544198839760105069860415948248486655350742993041864954064196field","checksum":"7848435433502532569425287419063381736913355859517668180377091558079541996646field","value":"record1qyqsp83ncqrtrev57v03h3j8qcysfgef256zh7pmh7zgj83h6g7tfkq0qyzxgct5vy3sqqspqzx4ww05zz3grf6hxgr46csu2vmzr2lgq0f48kxp4j383l68ufqsq45f8wqk6jxfnkm6v92cq48xea0tfrg0fwwr249m95t4eka6jkgv0c5y7k"}' - - '{"type":"future","id":"7550940621112069147305499283447693470949248949646948758584545929055098614021field","value":"{\n program_id: relay.aleo,\n function_name: send_without_check,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' + - '{"type":"record","id":"4318016682601964951941075964816657999182148443418937820958519250759514688744field","checksum":"710696789209865634545334124645897103218620227147717749173439218439756518633field","value":"record1qyqsp5e73czvz9kvsnku845h0v4lx9ddxhhfp5d6u69us96r33upwnczqyzxgct5vy3sqqspqpc74m2j7e8ftk3gnj8qs4pvt96rsjdgthl9w9ej0cwf9jgyvfmqtyd66x9m2qjxjfes26ukjnm6hzuzch23syjketdnw5gdlrurwec23u3hv9"}' + - '{"type":"future","id":"2493314668767081995438573059026908296255004119285023474956612413303656492322field","value":"{\n program_id: relay.aleo,\n function_name: send_without_check,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' speculate: the execution was accepted add_next_block: succeeded. +- verified: true + execute: + relay.aleo/check_has_registered: + outputs: + - '{"type":"future","id":"5798673214905040069582797944224228205081350391492709789594919833316883071861field","value":"{\n program_id: relay.aleo,\n function_name: check_has_registered,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' + speculate: the execution was rejected + add_next_block: succeeded. - verified: true execute: registry.aleo/register: outputs: - - '{"type":"future","id":"420928543522275050479077069598359906893359132913160778313607215088435256404field","value":"{\n program_id: registry.aleo,\n function_name: register,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' + - '{"type":"future","id":"8039731813254390280133349610037168001950148597333933961448833324938980566665field","value":"{\n program_id: registry.aleo,\n function_name: register,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' + speculate: the execution was accepted + add_next_block: succeeded. +- verified: true + execute: + relay.aleo/check_has_registered: + outputs: + - '{"type":"future","id":"2049729709084378408208936775159884510094821976911931753152344792750331977221field","value":"{\n program_id: relay.aleo,\n function_name: check_has_registered,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' speculate: the execution was accepted add_next_block: succeeded. - verified: true execute: relay.aleo/send: outputs: - - '{"type":"record","id":"2277384653342632398532359071690090462344215994043547853708800775056671259572field","checksum":"3071210942562837171924171313096615835242397071199450951002063969440885822680field","value":"record1qyqspfwaru0f2lj0s2k6p9jfmmkzyvkzl5qpagt00edyuf9qn3gnu5g9qyzxgct5vy3sqqspqrncgctd3wfmz2ggx0v7l5cggxxad49wcmtlyrjnk8fqulmkg3h3rleuqh8nmwn5d9z8cpf6z75sy880xenua6hu9wk6ptzwh9vnzps3l7743a"}' - - '{"type":"future","id":"7335072283454266955486193272021538348385359506102454702232503952941871822416field","value":"{\n program_id: relay.aleo,\n function_name: send,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' + - '{"type":"record","id":"3616683813988642347503060622912740756389352290494010006842210904168685917153field","checksum":"6191854693070448539885194715256244372853317530758618643648740000978270052149field","value":"record1qyqsqmul3w95f6fvpkptv0rn5m4ta2xktswvv58fc8zeach0gdyaq9stqyzxgct5vy3sqqspqz7hj482yakh4nujgju4st0d5wr9l2ltyhlc7hm2h67lfty9kauqd37uafwtwkanjgqnxxkek5ar4x4rtmqcw7l4tc2jy2am4k5q6zc9pj3yfl"}' + - '{"type":"future","id":"5636131129483545232301025738488486446822977545474078636366853933206498306924field","value":"{\n program_id: relay.aleo,\n function_name: send,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' speculate: the execution was accepted add_next_block: succeeded. - verified: true execute: registry.aleo/unregister: outputs: - - '{"type":"future","id":"679464137653274742839187887301618622489786113106422850487639713737535385053field","value":"{\n program_id: registry.aleo,\n function_name: unregister,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' + - '{"type":"future","id":"5277738172931387381884079014823049888247511234602036315442583090239139710831field","value":"{\n program_id: registry.aleo,\n function_name: unregister,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' speculate: the execution was accepted add_next_block: succeeded. - verified: true execute: relay.aleo/send: outputs: - - '{"type":"record","id":"6497977440830787207175874226764101265608813002804421333613230199582364410758field","checksum":"319323911748946858530605909565888788506340329996151513367076865761846915611field","value":"record1qyqsqnajqear5neee3l8fykp4vcq35sgwreyz7hz3png3cn2yyljdscfqyzxgct5vy3sqqspqzu6lezptk9xjpx35xdrv5tztz0v9qs9xx803pyqury2j47x2d5seymhf3xa2wefz7mkas7r7m3uf4kte7fdwm00ral53q2mhclx95qte8mpvc"}' - - '{"type":"future","id":"884722454089253418562221490807303959161101695210458740892906535295075161672field","value":"{\n program_id: relay.aleo,\n function_name: send,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' + - '{"type":"record","id":"7999943092608705210868690426378362644128080928438492993595543488896669041130field","checksum":"7727223916356059324700805676432800956308622947890454711018128366728019654812field","value":"record1qyqsp7sfe5eyrww9rsgzmw2yy7skjj82k47yel4ly7jqwqfem70n58qzqyzxgct5vy3sqqspqqrtcn7h3gpj9ususfcv7ctsqzanatgfx5hlvpfd23vt4c85e8zse9h8jxu89yk6thrcf0gcj8e7ttys4gsftg0han56zmklgte5j3grhzqfe2"}' + - '{"type":"future","id":"3543900037397003385324398400449886361329465057481632344369439873330044026217field","value":"{\n program_id: relay.aleo,\n function_name: send,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm\n ]\n}"}' speculate: the execution was rejected add_next_block: succeeded. additional: - child_outputs: credits.aleo/fee_public: outputs: - - '{"type":"future","id":"7648175304675096026780640150249050430126313932796261601585627346676503665056field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12331u64\n ]\n}"}' + - '{"type":"future","id":"3817926103996179346739819443311299842008633349695169924818855439505376699375field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12331u64\n ]\n}"}' +- child_outputs: + credits.aleo/fee_public: + outputs: + - '{"type":"future","id":"8327655085364264976444922469539260203640150056566362427811635889033582688436field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12359u64\n ]\n}"}' +- child_outputs: + credits.aleo/fee_public: + outputs: + - '{"type":"future","id":"4615274813319040360881215398364008209916436742385780192081555194654152991496field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12149u64\n ]\n}"}' - child_outputs: credits.aleo/fee_public: outputs: - - '{"type":"future","id":"2705483676500556524709771070827454100315478149315997882559815259752103335543field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12359u64\n ]\n}"}' + - '{"type":"future","id":"5159959314205108668289382247670650675337509845717320124088252081414795457358field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm,\n 14542u64\n ]\n}"}' - child_outputs: credits.aleo/fee_public: outputs: - - '{"type":"future","id":"1411848222023701190996666942616875099282931632258684196395264413190693640893field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm,\n 14542u64\n ]\n}"}' + - '{"type":"future","id":"7995304610765056429975755609756321908929481317797093337208614102489214121861field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12149u64\n ]\n}"}' - child_outputs: credits.aleo/fee_public: outputs: - - '{"type":"future","id":"1868190452431317368813291334581792128122726398918592355342406544035130142983field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12331u64\n ]\n}"}' + - '{"type":"future","id":"762656111160391091571049618548260391019934079060035723647171673336501373194field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12331u64\n ]\n}"}' - child_outputs: credits.aleo/fee_public: outputs: - - '{"type":"future","id":"4477898748688807061769744441075637584405202918505613760790829764406622025408field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm,\n 14546u64\n ]\n}"}' + - '{"type":"future","id":"2724237130950948809267129985974739498797269253195516460569067499347368422109field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm,\n 14546u64\n ]\n}"}' - child_outputs: credits.aleo/fee_public: outputs: - - '{"type":"future","id":"1737368985169748291589889371295386187060392770099481900284782778606372269731field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12331u64\n ]\n}"}' + - '{"type":"future","id":"2350204279608409472618229594826772186444280524286679998918235180118142717669field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1xe2fps8f9xpdas2q0fqy22uraenk84tvvzetrsyxgnwy6445h59s6wv78x,\n 12331u64\n ]\n}"}' diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/read_external_mapping.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/read_external_mapping.aleo index 20ad427064..0dfdf9e79f 100644 --- a/synthesizer/tests/tests/vm/execute_and_finalize/read_external_mapping.aleo +++ b/synthesizer/tests/tests/vm/execute_and_finalize/read_external_mapping.aleo @@ -9,10 +9,16 @@ cases: - program: relay.aleo function: send_without_check inputs: [aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm, 0u8] + - program: relay.aleo + function: check_has_registered + inputs: [aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm] - program: registry.aleo function: register inputs: [] private_key: APrivateKey1zkpABon5degxuW8JnBniSXgN1C4eAGKfDH8qRPZe1geHpWp + - program: relay.aleo + function: check_has_registered + inputs: [aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm] - program: relay.aleo function: send inputs: [aleo1f6eg623knp66cwx0926w3plgdgzcmfpgyrzgnjz90mucgs3z7s9qls4upm, 1u8] @@ -57,6 +63,16 @@ record message: owner as address.private; data as u8.private; +function check_has_registered: + input r0 as address.public; + async check_has_registered r0 into r1; + output r1 as relay.aleo/check_has_registered.future; + +finalize check_has_registered: + input r0 as address.public; + contains registry.aleo/users[r0] into r1; + assert.eq r1 true; + function send: input r0 as address.public; input r1 as u8.public;