snarkvm_synthesizer_program/
bytes.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 super::*;
17
18impl<N: Network, Instruction: InstructionTrait<N>, Command: CommandTrait<N>> FromBytes
19    for ProgramCore<N, Instruction, Command>
20{
21    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
22        // Read the version.
23        let version = u8::read_le(&mut reader)?;
24        // Ensure the version is valid.
25        if version != 1 {
26            return Err(error("Invalid program version"));
27        }
28
29        // Read the program ID.
30        let id = ProgramID::read_le(&mut reader)?;
31
32        // Initialize the program.
33        let mut program = ProgramCore::new(id).map_err(|e| error(e.to_string()))?;
34
35        // Read the number of program imports.
36        let imports_len = u8::read_le(&mut reader)?;
37        // Read the program imports.
38        for _ in 0..imports_len {
39            program.add_import(Import::read_le(&mut reader)?).map_err(|e| error(e.to_string()))?;
40        }
41
42        // Read the number of components.
43        let components_len = u16::read_le(&mut reader)?;
44        for _ in 0..components_len {
45            // Read the variant.
46            let variant = u8::read_le(&mut reader)?;
47            // Match the variant.
48            match variant {
49                // Read the mapping.
50                0 => program.add_mapping(Mapping::read_le(&mut reader)?).map_err(|e| error(e.to_string()))?,
51                // Read the struct.
52                1 => program.add_struct(StructType::read_le(&mut reader)?).map_err(|e| error(e.to_string()))?,
53                // Read the record.
54                2 => program.add_record(RecordType::read_le(&mut reader)?).map_err(|e| error(e.to_string()))?,
55                // Read the closure.
56                3 => program.add_closure(ClosureCore::read_le(&mut reader)?).map_err(|e| error(e.to_string()))?,
57                // Read the function.
58                4 => program.add_function(FunctionCore::read_le(&mut reader)?).map_err(|e| error(e.to_string()))?,
59                // Invalid variant.
60                _ => return Err(error(format!("Failed to parse program. Invalid component variant '{variant}'"))),
61            }
62        }
63
64        Ok(program)
65    }
66}
67
68impl<N: Network, Instruction: InstructionTrait<N>, Command: CommandTrait<N>> ToBytes
69    for ProgramCore<N, Instruction, Command>
70{
71    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
72        // Write the version.
73        1u8.write_le(&mut writer)?;
74
75        // Write the program ID.
76        self.id.write_le(&mut writer)?;
77
78        // Write the number of program imports.
79        u8::try_from(self.imports.len()).map_err(|e| error(e.to_string()))?.write_le(&mut writer)?;
80        // Write the program imports.
81        for import in self.imports.values() {
82            import.write_le(&mut writer)?;
83        }
84
85        // Write the number of components.
86        u16::try_from(self.components.len()).map_err(|e| error(e.to_string()))?.write_le(&mut writer)?;
87        // Write the components.
88        for (identifier, definition) in self.components.iter() {
89            match definition {
90                ProgramDefinition::Mapping => match self.mappings.get(identifier) {
91                    Some(mapping) => {
92                        // Write the variant.
93                        0u8.write_le(&mut writer)?;
94                        // Write the mapping.
95                        mapping.write_le(&mut writer)?;
96                    }
97                    None => return Err(error(format!("Mapping '{identifier}' is not defined"))),
98                },
99                ProgramDefinition::Struct => match self.structs.get(identifier) {
100                    Some(struct_) => {
101                        // Write the variant.
102                        1u8.write_le(&mut writer)?;
103                        // Write the struct.
104                        struct_.write_le(&mut writer)?;
105                    }
106                    None => return Err(error(format!("Struct '{identifier}' is not defined."))),
107                },
108                ProgramDefinition::Record => match self.records.get(identifier) {
109                    Some(record) => {
110                        // Write the variant.
111                        2u8.write_le(&mut writer)?;
112                        // Write the record.
113                        record.write_le(&mut writer)?;
114                    }
115                    None => return Err(error(format!("Record '{identifier}' is not defined."))),
116                },
117                ProgramDefinition::Closure => match self.closures.get(identifier) {
118                    Some(closure) => {
119                        // Write the variant.
120                        3u8.write_le(&mut writer)?;
121                        // Write the closure.
122                        closure.write_le(&mut writer)?;
123                    }
124                    None => return Err(error(format!("Closure '{identifier}' is not defined."))),
125                },
126                ProgramDefinition::Function => match self.functions.get(identifier) {
127                    Some(function) => {
128                        // Write the variant.
129                        4u8.write_le(&mut writer)?;
130                        // Write the function.
131                        function.write_le(&mut writer)?;
132                    }
133                    None => return Err(error(format!("Function '{identifier}' is not defined."))),
134                },
135            }
136        }
137
138        Ok(())
139    }
140}
141
142#[cfg(test)]
143mod tests {
144    use super::*;
145    use crate::Program;
146    use console::network::MainnetV0;
147
148    type CurrentNetwork = MainnetV0;
149
150    #[test]
151    fn test_bytes() -> Result<()> {
152        let program = r"
153program token.aleo;
154
155record token:
156    owner as address.private;
157    token_amount as u64.private;
158
159function compute:
160    input r0 as token.record;
161    add r0.token_amount r0.token_amount into r1;
162    output r1 as u64.private;";
163
164        // Initialize a new program.
165        let (string, expected) = Program::<CurrentNetwork>::parse(program).unwrap();
166        assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
167
168        let expected_bytes = expected.to_bytes_le()?;
169
170        let candidate = Program::<CurrentNetwork>::from_bytes_le(&expected_bytes)?;
171        assert_eq!(expected, candidate);
172        assert_eq!(expected_bytes, candidate.to_bytes_le()?);
173
174        Ok(())
175    }
176}