Skip to main content

snarkvm_ledger_block/transaction/deployment/
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 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            3 => DeploymentVersion::V3,
26            version => return Err(error(format!("Invalid deployment version: {version}"))),
27        };
28
29        // Read the edition.
30        let edition = u16::read_le(&mut reader)?;
31        // Read the program.
32        let program = Program::read_le(&mut reader)?;
33
34        // Read the number of entries in the bundle.
35        let num_entries = u16::read_le(&mut reader)?;
36        // Ensure the number of entries is within bounds.
37        let max_entries = N::MAX_FUNCTIONS + N::MAX_RECORDS;
38        if num_entries as usize > max_entries {
39            return Err(error(format!(
40                "Deployment (from 'read_le') has too many entries ({num_entries} > {max_entries})"
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 V2 or V3, read the program checksum and verify it.
57        let program_checksum = match version {
58            DeploymentVersion::V1 => None,
59            DeploymentVersion::V2 | DeploymentVersion::V3 => {
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 V2, read the program owner.
75        // Note: V3 (amendments) do not have a program owner.
76        let program_owner = match version {
77            DeploymentVersion::V1 | DeploymentVersion::V3 => None,
78            DeploymentVersion::V2 => {
79                // Read the program owner.
80                let owner = Address::<N>::read_le(&mut reader)?;
81                Some(owner)
82            }
83        };
84
85        // Return the deployment.
86        Self::new(edition, program, verifying_keys, program_checksum, program_owner)
87            .map_err(|err| error(format!("{err}")))
88    }
89}
90
91impl<N: Network> ToBytes for Deployment<N> {
92    /// Writes the deployment to a buffer.
93    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
94        // Determine the version.
95        // Note: This method determines the version based on the presence of checksum and owner fields.
96        let version = self.version().map_err(error)?;
97        // Write the version.
98        (version as u8).write_le(&mut writer)?;
99        // Write the edition.
100        self.edition.write_le(&mut writer)?;
101        // Write the program.
102        self.program.write_le(&mut writer)?;
103        // Write the number of entries in the bundle.
104        (u16::try_from(self.verifying_keys.len()).map_err(|e| error(e.to_string()))?).write_le(&mut writer)?;
105        // Write each entry.
106        for (name, (verifying_key, certificate)) in &self.verifying_keys {
107            // Write the name.
108            name.write_le(&mut writer)?;
109            // Write the verifying key.
110            verifying_key.write_le(&mut writer)?;
111            // Write the certificate.
112            certificate.write_le(&mut writer)?;
113        }
114        // If the deployment version is V2 or V3, write the program checksum.
115        // Note: The unwrap is safe because `Deployment::version` only returns V2/V3 if the checksum is present.
116        if matches!(version, DeploymentVersion::V2 | DeploymentVersion::V3) {
117            // Write the bytes of the checksum.
118            for byte in &self.program_checksum.unwrap() {
119                byte.write_le(&mut writer)?;
120            }
121        }
122        // If the deployment version is V2, write the program owner.
123        // Note: The unwrap is safe because `Deployment::version` only returns V2 if the owner is present.
124        if matches!(version, DeploymentVersion::V2) {
125            self.program_owner.unwrap().write_le(&mut writer)?;
126        }
127        Ok(())
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134
135    #[test]
136    fn test_bytes() -> Result<()> {
137        let rng = &mut TestRng::default();
138
139        // Construct the deployments.
140        for expected in [
141            test_helpers::sample_deployment_v1(Uniform::rand(rng), rng),
142            test_helpers::sample_deployment_v2_without_translation_keys(Uniform::rand(rng), rng),
143            test_helpers::sample_deployment_v2_with_translation_keys(Uniform::rand(rng), rng),
144            test_helpers::sample_deployment_v3(Uniform::rand(rng), rng),
145        ] {
146            // Check the byte representation.
147            let expected_bytes = expected.to_bytes_le()?;
148            assert_eq!(expected, Deployment::read_le(&expected_bytes[..])?);
149        }
150
151        Ok(())
152    }
153}