snarkvm_ledger_narwhal_data/
lib.rs

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