Skip to main content

snarkvm_ledger_narwhal_data/
lib.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
16extern crate snarkvm_console as console;
17
18use console::prelude::*;
19
20use ::bytes::Bytes;
21
22#[cfg(feature = "async")]
23use tokio::task;
24
25const PREFIX: &str = "data";
26
27/// As a sanity check, we set a hardcoded upper-bound limit to the size of the data.
28/// This is to prevent a malicious node from sending us a huge data object that would
29/// cause us to run out of memory.
30const MAX_DATA_SIZE: u32 = 1024 * 1024 * 1024; // 1 GB
31
32/// This object enables deferred deserialization / ahead-of-time serialization for objects that
33/// take a while to deserialize / serialize, in order to allow these operations to be non-blocking.
34#[derive(Clone, PartialEq, Eq)]
35pub enum Data<T: FromBytes + ToBytes + Send + 'static> {
36    Object(T),
37    Buffer(Bytes),
38}
39
40impl<T: FromBytes + ToBytes + Send + 'static> Data<T> {
41    pub fn to_checksum<N: Network>(&self) -> Result<N::TransmissionChecksum> {
42        // Convert to bits.
43        let preimage = match self {
44            Self::Object(object) => object.to_bytes_le()?.to_bits_le(),
45            Self::Buffer(bytes) => bytes.deref().to_bits_le(),
46        };
47        // Hash the preimage bits.
48        let hash = N::hash_sha3_256(&preimage)?;
49        // Select the number of bits needed to parse the checksum.
50        let num_bits = usize::try_from(N::TransmissionChecksum::BITS).map_err(error)?;
51        // Return the checksum.
52        N::TransmissionChecksum::from_bits_le(&hash[0..num_bits])
53    }
54
55    pub fn into<T2: From<Data<T>> + From<T> + FromBytes + ToBytes + Send + 'static>(self) -> Data<T2> {
56        match self {
57            Self::Object(x) => Data::Object(x.into()),
58            Self::Buffer(bytes) => Data::Buffer(bytes),
59        }
60    }
61
62    #[cfg(feature = "async")]
63    pub async fn deserialize(self) -> Result<T> {
64        match self {
65            Self::Object(x) => Ok(x),
66            Self::Buffer(bytes) => match task::spawn_blocking(move || T::from_bytes_le(&bytes)).await {
67                Ok(x) => x,
68                Err(err) => Err(err.into()),
69            },
70        }
71    }
72
73    pub fn deserialize_blocking(self) -> Result<T> {
74        match self {
75            Self::Object(x) => Ok(x),
76            Self::Buffer(bytes) => T::from_bytes_le(&bytes),
77        }
78    }
79
80    #[cfg(feature = "async")]
81    pub async fn serialize(self) -> Result<Bytes> {
82        match self {
83            Self::Object(x) => match task::spawn_blocking(move || x.to_bytes_le()).await {
84                Ok(bytes) => bytes.map(|vec| vec.into()),
85                Err(err) => Err(err.into()),
86            },
87            Self::Buffer(bytes) => Ok(bytes),
88        }
89    }
90
91    pub fn serialize_blocking_into<W: Write>(&self, writer: &mut W) -> Result<()> {
92        match self {
93            Self::Object(x) => Ok(x.write_le(writer)?),
94            Self::Buffer(bytes) => Ok(writer.write_all(bytes)?),
95        }
96    }
97}
98
99impl<T: FromBytes + ToBytes + DeserializeOwned + Send + 'static> FromStr for Data<T> {
100    type Err = Error;
101
102    /// Initializes the data from a JSON-string.
103    fn from_str(data: &str) -> Result<Self, Self::Err> {
104        Ok(serde_json::from_str(data)?)
105    }
106}
107
108impl<T: FromBytes + ToBytes + Serialize + Send + 'static> Debug for Data<T> {
109    /// Prints the data as a JSON-string.
110    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
111        Display::fmt(self, f)
112    }
113}
114
115impl<T: FromBytes + ToBytes + Serialize + Send + 'static> Display for Data<T> {
116    /// Displays the data as a JSON-string.
117    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
118        write!(f, "{}", serde_json::to_string(self).map_err::<fmt::Error, _>(ser::Error::custom)?)
119    }
120}
121
122impl<T: FromBytes + ToBytes + Send + 'static> FromBytes for Data<T> {
123    /// Reads the data from the buffer.
124    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
125        // Read the version.
126        let version = u8::read_le(&mut reader)?;
127        // Ensure the version is valid.
128        if version != 1 {
129            return Err(error("Invalid data version"));
130        }
131
132        // Read the number of bytes.
133        let num_bytes = u32::read_le(&mut reader)?;
134        // Ensure the number of bytes is with safe bound limits.
135        if num_bytes > MAX_DATA_SIZE {
136            return Err(error(format!("Failed to deserialize data ({num_bytes} bytes)")));
137        }
138        // Read the bytes.
139        let mut bytes = Vec::new();
140        (&mut reader).take(num_bytes as u64).read_to_end(&mut bytes)?;
141        // Return the data.
142        Ok(Self::Buffer(Bytes::from(bytes)))
143    }
144}
145
146impl<T: FromBytes + ToBytes + Send + 'static> ToBytes for Data<T> {
147    /// Writes the data to the buffer.
148    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
149        // Write the version.
150        1u8.write_le(&mut writer)?;
151
152        // Write the data.
153        match self {
154            Self::Object(object) => {
155                // Serialize the object.
156                let buffer =
157                    object.to_bytes_le().map_err(|e| error(format!("Failed to serialize 'Data::Object' - {e}")))?;
158                // Write the object.
159                u32::try_from(buffer.len()).map_err(error)?.write_le(&mut writer)?;
160                // Write the object.
161                writer.write_all(&buffer)
162            }
163            Self::Buffer(buffer) => {
164                // Write the number of bytes.
165                u32::try_from(buffer.len()).map_err(error)?.write_le(&mut writer)?;
166                // Write the bytes.
167                writer.write_all(buffer)
168            }
169        }
170    }
171}
172
173impl<T: FromBytes + ToBytes + Serialize + Send + 'static> Serialize for Data<T> {
174    /// Serializes the data to a JSON-string or buffer.
175    #[inline]
176    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
177        match serializer.is_human_readable() {
178            true => {
179                let mut data = serializer.serialize_struct("Data", 2)?;
180                match self {
181                    Self::Object(object) => {
182                        data.serialize_field("type", "object")?;
183                        data.serialize_field("data", object)?;
184                    }
185                    Self::Buffer(buffer) => {
186                        use console::prelude::ser::Error;
187
188                        data.serialize_field("type", "buffer")?;
189
190                        // Encode to bech32m.
191                        let buffer = bech32::encode(PREFIX, buffer.to_vec().to_base32(), bech32::Variant::Bech32m)
192                            .map_err(|_| S::Error::custom("Failed to encode data into bech32m"))?;
193
194                        // Add the bech32m string.
195                        data.serialize_field("data", &buffer)?;
196                    }
197                }
198                data.end()
199            }
200            false => ToBytesSerializer::serialize_with_size_encoding(self, serializer),
201        }
202    }
203}
204
205impl<'de, T: FromBytes + ToBytes + DeserializeOwned + Send + 'static> Deserialize<'de> for Data<T> {
206    /// Deserializes the data from a JSON-string or buffer.
207    #[inline]
208    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
209        match deserializer.is_human_readable() {
210            true => {
211                let mut data = serde_json::Value::deserialize(deserializer)?;
212                let type_: String = DeserializeExt::take_from_value::<D>(&mut data, "type")?;
213
214                // Recover the data.
215                match type_.as_str() {
216                    "object" => {
217                        let object = DeserializeExt::take_from_value::<D>(&mut data, "data")?;
218                        Ok(Self::Object(object))
219                    }
220                    "buffer" => {
221                        let encoding: String = DeserializeExt::take_from_value::<D>(&mut data, "data")?;
222
223                        // Decode from bech32m.
224                        let (hrp, data, variant) = bech32::decode(&encoding).map_err(de::Error::custom)?;
225                        if hrp != PREFIX {
226                            return Err(de::Error::custom(error(format!("Invalid data HRP - {hrp}"))));
227                        };
228                        if data.is_empty() {
229                            return Err(de::Error::custom(error("Invalid bech32m data (empty)")));
230                        }
231                        if variant != bech32::Variant::Bech32m {
232                            return Err(de::Error::custom(error("Invalid data - variant is not bech32m")));
233                        }
234                        Ok(Self::Buffer(Bytes::from(Vec::from_base32(&data).map_err(de::Error::custom)?)))
235                    }
236                    _ => Err(de::Error::custom(error(format!("Invalid data type - {type_}")))),
237                }
238            }
239            false => FromBytesDeserializer::<Self>::deserialize_with_size_encoding(deserializer, "data"),
240        }
241    }
242}
243
244#[cfg(test)]
245mod tests {
246    use super::*;
247    use console::network::MainnetV0;
248    use snarkvm_ledger_block::Transaction;
249
250    #[test]
251    fn test_to_checksum() {
252        let rng = &mut TestRng::default();
253
254        // Sample transactions
255        let transactions = [
256            snarkvm_ledger_test_helpers::sample_deployment_transaction(1, Uniform::rand(rng), true, rng),
257            snarkvm_ledger_test_helpers::sample_deployment_transaction(1, Uniform::rand(rng), false, rng),
258            snarkvm_ledger_test_helpers::sample_deployment_transaction(2, Uniform::rand(rng), true, rng),
259            snarkvm_ledger_test_helpers::sample_deployment_transaction(2, Uniform::rand(rng), false, rng),
260            snarkvm_ledger_test_helpers::sample_execution_transaction_with_fee(true, rng, 0),
261            snarkvm_ledger_test_helpers::sample_execution_transaction_with_fee(false, rng, 0),
262            snarkvm_ledger_test_helpers::sample_fee_private_transaction(rng),
263            snarkvm_ledger_test_helpers::sample_fee_public_transaction(rng),
264        ];
265
266        for transaction in transactions.into_iter() {
267            // Convert the transaction to a Data buffer.
268            let data_bytes: Data<Transaction<MainnetV0>> = Data::Buffer(transaction.to_bytes_le().unwrap().into());
269            // Convert the transaction to a data object.
270            let data = Data::Object(transaction);
271
272            // Compute the checksums.
273            let checksum_1 = data_bytes.to_checksum::<MainnetV0>().unwrap();
274            let checksum_2 = data.to_checksum::<MainnetV0>().unwrap();
275
276            // Ensure the checksums are equal.
277            assert_eq!(checksum_1, checksum_2);
278        }
279    }
280}