Skip to main content

snarkvm_console_program/data/dynamic/record/
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 DynamicRecord<N> {
19    /// Reads the dynamic record from a buffer.
20    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
21        // Read the serialization format version.
22        let version = u8::read_le(&mut reader)?;
23        // Ensure the version is valid.
24        if version != 1 {
25            return Err(error("Invalid dynamic record version"));
26        }
27
28        // Read the owner.
29        let owner = Address::read_le(&mut reader)?;
30
31        // Read the root.
32        let root = Field::read_le(&mut reader)?;
33
34        // Read the nonce.
35        let nonce = Group::read_le(&mut reader)?;
36
37        // Read the record version field.
38        let version = U8::read_le(&mut reader)?;
39
40        Ok(Self::new_unchecked(owner, root, nonce, version, None))
41    }
42}
43
44impl<N: Network> ToBytes for DynamicRecord<N> {
45    /// Writes the record to a buffer.
46    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
47        // Write the serialization format version.
48        1u8.write_le(&mut writer)?;
49
50        // Write the owner.
51        self.owner.write_le(&mut writer)?;
52
53        // Write the root.
54        self.root.write_le(&mut writer)?;
55
56        // Write the nonce.
57        self.nonce.write_le(&mut writer)?;
58
59        // Write the record version field.
60        self.version.write_le(&mut writer)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use crate::{Entry, Identifier, Literal, Owner, Plaintext, Record};
68    use snarkvm_console_network::MainnetV0;
69    use snarkvm_console_types::U64;
70    use snarkvm_utilities::{TestRng, Uniform};
71
72    use core::str::FromStr;
73
74    type CurrentNetwork = MainnetV0;
75
76    /// Verifies that a dynamic record round-trips through byte serialization.
77    fn check_bytes(record: &Record<CurrentNetwork, Plaintext<CurrentNetwork>>) {
78        let expected = DynamicRecord::from_record(record).unwrap();
79        let expected_bytes = expected.to_bytes_le().unwrap();
80        let candidate = DynamicRecord::<CurrentNetwork>::read_le(&expected_bytes[..]).unwrap();
81        assert_eq!(expected.owner(), candidate.owner());
82        assert_eq!(expected.root(), candidate.root());
83        assert_eq!(expected.nonce(), candidate.nonce());
84        assert_eq!(expected.version(), candidate.version());
85    }
86
87    #[test]
88    fn test_bytes() {
89        let rng = &mut TestRng::default();
90
91        // Test with a simple record (one entry).
92        let data = indexmap::indexmap! {
93            Identifier::from_str("amount").unwrap() => Entry::Private(Plaintext::from(Literal::U64(U64::rand(rng)))),
94        };
95        let owner = Owner::Public(Address::rand(rng));
96        let record = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::from_plaintext(
97            owner,
98            data,
99            Group::rand(rng),
100            U8::new(0),
101        )
102        .unwrap();
103        check_bytes(&record);
104
105        // Test with an empty record.
106        let owner = Owner::Public(Address::rand(rng));
107        let record = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::from_plaintext(
108            owner,
109            indexmap::IndexMap::new(),
110            Group::rand(rng),
111            U8::new(0),
112        )
113        .unwrap();
114        check_bytes(&record);
115
116        // Test with multiple entries.
117        let data = indexmap::indexmap! {
118            Identifier::from_str("a").unwrap() => Entry::Private(Plaintext::from(Literal::U64(U64::rand(rng)))),
119            Identifier::from_str("b").unwrap() => Entry::Public(Plaintext::from(Literal::U64(U64::rand(rng)))),
120            Identifier::from_str("c").unwrap() => Entry::Constant(Plaintext::from(Literal::U64(U64::rand(rng)))),
121        };
122        let owner = Owner::Private(Plaintext::from(Literal::Address(Address::rand(rng))));
123        let record = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::from_plaintext(
124            owner,
125            data,
126            Group::rand(rng),
127            U8::new(0),
128        )
129        .unwrap();
130        check_bytes(&record);
131    }
132}