Skip to main content

snarkvm_console_program/data/future/
bytes.rs

1// Copyright (c) 2019-2026 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 Future<N> {
19    /// Reads in a future from a buffer.
20    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
21        // Read the future.
22        Self::read_le_internal(&mut reader, 0)
23    }
24}
25
26impl<N: Network> Future<N> {
27    /// Reads in a future from a buffer, while tracking the depth of the data.
28    fn read_le_internal<R: Read>(mut reader: R, depth: usize) -> IoResult<Self> {
29        // Ensure that the depth is within the maximum limit.
30        // Note: `N::MAX_DATA_DEPTH` is an upper bound on the number of nested futures.
31        //  The true maximum is defined by `Transaction::<N>::MAX_TRANSITIONS`, however, that object is not accessible in this crate.
32        //  In practice, `MAX_DATA_DEPTH` is 32, while `MAX_TRANSITIONS` is 31.
33        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        // Read the program ID.
40        let program_id = ProgramID::read_le(&mut reader)?;
41        // Read the function name.
42        let function_name = Identifier::<N>::read_le(&mut reader)?;
43        // Read the number of arguments to the future.
44        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        // Read the arguments.
49        let mut arguments = Vec::with_capacity(num_arguments);
50        for _ in 0..num_arguments {
51            // Read the argument (in 2 steps to prevent infinite recursion).
52            let num_bytes = u16::read_le(&mut reader)?;
53            // Read the argument bytes.
54            let mut bytes = Vec::new();
55            (&mut reader).take(num_bytes as u64).read_to_end(&mut bytes)?;
56            // Recover the argument.
57            let entry = Argument::read_le_internal(&mut bytes.as_slice(), depth)?;
58            // Add the argument.
59            arguments.push(entry);
60        }
61        // Return the future.
62        Ok(Self::new(program_id, function_name, arguments))
63    }
64}
65
66impl<N: Network> ToBytes for Future<N> {
67    /// Writes a future to a buffer.
68    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
69        // Write the program ID.
70        self.program_id.write_le(&mut writer)?;
71        // Write the function name.
72        self.function_name.write_le(&mut writer)?;
73        // Write the number of arguments.
74        if self.arguments.len() > N::MAX_INPUTS {
75            return Err(error("Failed to write future: too many arguments"));
76        };
77        u8::try_from(self.arguments.len()).map_err(error)?.write_le(&mut writer)?;
78        // Write each argument.
79        for argument in &self.arguments {
80            // Write the argument (performed in 2 steps to prevent infinite recursion).
81            let bytes = argument.to_bytes_le().map_err(error)?;
82            // Write the number of bytes.
83            u16::try_from(bytes.len()).map_err(error)?.write_le(&mut writer)?;
84            // Write the bytes.
85            bytes.write_le(&mut writer)?;
86        }
87        Ok(())
88    }
89}
90
91impl<N: Network> Argument<N> {
92    fn read_le_internal<R: Read>(mut reader: R, depth: usize) -> IoResult<Self>
93    where
94        Self: Sized,
95    {
96        // Read the index.
97        let index = u8::read_le(&mut reader)?;
98        // Read the argument.
99        let argument = match index {
100            0 => Self::Plaintext(Plaintext::read_le(&mut reader)?),
101            1 => Self::Future(Future::read_le_internal(&mut reader, depth + 1)?),
102            2 => Self::DynamicFuture(DynamicFuture::read_le(&mut reader)?),
103            3.. => return Err(error(format!("Failed to decode future argument {index}"))),
104        };
105        Ok(argument)
106    }
107}
108
109impl<N: Network> ToBytes for Argument<N> {
110    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
111        match self {
112            Self::Plaintext(plaintext) => {
113                0u8.write_le(&mut writer)?;
114                plaintext.write_le(&mut writer)
115            }
116            Self::Future(future) => {
117                1u8.write_le(&mut writer)?;
118                future.write_le(&mut writer)
119            }
120            Self::DynamicFuture(dynamic_future) => {
121                2u8.write_le(&mut writer)?;
122                dynamic_future.write_le(&mut writer)
123            }
124        }
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use snarkvm_console_network::MainnetV0;
132
133    use core::str::FromStr;
134
135    type CurrentNetwork = MainnetV0;
136
137    #[test]
138    fn test_bytes() {
139        // Check the future manually.
140        let expected =
141            Future::<CurrentNetwork>::from_str("{ program_id: credits.aleo, function_name: transfer, arguments: [] }")
142                .unwrap();
143
144        // Check the byte representation.
145        let expected_bytes = expected.to_bytes_le().unwrap();
146        assert_eq!(expected, Future::read_le(&expected_bytes[..]).unwrap());
147    }
148
149    #[test]
150    fn test_bytes_with_plaintext_arguments() {
151        // Create a future with plaintext arguments.
152        let expected = Future::<CurrentNetwork>::new(
153            ProgramID::from_str("test.aleo").unwrap(),
154            Identifier::from_str("foo").unwrap(),
155            vec![
156                Argument::Plaintext(Plaintext::from_str("100u64").unwrap()),
157                Argument::Plaintext(Plaintext::from_str("true").unwrap()),
158            ],
159        );
160
161        // Check the byte representation.
162        let expected_bytes = expected.to_bytes_le().unwrap();
163        let candidate = Future::read_le(&expected_bytes[..]).unwrap();
164        assert_eq!(expected, candidate);
165    }
166
167    #[test]
168    fn test_bytes_with_dynamic_future_argument() {
169        // Create an inner future.
170        let inner = Future::<CurrentNetwork>::new(
171            ProgramID::from_str("inner.aleo").unwrap(),
172            Identifier::from_str("bar").unwrap(),
173            vec![Argument::Plaintext(Plaintext::from_str("42u64").unwrap())],
174        );
175
176        // Convert to dynamic future.
177        let dynamic_inner = DynamicFuture::from_future(&inner).unwrap();
178
179        // Create a future with a dynamic future argument.
180        let expected = Future::<CurrentNetwork>::new(
181            ProgramID::from_str("outer.aleo").unwrap(),
182            Identifier::from_str("baz").unwrap(),
183            vec![Argument::DynamicFuture(dynamic_inner)],
184        );
185
186        // Check the byte representation.
187        let expected_bytes = expected.to_bytes_le().unwrap();
188        let candidate = Future::read_le(&expected_bytes[..]).unwrap();
189
190        // Verify the structure matches.
191        assert_eq!(expected.program_id(), candidate.program_id());
192        assert_eq!(expected.function_name(), candidate.function_name());
193        assert_eq!(expected.arguments().len(), candidate.arguments().len());
194
195        // Verify the dynamic future argument.
196        match (&expected.arguments()[0], &candidate.arguments()[0]) {
197            (Argument::DynamicFuture(e), Argument::DynamicFuture(c)) => {
198                assert_eq!(e.program_name(), c.program_name());
199                assert_eq!(e.program_network(), c.program_network());
200                assert_eq!(e.function_name(), c.function_name());
201                assert_eq!(e.checksum(), c.checksum());
202            }
203            _ => panic!("Expected DynamicFuture argument"),
204        }
205    }
206
207    #[test]
208    fn test_bytes_with_nested_future_argument() {
209        // Create an inner future.
210        let inner = Future::<CurrentNetwork>::new(
211            ProgramID::from_str("inner.aleo").unwrap(),
212            Identifier::from_str("bar").unwrap(),
213            vec![Argument::Plaintext(Plaintext::from_str("42u64").unwrap())],
214        );
215
216        // Create a future with a nested future argument.
217        let expected = Future::<CurrentNetwork>::new(
218            ProgramID::from_str("outer.aleo").unwrap(),
219            Identifier::from_str("baz").unwrap(),
220            vec![Argument::Future(inner)],
221        );
222
223        // Check the byte representation.
224        let expected_bytes = expected.to_bytes_le().unwrap();
225        let candidate = Future::read_le(&expected_bytes[..]).unwrap();
226        assert_eq!(expected, candidate);
227    }
228
229    #[test]
230    fn test_bytes_with_mixed_arguments() {
231        // Create an inner future.
232        let inner = Future::<CurrentNetwork>::new(
233            ProgramID::from_str("inner.aleo").unwrap(),
234            Identifier::from_str("bar").unwrap(),
235            vec![],
236        );
237
238        // Convert to dynamic future.
239        let dynamic_inner = DynamicFuture::from_future(&inner).unwrap();
240
241        // Create a future with mixed arguments.
242        let expected = Future::<CurrentNetwork>::new(
243            ProgramID::from_str("test.aleo").unwrap(),
244            Identifier::from_str("mixed").unwrap(),
245            vec![
246                Argument::Plaintext(Plaintext::from_str("100u64").unwrap()),
247                Argument::Future(inner),
248                Argument::DynamicFuture(dynamic_inner),
249            ],
250        );
251
252        // Check the byte representation.
253        let expected_bytes = expected.to_bytes_le().unwrap();
254        let candidate = Future::read_le(&expected_bytes[..]).unwrap();
255
256        // Verify structure.
257        assert_eq!(expected.program_id(), candidate.program_id());
258        assert_eq!(expected.function_name(), candidate.function_name());
259        assert_eq!(expected.arguments().len(), candidate.arguments().len());
260    }
261
262    // A helper function to get the depth of a future.
263    fn get_depth<N: Network>(future: &Future<N>) -> usize {
264        // Count the number of nested futures.
265        future
266            .arguments
267            .iter()
268            .map(|arg| match arg {
269                Argument::Plaintext(_) => 0,
270                Argument::Future(future) => 1 + get_depth(future),
271                Argument::DynamicFuture(_) => panic!("Dynamic futures are not used in this test"),
272            })
273            .sum()
274    }
275
276    #[test]
277    fn test_deeply_nested_future() {
278        // Creates a nested `Future`.
279        // This method is iterative to avoid stack overflows.
280        fn create_nested_future(depth: usize) -> Vec<u8> {
281            // Start from the innermost value.
282            let mut result = Future::<CurrentNetwork>::from_str(
283                r"{
284                program_id: foo.aleo,
285                function_name: bar,
286                arguments: []
287            }",
288            )
289            .unwrap()
290            .to_bytes_le()
291            .unwrap();
292            // Reverse the bytes.
293            result.reverse();
294            // Build up the structure in reverse.
295            for _ in 0..depth {
296                // Write the variant of the argument in reverse.
297                let mut variant = 1u8.to_bytes_le().unwrap();
298                variant.reverse();
299                result.extend(variant);
300                // Write the size of the object in bytes in reverse.
301                let mut length = (u16::try_from(result.len()).unwrap()).to_bytes_le().unwrap();
302                length.reverse();
303                result.extend(length);
304                // Write the number of arguments in reverse.
305                let mut num_elements = 1u8.to_bytes_le().unwrap();
306                num_elements.reverse();
307                result.extend(num_elements);
308                // Write the function name in reverse.
309                let mut function_name = Identifier::<CurrentNetwork>::from_str("bar").unwrap().to_bytes_le().unwrap();
310                function_name.reverse();
311                result.extend(function_name);
312                // Write the program ID in reverse.
313                let mut program_id = ProgramID::<CurrentNetwork>::from_str("foo.aleo").unwrap().to_bytes_le().unwrap();
314                program_id.reverse();
315                result.extend(program_id);
316            }
317            // Reverse the result to get the correct order.
318            result.reverse();
319            result
320        }
321
322        // A helper function to run the test.
323        fn run_test(expected_depth: usize, input: Vec<u8>, expected_error: bool) {
324            // Parse the input string.
325            let result = Future::<CurrentNetwork>::read_le(&*input);
326            // // Check if the result is an error.
327            match expected_error {
328                true => {
329                    assert!(result.is_err());
330                    return;
331                }
332                false => assert!(result.is_ok()),
333            };
334            // Unwrap the result.
335            let candidate = result.unwrap();
336            // Check if the candidate is equal to the input, with whitespace removed.
337            assert_eq!(input, candidate.to_bytes_le().unwrap());
338            // Check if the candidate is equal to the expected depth.
339            assert_eq!(get_depth(&candidate), expected_depth);
340        }
341
342        // Initialize a sequence of depths to check.
343        // Note: It is not possible to create a `Future` of depth 4000 in this test as it's size would exceed `u16::MAX`.
344        let mut depths = (0usize..100).collect_vec();
345        depths.extend((100..3900).step_by(100));
346
347        // Test deeply nested arrays with different literal types.
348        for i in depths.iter().copied() {
349            run_test(i, create_nested_future(i), i > CurrentNetwork::MAX_DATA_DEPTH);
350            run_test(i, create_nested_future(i), i > CurrentNetwork::MAX_DATA_DEPTH);
351            run_test(i, create_nested_future(i), i > CurrentNetwork::MAX_DATA_DEPTH);
352            run_test(i, create_nested_future(i), i > CurrentNetwork::MAX_DATA_DEPTH);
353        }
354    }
355}