snarkvm_synthesizer_program/
bytes.rs1use super::*;
17
18impl<N: Network> FromBytes for ProgramCore<N> {
19 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
20 let version = u8::read_le(&mut reader)?;
22 if version != 1 {
24 return Err(error("Invalid program version"));
25 }
26
27 let id = ProgramID::read_le(&mut reader)?;
29
30 let mut program = ProgramCore::new(id).map_err(error)?;
32
33 let imports_len = u8::read_le(&mut reader)?;
35 for _ in 0..imports_len {
37 program.add_import(Import::read_le(&mut reader)?).map_err(error)?;
38 }
39
40 let components_len = u16::read_le(&mut reader)?;
42 for _ in 0..components_len {
43 let variant = u8::read_le(&mut reader)?;
45 match variant {
47 0 => program.add_mapping(Mapping::read_le(&mut reader)?).map_err(error)?,
49 1 => program.add_struct(StructType::read_le(&mut reader)?).map_err(error)?,
51 2 => program.add_record(RecordType::read_le(&mut reader)?).map_err(error)?,
53 3 => program.add_closure(ClosureCore::read_le(&mut reader)?).map_err(error)?,
55 4 => program.add_function(FunctionCore::read_le(&mut reader)?).map_err(error)?,
57 5 => program.add_constructor(ConstructorCore::read_le(&mut reader)?).map_err(error)?,
59 6 => program.add_view(ViewCore::read_le(&mut reader)?).map_err(error)?,
61 _ => return Err(error(format!("Failed to parse program. Invalid component variant '{variant}'"))),
63 }
64 }
65
66 Ok(program)
67 }
68}
69
70impl<N: Network> ToBytes for ProgramCore<N> {
71 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
72 1u8.write_le(&mut writer)?;
74
75 self.id.write_le(&mut writer)?;
77
78 u8::try_from(self.imports.len()).map_err(error)?.write_le(&mut writer)?;
80 for import in self.imports.values() {
82 import.write_le(&mut writer)?;
83 }
84
85 u16::try_from(self.components.len()).map_err(error)?.write_le(&mut writer)?;
87
88 for (label, definition) in self.components.iter() {
90 match label {
91 ProgramLabel::Constructor => {
92 if let Some(constructor) = &self.constructor {
94 5u8.write_le(&mut writer)?;
96 constructor.write_le(&mut writer)?;
98 }
99 }
100 ProgramLabel::Identifier(identifier) => {
101 match definition {
102 ProgramDefinition::Constructor => {
103 return Err(error("A program constructor cannot have a named label"));
104 }
105 ProgramDefinition::Mapping => match self.mappings.get(identifier) {
106 Some(mapping) => {
107 0u8.write_le(&mut writer)?;
109 mapping.write_le(&mut writer)?;
111 }
112 None => return Err(error(format!("Mapping '{identifier}' is not defined"))),
113 },
114 ProgramDefinition::Struct => match self.structs.get(identifier) {
115 Some(struct_) => {
116 1u8.write_le(&mut writer)?;
118 struct_.write_le(&mut writer)?;
120 }
121 None => return Err(error(format!("Struct '{identifier}' is not defined."))),
122 },
123 ProgramDefinition::Record => match self.records.get(identifier) {
124 Some(record) => {
125 2u8.write_le(&mut writer)?;
127 record.write_le(&mut writer)?;
129 }
130 None => return Err(error(format!("Record '{identifier}' is not defined."))),
131 },
132 ProgramDefinition::Closure => match self.closures.get(identifier) {
133 Some(closure) => {
134 3u8.write_le(&mut writer)?;
136 closure.write_le(&mut writer)?;
138 }
139 None => return Err(error(format!("Closure '{identifier}' is not defined."))),
140 },
141 ProgramDefinition::Function => match self.functions.get(identifier) {
142 Some(function) => {
143 4u8.write_le(&mut writer)?;
145 function.write_le(&mut writer)?;
147 }
148 None => return Err(error(format!("Function '{identifier}' is not defined."))),
149 },
150 ProgramDefinition::View => match self.views.get(identifier) {
151 Some(view) => {
152 6u8.write_le(&mut writer)?;
154 view.write_le(&mut writer)?;
156 }
157 None => return Err(error(format!("View '{identifier}' is not defined."))),
158 },
159 }
160 }
161 }
162 }
163 Ok(())
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use crate::Program;
171 use console::network::MainnetV0;
172
173 type CurrentNetwork = MainnetV0;
174
175 #[test]
176 fn test_bytes_with_view() -> Result<()> {
177 let program = r"
178program token_with_view.aleo;
179
180mapping balances:
181 key as address.public;
182 value as u64.public;
183
184function noop:
185 input r0 as u64.private;
186 output r0 as u64.private;
187
188view total_balance:
189 input r0 as address.public;
190 get.or_use balances[r0] 0u64 into r1;
191 output r1 as u64.public;";
192
193 let (string, expected) = Program::<CurrentNetwork>::parse(program).unwrap();
194 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
195
196 let expected_bytes = expected.to_bytes_le()?;
197 let candidate = Program::<CurrentNetwork>::from_bytes_le(&expected_bytes)?;
198 assert_eq!(expected, candidate);
199 assert_eq!(expected_bytes, candidate.to_bytes_le()?);
200
201 Ok(())
202 }
203
204 #[test]
205 fn test_bytes() -> Result<()> {
206 let program = r"
207program token.aleo;
208
209record token:
210 owner as address.private;
211 token_amount as u64.private;
212
213function compute:
214 input r0 as token.record;
215 add r0.token_amount r0.token_amount into r1;
216 output r1 as u64.private;";
217
218 let (string, expected) = Program::<CurrentNetwork>::parse(program).unwrap();
220 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
221
222 let expected_bytes = expected.to_bytes_le()?;
223
224 let candidate = Program::<CurrentNetwork>::from_bytes_le(&expected_bytes)?;
225 assert_eq!(expected, candidate);
226 assert_eq!(expected_bytes, candidate.to_bytes_le()?);
227
228 Ok(())
229 }
230}