Skip to main content

snarkvm_console_program/request/
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 Request<N> {
19    /// Reads the request from a buffer.
20    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
21        // Read the version.
22        let version = u8::read_le(&mut reader)?;
23        // Validate the version.
24        if version != 1 && version != 2 {
25            return Err(error(format!("Invalid request version: {version}")));
26        }
27
28        // Read the signer.
29        let signer = FromBytes::read_le(&mut reader)?;
30        // Read the network ID.
31        let network_id = FromBytes::read_le(&mut reader)?;
32        // Read the program ID.
33        let program_id = FromBytes::read_le(&mut reader)?;
34        // Read the function name.
35        let function_name = FromBytes::read_le(&mut reader)?;
36
37        // Read the number of inputs.
38        let inputs_len = u16::read_le(&mut reader)?;
39        // Ensure the number of inputs is within bounds.
40        if inputs_len as usize > N::MAX_INPUTS {
41            return Err(error(format!(
42                "Request (from 'read_le') has too many inputs ({inputs_len} > {})",
43                N::MAX_INPUTS
44            )));
45        }
46        // Read the input IDs.
47        let input_ids = (0..inputs_len).map(|_| FromBytes::read_le(&mut reader)).collect::<Result<Vec<_>, _>>()?;
48        // Read the inputs.
49        let inputs = (0..inputs_len).map(|_| FromBytes::read_le(&mut reader)).collect::<Result<Vec<_>, _>>()?;
50
51        // Read the signature.
52        let signature = FromBytes::read_le(&mut reader)?;
53        // Read the tag secret key.
54        let sk_tag = FromBytes::read_le(&mut reader)?;
55        // Read the transition view key.
56        let tvk = FromBytes::read_le(&mut reader)?;
57        // Read the transition commitment.
58        let tcm = FromBytes::read_le(&mut reader)?;
59        // Read the signer commitment.
60        let scm = FromBytes::read_le(&mut reader)?;
61
62        // Read the dynamic flag. V1 requests are implicitly static.
63        let is_dynamic = match version {
64            1 => false,
65            2 => bool::read_le(&mut reader)?,
66            // Note that the version is validated above to be 1 or 2.
67            _ => unreachable!(),
68        };
69
70        Ok(Self::from((
71            signer,
72            network_id,
73            program_id,
74            function_name,
75            input_ids,
76            inputs,
77            signature,
78            sk_tag,
79            tvk,
80            tcm,
81            scm,
82            is_dynamic,
83        )))
84    }
85}
86
87impl<N: Network> ToBytes for Request<N> {
88    /// Writes the request to a buffer.
89    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
90        // Always write version 2.
91        // This is safe because `Request` is not persisted to the ledger so its serialized format can be changed.
92        2u8.write_le(&mut writer)?;
93        // Write the signer.
94        self.signer.write_le(&mut writer)?;
95        // Write the network ID.
96        self.network_id.write_le(&mut writer)?;
97        // Write the program ID.
98        self.program_id.write_le(&mut writer)?;
99        // Write the function name.
100        self.function_name.write_le(&mut writer)?;
101
102        // Ensure the input IDs and inputs are the same length.
103        if self.input_ids.len() != self.inputs.len() {
104            return Err(error("Invalid request: mismatching number of input IDs and inputs"));
105        }
106
107        // Write the number of inputs.
108        u16::try_from(self.input_ids.len())
109            .or_halt_with::<N>("Request inputs length exceeds u16")
110            .write_le(&mut writer)?;
111        // Write the input IDs.
112        for input_id in &self.input_ids {
113            input_id.write_le(&mut writer)?;
114        }
115        // Write the inputs.
116        for input in &self.inputs {
117            input.write_le(&mut writer)?;
118        }
119
120        // Write the signature.
121        self.signature.write_le(&mut writer)?;
122        // Write the tag secret key.
123        self.sk_tag.write_le(&mut writer)?;
124        // Write the transition view key.
125        self.tvk.write_le(&mut writer)?;
126        // Write the transition commitment.
127        self.tcm.write_le(&mut writer)?;
128        // Write the signer commitment.
129        self.scm.write_le(&mut writer)?;
130
131        // Write the dynamic flag.
132        self.is_dynamic.write_le(&mut writer)?;
133
134        Ok(())
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141
142    #[test]
143    fn test_bytes() {
144        let mut rng = TestRng::default();
145
146        for expected in test_helpers::sample_requests(&mut rng).into_iter() {
147            // Check the byte representation.
148            let expected_bytes = expected.to_bytes_le().unwrap();
149            assert_eq!(expected, Request::read_le(&expected_bytes[..]).unwrap());
150        }
151    }
152}