Skip to content

Commit

Permalink
Merge pull request #2355 from AleoHQ/cleanup/mapping-op-ids
Browse files Browse the repository at this point in the history
[Cleanup] Address TODOs for `Command` parsers and serializers.
  • Loading branch information
howardwu authored Feb 20, 2024
2 parents f262864 + 874c691 commit b0cf93b
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 272 deletions.
55 changes: 41 additions & 14 deletions synthesizer/process/src/stack/finalize_types/initialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ use crate::RegisterTypes;
use synthesizer_program::{
Await,
Branch,
CallOperator,
CastType,
Contains,
Get,
GetOrUse,
MappingLocator,
RandChaCha,
Remove,
Set,
Expand Down Expand Up @@ -174,7 +174,7 @@ impl<N: Network> FinalizeTypes<N> {
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)?,
Expand Down Expand Up @@ -252,16 +252,43 @@ impl<N: Network> FinalizeTypes<N> {
fn check_contains(
&mut self,
stack: &(impl StackMatches<N> + StackProgram<N>),
finalize_name: &Identifier<N>,
contains: &Contains<N>,
) -> 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.
Expand Down Expand Up @@ -291,7 +318,7 @@ impl<N: Network> FinalizeTypes<N> {
fn check_get(&mut self, stack: &(impl StackMatches<N> + StackProgram<N>), get: &Get<N>) -> 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.
Expand All @@ -314,7 +341,7 @@ impl<N: Network> FinalizeTypes<N> {
// 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())
Expand Down Expand Up @@ -357,7 +384,7 @@ impl<N: Network> FinalizeTypes<N> {
) -> 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.
Expand All @@ -380,7 +407,7 @@ impl<N: Network> FinalizeTypes<N> {
// 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())
Expand Down
44 changes: 34 additions & 10 deletions synthesizer/program/src/logic/command/contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand All @@ -28,7 +29,7 @@ use console::{
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Contains<N: Network> {
/// The mapping name.
mapping: Identifier<N>,
mapping: CallOperator<N>,
/// The key to access the mapping.
key: Operand<N>,
/// The destination register.
Expand All @@ -48,9 +49,9 @@ impl<N: Network> Contains<N> {
vec![self.key.clone()]
}

/// Returns the mapping name.
/// Returns the mapping.
#[inline]
pub const fn mapping_name(&self) -> &Identifier<N> {
pub const fn mapping(&self) -> &CallOperator<N> {
&self.mapping
}

Expand All @@ -76,16 +77,22 @@ impl<N: Network> Contains<N> {
store: &impl FinalizeStoreTrait<N>,
registers: &mut (impl RegistersLoad<N> + RegistersStore<N>),
) -> 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))))?;
Expand All @@ -106,7 +113,7 @@ impl<N: Network> Parser for Contains<N> {
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.
Expand Down Expand Up @@ -177,7 +184,7 @@ impl<N: Network> FromBytes for Contains<N> {
/// Reads the command from a buffer.
fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
// 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.
Expand Down Expand Up @@ -210,9 +217,26 @@ mod tests {
fn test_parse() {
let (string, contains) = Contains::<CurrentNetwork>::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::<CurrentNetwork>::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::<CurrentNetwork>::parse("contains account[r0] into r1;").unwrap();
assert!(string.is_empty());
let bytes_le = contains.to_bytes_le().unwrap();
let result = Contains::<CurrentNetwork>::from_bytes_le(&bytes_le[..]);
assert!(result.is_ok())
}
}
Loading

0 comments on commit b0cf93b

Please sign in to comment.