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