snarkvm_console_program/data/record/
bytes.rs

1// Copyright 2024-2025 Aleo Network Foundation
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, Private: Visibility> FromBytes for Record<N, Private> {
19    /// Reads the record from a buffer.
20    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
21        // Read the owner.
22        let owner = Owner::read_le(&mut reader)?;
23        // Read the number of entries in the record data.
24        let num_entries = u8::read_le(&mut reader)?;
25        // Read the record data.
26        let mut data = IndexMap::with_capacity(num_entries as usize);
27        for _ in 0..num_entries {
28            // Read the identifier.
29            let identifier = Identifier::<N>::read_le(&mut reader)?;
30            // Read the entry value (in 2 steps to prevent infinite recursion).
31            let num_bytes = u16::read_le(&mut reader)?;
32            // Read the entry bytes.
33            let mut bytes = Vec::new();
34            (&mut reader).take(num_bytes as u64).read_to_end(&mut bytes)?;
35            // Recover the entry value.
36            let entry = Entry::read_le(&mut bytes.as_slice())?;
37            // Add the entry.
38            data.insert(identifier, entry);
39        }
40        // Read the nonce.
41        let nonce = Group::read_le(&mut reader)?;
42
43        // Prepare the reserved entry names.
44        let reserved = [Identifier::from_str("owner").map_err(|e| error(e.to_string()))?];
45        // Ensure the entries has no duplicate names.
46        if has_duplicates(data.keys().chain(reserved.iter())) {
47            return Err(error("Duplicate entry type found in record"));
48        }
49        // Ensure the number of entries is within the maximum limit.
50        if data.len() > N::MAX_DATA_ENTRIES {
51            return Err(error("Failed to parse record: too many entries"));
52        }
53
54        Ok(Self { owner, data, nonce })
55    }
56}
57
58impl<N: Network, Private: Visibility> ToBytes for Record<N, Private> {
59    /// Writes the record to a buffer.
60    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
61        // Write the owner.
62        self.owner.write_le(&mut writer)?;
63        // Write the number of entries in the record data.
64        u8::try_from(self.data.len()).or_halt_with::<N>("Record length exceeds u8::MAX").write_le(&mut writer)?;
65        // Write each entry.
66        for (entry_name, entry_value) in &self.data {
67            // Write the entry name.
68            entry_name.write_le(&mut writer)?;
69            // Write the entry value (performed in 2 steps to prevent infinite recursion).
70            let bytes = entry_value.to_bytes_le().map_err(|e| error(e.to_string()))?;
71            // Write the number of bytes.
72            u16::try_from(bytes.len())
73                .or_halt_with::<N>("Record entry exceeds u16::MAX bytes")
74                .write_le(&mut writer)?;
75            // Write the bytes.
76            bytes.write_le(&mut writer)?;
77        }
78        // Write the nonce.
79        self.nonce.write_le(&mut writer)
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use snarkvm_console_network::MainnetV0;
87
88    type CurrentNetwork = MainnetV0;
89
90    #[test]
91    fn test_bytes() -> Result<()> {
92        // Construct a new record.
93        let expected = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::from_str(
94            "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.private, token_amount: 100u64.private, _nonce: 0group.public }",
95        )?;
96
97        // Check the byte representation.
98        let expected_bytes = expected.to_bytes_le()?;
99        assert_eq!(expected, Record::read_le(&expected_bytes[..])?);
100        Ok(())
101    }
102}