snarkvm_console_program/data/future/
bytes.rs1use super::*;
17
18impl<N: Network> FromBytes for Future<N> {
19 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
21 Self::read_le_internal(&mut reader, 0)
23 }
24}
25
26impl<N: Network> Future<N> {
27 fn read_le_internal<R: Read>(mut reader: R, depth: usize) -> IoResult<Self> {
29 if depth > N::MAX_DATA_DEPTH {
34 return Err(error(format!(
35 "Failed to deserialize plaintext: Depth exceeds maximum limit: {}",
36 N::MAX_DATA_DEPTH
37 )));
38 }
39 let program_id = ProgramID::read_le(&mut reader)?;
41 let function_name = Identifier::<N>::read_le(&mut reader)?;
43 let num_arguments = u8::read_le(&mut reader)? as usize;
45 if num_arguments > N::MAX_INPUTS {
46 return Err(error("Failed to read future: too many arguments"));
47 };
48 let mut arguments = Vec::with_capacity(num_arguments);
50 for _ in 0..num_arguments {
51 let num_bytes = u16::read_le(&mut reader)?;
53 let mut bytes = Vec::new();
55 (&mut reader).take(num_bytes as u64).read_to_end(&mut bytes)?;
56 if bytes.len() != num_bytes as usize {
58 return Err(error("Failed to read future: argument is truncated"));
59 }
60 let mut slice = bytes.as_slice();
62 let entry = Argument::read_le_internal(&mut slice, depth)?;
63 if !slice.is_empty() {
66 return Err(error("Failed to read future: argument has trailing bytes"));
67 }
68 arguments.push(entry);
70 }
71 Ok(Self::new(program_id, function_name, arguments))
73 }
74}
75
76impl<N: Network> ToBytes for Future<N> {
77 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
79 self.program_id.write_le(&mut writer)?;
81 self.function_name.write_le(&mut writer)?;
83 if self.arguments.len() > N::MAX_INPUTS {
85 return Err(error("Failed to write future: too many arguments"));
86 };
87 u8::try_from(self.arguments.len()).map_err(error)?.write_le(&mut writer)?;
88 for argument in &self.arguments {
90 let bytes = argument.to_bytes_le().map_err(error)?;
92 u16::try_from(bytes.len()).map_err(error)?.write_le(&mut writer)?;
94 bytes.write_le(&mut writer)?;
96 }
97 Ok(())
98 }
99}
100
101impl<N: Network> Argument<N> {
102 fn read_le_internal<R: Read>(mut reader: R, depth: usize) -> IoResult<Self>
103 where
104 Self: Sized,
105 {
106 let index = u8::read_le(&mut reader)?;
108 let argument = match index {
110 0 => Self::Plaintext(Plaintext::read_le(&mut reader)?),
111 1 => Self::Future(Future::read_le_internal(&mut reader, depth + 1)?),
112 2 => Self::DynamicFuture(DynamicFuture::read_le(&mut reader)?),
113 3.. => return Err(error(format!("Failed to decode future argument {index}"))),
114 };
115 Ok(argument)
116 }
117}
118
119impl<N: Network> ToBytes for Argument<N> {
120 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
121 match self {
122 Self::Plaintext(plaintext) => {
123 0u8.write_le(&mut writer)?;
124 plaintext.write_le(&mut writer)
125 }
126 Self::Future(future) => {
127 1u8.write_le(&mut writer)?;
128 future.write_le(&mut writer)
129 }
130 Self::DynamicFuture(dynamic_future) => {
131 2u8.write_le(&mut writer)?;
132 dynamic_future.write_le(&mut writer)
133 }
134 }
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use snarkvm_console_network::MainnetV0;
142
143 use core::str::FromStr;
144
145 type CurrentNetwork = MainnetV0;
146
147 #[test]
148 fn test_bytes() {
149 let expected =
151 Future::<CurrentNetwork>::from_str("{ program_id: credits.aleo, function_name: transfer, arguments: [] }")
152 .unwrap();
153
154 let expected_bytes = expected.to_bytes_le().unwrap();
156 assert_eq!(expected, Future::read_le(&expected_bytes[..]).unwrap());
157 }
158
159 #[test]
160 fn test_bytes_with_plaintext_arguments() {
161 let expected = Future::<CurrentNetwork>::new(
163 ProgramID::from_str("test.aleo").unwrap(),
164 Identifier::from_str("foo").unwrap(),
165 vec![
166 Argument::Plaintext(Plaintext::from_str("100u64").unwrap()),
167 Argument::Plaintext(Plaintext::from_str("true").unwrap()),
168 ],
169 );
170
171 let expected_bytes = expected.to_bytes_le().unwrap();
173 let candidate = Future::read_le(&expected_bytes[..]).unwrap();
174 assert_eq!(expected, candidate);
175 }
176
177 #[test]
178 fn test_bytes_with_dynamic_future_argument() {
179 let inner = Future::<CurrentNetwork>::new(
181 ProgramID::from_str("inner.aleo").unwrap(),
182 Identifier::from_str("bar").unwrap(),
183 vec![Argument::Plaintext(Plaintext::from_str("42u64").unwrap())],
184 );
185
186 let dynamic_inner = DynamicFuture::from_future(&inner).unwrap();
188
189 let expected = Future::<CurrentNetwork>::new(
191 ProgramID::from_str("outer.aleo").unwrap(),
192 Identifier::from_str("baz").unwrap(),
193 vec![Argument::DynamicFuture(dynamic_inner)],
194 );
195
196 let expected_bytes = expected.to_bytes_le().unwrap();
198 let candidate = Future::read_le(&expected_bytes[..]).unwrap();
199
200 assert_eq!(expected.program_id(), candidate.program_id());
202 assert_eq!(expected.function_name(), candidate.function_name());
203 assert_eq!(expected.arguments().len(), candidate.arguments().len());
204
205 match (&expected.arguments()[0], &candidate.arguments()[0]) {
207 (Argument::DynamicFuture(e), Argument::DynamicFuture(c)) => {
208 assert_eq!(e.program_name(), c.program_name());
209 assert_eq!(e.program_network(), c.program_network());
210 assert_eq!(e.function_name(), c.function_name());
211 assert_eq!(e.checksum(), c.checksum());
212 }
213 _ => panic!("Expected DynamicFuture argument"),
214 }
215 }
216
217 #[test]
218 fn test_bytes_with_nested_future_argument() {
219 let inner = Future::<CurrentNetwork>::new(
221 ProgramID::from_str("inner.aleo").unwrap(),
222 Identifier::from_str("bar").unwrap(),
223 vec![Argument::Plaintext(Plaintext::from_str("42u64").unwrap())],
224 );
225
226 let expected = Future::<CurrentNetwork>::new(
228 ProgramID::from_str("outer.aleo").unwrap(),
229 Identifier::from_str("baz").unwrap(),
230 vec![Argument::Future(inner)],
231 );
232
233 let expected_bytes = expected.to_bytes_le().unwrap();
235 let candidate = Future::read_le(&expected_bytes[..]).unwrap();
236 assert_eq!(expected, candidate);
237 }
238
239 #[test]
240 fn test_bytes_with_mixed_arguments() {
241 let inner = Future::<CurrentNetwork>::new(
243 ProgramID::from_str("inner.aleo").unwrap(),
244 Identifier::from_str("bar").unwrap(),
245 vec![],
246 );
247
248 let dynamic_inner = DynamicFuture::from_future(&inner).unwrap();
250
251 let expected = Future::<CurrentNetwork>::new(
253 ProgramID::from_str("test.aleo").unwrap(),
254 Identifier::from_str("mixed").unwrap(),
255 vec![
256 Argument::Plaintext(Plaintext::from_str("100u64").unwrap()),
257 Argument::Future(inner),
258 Argument::DynamicFuture(dynamic_inner),
259 ],
260 );
261
262 let expected_bytes = expected.to_bytes_le().unwrap();
264 let candidate = Future::read_le(&expected_bytes[..]).unwrap();
265
266 assert_eq!(expected.program_id(), candidate.program_id());
268 assert_eq!(expected.function_name(), candidate.function_name());
269 assert_eq!(expected.arguments().len(), candidate.arguments().len());
270 }
271
272 fn get_depth<N: Network>(future: &Future<N>) -> usize {
274 future
276 .arguments
277 .iter()
278 .map(|arg| match arg {
279 Argument::Plaintext(_) => 0,
280 Argument::Future(future) => 1 + get_depth(future),
281 Argument::DynamicFuture(_) => panic!("Dynamic futures are not used in this test"),
282 })
283 .sum()
284 }
285
286 #[test]
287 fn test_deeply_nested_future() {
288 fn create_nested_future(depth: usize) -> Vec<u8> {
291 let mut result = Future::<CurrentNetwork>::from_str(
293 r"{
294 program_id: foo.aleo,
295 function_name: bar,
296 arguments: []
297 }",
298 )
299 .unwrap()
300 .to_bytes_le()
301 .unwrap();
302 result.reverse();
304 for _ in 0..depth {
306 let mut variant = 1u8.to_bytes_le().unwrap();
308 variant.reverse();
309 result.extend(variant);
310 let mut length = (u16::try_from(result.len()).unwrap()).to_bytes_le().unwrap();
312 length.reverse();
313 result.extend(length);
314 let mut num_elements = 1u8.to_bytes_le().unwrap();
316 num_elements.reverse();
317 result.extend(num_elements);
318 let mut function_name = Identifier::<CurrentNetwork>::from_str("bar").unwrap().to_bytes_le().unwrap();
320 function_name.reverse();
321 result.extend(function_name);
322 let mut program_id = ProgramID::<CurrentNetwork>::from_str("foo.aleo").unwrap().to_bytes_le().unwrap();
324 program_id.reverse();
325 result.extend(program_id);
326 }
327 result.reverse();
329 result
330 }
331
332 fn run_test(expected_depth: usize, input: Vec<u8>, expected_error: bool) {
334 let result = Future::<CurrentNetwork>::read_le(&*input);
336 match expected_error {
338 true => {
339 assert!(result.is_err());
340 return;
341 }
342 false => assert!(result.is_ok()),
343 };
344 let candidate = result.unwrap();
346 assert_eq!(input, candidate.to_bytes_le().unwrap());
348 assert_eq!(get_depth(&candidate), expected_depth);
350 }
351
352 let mut depths = (0usize..100).collect_vec();
355 depths.extend((100..3900).step_by(100));
356
357 for i in depths.iter().copied() {
359 run_test(i, create_nested_future(i), i > CurrentNetwork::MAX_DATA_DEPTH);
360 run_test(i, create_nested_future(i), i > CurrentNetwork::MAX_DATA_DEPTH);
361 run_test(i, create_nested_future(i), i > CurrentNetwork::MAX_DATA_DEPTH);
362 run_test(i, create_nested_future(i), i > CurrentNetwork::MAX_DATA_DEPTH);
363 }
364 }
365
366 fn future_with_padded_argument(padding: usize) -> Result<Vec<u8>> {
369 let argument = Argument::<CurrentNetwork>::Plaintext(Plaintext::from_str("7u8")?);
370 let argument_bytes = argument.to_bytes_le()?;
371
372 let mut bytes = Vec::new();
373 ProgramID::<CurrentNetwork>::from_str("credits.aleo")?.write_le(&mut bytes)?;
374 Identifier::<CurrentNetwork>::from_str("transfer")?.write_le(&mut bytes)?;
375 1u8.write_le(&mut bytes)?;
376 u16::try_from(argument_bytes.len() + padding)?.write_le(&mut bytes)?;
377 bytes.extend_from_slice(&argument_bytes);
378 bytes.extend(std::iter::repeat_n(0u8, padding));
379 Ok(bytes)
380 }
381
382 #[test]
383 fn test_future_argument_rejects_trailing_bytes() -> Result<()> {
384 let exact = future_with_padded_argument(0)?;
386 let future = Future::<CurrentNetwork>::read_le(&exact[..])?;
387 assert_eq!(exact, future.to_bytes_le()?, "the unpadded encoding must round trip");
388
389 for padding in [1, 8, 32] {
393 let padded = future_with_padded_argument(padding)?;
394 assert_ne!(padded, exact);
395 assert!(
396 Future::<CurrentNetwork>::read_le(&padded[..]).is_err(),
397 "a future argument declaring {padding} bytes more than it uses must be rejected"
398 );
399 }
400 Ok(())
401 }
402}