snarkvm_synthesizer_program/logic/command/
set.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::{
17    FinalizeOperation,
18    Opcode,
19    Operand,
20    traits::{FinalizeStoreTrait, RegistersLoad, StackMatches, StackProgram},
21};
22use console::{
23    network::prelude::*,
24    program::{Identifier, Value},
25};
26
27/// A set command, e.g. `set r1 into mapping[r0];`
28/// Sets the `key` entry as `value` in `mapping`.
29#[derive(Clone, PartialEq, Eq, Hash)]
30pub struct Set<N: Network> {
31    /// The mapping name.
32    mapping: Identifier<N>,
33    /// The key to access the mapping.
34    key: Operand<N>,
35    /// The value to be set.
36    value: Operand<N>,
37}
38
39impl<N: Network> Set<N> {
40    /// Returns the opcode.
41    #[inline]
42    pub const fn opcode() -> Opcode {
43        Opcode::Command("set")
44    }
45
46    /// Returns the operands in the operation.
47    #[inline]
48    pub fn operands(&self) -> Vec<Operand<N>> {
49        vec![self.value.clone(), self.key.clone()]
50    }
51
52    /// Returns the mapping name.
53    #[inline]
54    pub const fn mapping_name(&self) -> &Identifier<N> {
55        &self.mapping
56    }
57
58    /// Returns the operand containing the key.
59    #[inline]
60    pub const fn key(&self) -> &Operand<N> {
61        &self.key
62    }
63
64    /// Returns the operand containing the value.
65    #[inline]
66    pub const fn value(&self) -> &Operand<N> {
67        &self.value
68    }
69}
70
71impl<N: Network> Set<N> {
72    /// Finalizes the command.
73    #[inline]
74    pub fn finalize(
75        &self,
76        stack: &(impl StackMatches<N> + StackProgram<N>),
77        store: &impl FinalizeStoreTrait<N>,
78        registers: &mut impl RegistersLoad<N>,
79    ) -> Result<FinalizeOperation<N>> {
80        // Ensure the mapping exists in storage.
81        if !store.contains_mapping_confirmed(stack.program_id(), &self.mapping)? {
82            bail!("Mapping '{}/{}' does not exist in storage", stack.program_id(), self.mapping);
83        }
84
85        // Load the key operand as a plaintext.
86        let key = registers.load_plaintext(stack, &self.key)?;
87        // Load the value operand as a plaintext.
88        let value = Value::Plaintext(registers.load_plaintext(stack, &self.value)?);
89
90        // Update the value in storage, and return the finalize operation.
91        store.update_key_value(*stack.program_id(), self.mapping, key, value)
92    }
93}
94
95impl<N: Network> Parser for Set<N> {
96    /// Parses a string into an operation.
97    #[inline]
98    fn parse(string: &str) -> ParserResult<Self> {
99        // Parse the whitespace and comments from the string.
100        let (string, _) = Sanitizer::parse(string)?;
101        // Parse the opcode from the string.
102        let (string, _) = tag(*Self::opcode())(string)?;
103        // Parse the whitespace from the string.
104        let (string, _) = Sanitizer::parse_whitespaces(string)?;
105
106        // Parse the value operand from the string.
107        let (string, value) = Operand::parse(string)?;
108        // Parse the whitespace from the string.
109        let (string, _) = Sanitizer::parse_whitespaces(string)?;
110
111        // Parse the "into" keyword from the string.
112        let (string, _) = tag("into")(string)?;
113        // Parse the whitespace from the string.
114        let (string, _) = Sanitizer::parse_whitespaces(string)?;
115
116        // Parse the mapping name from the string.
117        let (string, mapping) = Identifier::parse(string)?;
118        // Parse the "[" from the string.
119        let (string, _) = tag("[")(string)?;
120        // Parse the whitespace from the string.
121        let (string, _) = Sanitizer::parse_whitespaces(string)?;
122        // Parse the key operand from the string.
123        let (string, key) = Operand::parse(string)?;
124        // Parse the whitespace from the string.
125        let (string, _) = Sanitizer::parse_whitespaces(string)?;
126        // Parse the "]" from the string.
127        let (string, _) = tag("]")(string)?;
128        // Parse the whitespace from the string.
129        let (string, _) = Sanitizer::parse_whitespaces(string)?;
130        // Parse the ";" from the string.
131        let (string, _) = tag(";")(string)?;
132
133        Ok((string, Self { mapping, key, value }))
134    }
135}
136
137impl<N: Network> FromStr for Set<N> {
138    type Err = Error;
139
140    /// Parses a string into the command.
141    #[inline]
142    fn from_str(string: &str) -> Result<Self> {
143        match Self::parse(string) {
144            Ok((remainder, object)) => {
145                // Ensure the remainder is empty.
146                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
147                // Return the object.
148                Ok(object)
149            }
150            Err(error) => bail!("Failed to parse string. {error}"),
151        }
152    }
153}
154
155impl<N: Network> Debug for Set<N> {
156    /// Prints the command as a string.
157    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
158        Display::fmt(self, f)
159    }
160}
161
162impl<N: Network> Display for Set<N> {
163    /// Prints the command to a string.
164    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
165        // Print the command.
166        write!(f, "{} ", Self::opcode())?;
167        // Print the value operand.
168        write!(f, "{} into ", self.value)?;
169        // Print the mapping and key operand.
170        write!(f, "{}[{}];", self.mapping, self.key)
171    }
172}
173
174impl<N: Network> FromBytes for Set<N> {
175    /// Reads the command from a buffer.
176    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
177        // Read the mapping name.
178        let mapping = Identifier::read_le(&mut reader)?;
179        // Read the key operand.
180        let key = Operand::read_le(&mut reader)?;
181        // Read the value operand.
182        let value = Operand::read_le(&mut reader)?;
183        // Return the command.
184        Ok(Self { mapping, key, value })
185    }
186}
187
188impl<N: Network> ToBytes for Set<N> {
189    /// Writes the operation to a buffer.
190    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
191        // Write the mapping name.
192        self.mapping.write_le(&mut writer)?;
193        // Write the key operand.
194        self.key.write_le(&mut writer)?;
195        // Write the value operand.
196        self.value.write_le(&mut writer)
197    }
198}
199
200#[cfg(test)]
201mod tests {
202    use super::*;
203    use console::{network::MainnetV0, program::Register};
204
205    type CurrentNetwork = MainnetV0;
206
207    #[test]
208    fn test_parse() {
209        let (string, set) = Set::<CurrentNetwork>::parse("set r0 into account[r1];").unwrap();
210        assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
211        assert_eq!(set.mapping, Identifier::from_str("account").unwrap());
212        assert_eq!(set.operands().len(), 2, "The number of operands is incorrect");
213        assert_eq!(set.value, Operand::Register(Register::Locator(0)), "The first operand is incorrect");
214        assert_eq!(set.key, Operand::Register(Register::Locator(1)), "The second operand is incorrect");
215    }
216}