snarkvm_ledger_block/transaction/deployment/
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 Deployment<N> {
19    /// Reads the deployment from a buffer.
20    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
21        // Read the version and ensure the version is valid.
22        let version = match u8::read_le(&mut reader)? {
23            1 => DeploymentVersion::V1,
24            2 => DeploymentVersion::V2,
25            version => return Err(error(format!("Invalid deployment version: {version}"))),
26        };
27
28        // Read the edition.
29        let edition = u16::read_le(&mut reader)?;
30        // Read the program.
31        let program = Program::read_le(&mut reader)?;
32
33        // Read the number of entries in the bundle.
34        let num_entries = u16::read_le(&mut reader)?;
35        // Ensure the number of entries is within bounds.
36        if num_entries as usize > N::MAX_FUNCTIONS {
37            return Err(error(format!(
38                "Deployment (from 'read_le') has too many entries ({} > {})",
39                num_entries,
40                N::MAX_FUNCTIONS
41            )));
42        }
43        // Read the verifying keys.
44        let mut verifying_keys = Vec::with_capacity(num_entries as usize);
45        for _ in 0..num_entries {
46            // Read the identifier.
47            let identifier = Identifier::<N>::read_le(&mut reader)?;
48            // Read the verifying key.
49            let verifying_key = VerifyingKey::<N>::read_le(&mut reader)?;
50            // Read the certificate.
51            let certificate = Certificate::<N>::read_le(&mut reader)?;
52            // Add the entry.
53            verifying_keys.push((identifier, (verifying_key, certificate)));
54        }
55
56        // If the deployment version is 2, read the program checksum and verify it.
57        let program_checksum = match version {
58            DeploymentVersion::V1 => None,
59            DeploymentVersion::V2 => {
60                // Read the program checksum.
61                let bytes: [u8; 32] = FromBytes::read_le(&mut reader)?;
62                let checksum = bytes.map(U8::new);
63                // Verify the checksum.
64                if checksum != program.to_checksum() {
65                    return Err(error(format!(
66                        "Invalid checksum in the deployment: expected [{}], got [{}]",
67                        program.to_checksum().iter().join(", "),
68                        checksum.iter().join(", ")
69                    )));
70                }
71                Some(checksum)
72            }
73        };
74        // If the deployment version is 2, read the program owner.
75        let program_owner = match version {
76            DeploymentVersion::V1 => None,
77            DeploymentVersion::V2 => {
78                // Read the program owner.
79                let owner = Address::<N>::read_le(&mut reader)?;
80                Some(owner)
81            }
82        };
83
84        // Return the deployment.
85        Self::new(edition, program, verifying_keys, program_checksum, program_owner)
86            .map_err(|err| error(format!("{err}")))
87    }
88}
89
90impl<N: Network> ToBytes for Deployment<N> {
91    /// Writes the deployment to a buffer.
92    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
93        // Determine the version.
94        // Note: This method checks that either both or neither of the program checksum and program owner are present.
95        let version = self.version().map_err(error)?;
96        // Write the version.
97        (version as u8).write_le(&mut writer)?;
98        // Write the edition.
99        self.edition.write_le(&mut writer)?;
100        // Write the program.
101        self.program.write_le(&mut writer)?;
102        // Write the number of entries in the bundle.
103        (u16::try_from(self.verifying_keys.len()).map_err(|e| error(e.to_string()))?).write_le(&mut writer)?;
104        // Write each entry.
105        for (function_name, (verifying_key, certificate)) in &self.verifying_keys {
106            // Write the function name.
107            function_name.write_le(&mut writer)?;
108            // Write the verifying key.
109            verifying_key.write_le(&mut writer)?;
110            // Write the certificate.
111            certificate.write_le(&mut writer)?;
112        }
113        // If the deployment version is 2, write the program checksum and program owner.
114        // Note: The unwraps are safe because `Deployment::version` only returns `V2` if both the checksum and owner is present.
115        if version == DeploymentVersion::V2 {
116            // Write the bytes of the checksum.
117            for byte in &self.program_checksum.unwrap() {
118                byte.write_le(&mut writer)?;
119            }
120            // Write the bytes of the owner.
121            self.program_owner.unwrap().write_le(&mut writer)?;
122        }
123        Ok(())
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    #[test]
132    fn test_bytes() -> Result<()> {
133        let rng = &mut TestRng::default();
134
135        // Construct the deployments.
136        for expected in [
137            test_helpers::sample_deployment_v1(Uniform::rand(rng), rng),
138            test_helpers::sample_deployment_v2(Uniform::rand(rng), rng),
139        ] {
140            // Check the byte representation.
141            let expected_bytes = expected.to_bytes_le()?;
142            assert_eq!(expected, Deployment::read_le(&expected_bytes[..])?);
143        }
144
145        Ok(())
146    }
147}