1use crate::PrettyPrintRecordKey;
10use crate::error::Error;
11use bytes::{BufMut, Bytes, BytesMut};
12use libp2p::kad::Record;
13use prometheus_client::encoding::EncodeLabelValue;
14use rmp_serde::Serializer;
15use serde::{Deserialize, Serialize};
16use std::fmt::Display;
17use xor_name::XorName;
18
19#[derive(
21 EncodeLabelValue, Debug, Serialize, Deserialize, Clone, Copy, Eq, PartialEq, PartialOrd, Hash,
22)]
23pub enum DataTypes {
24 Chunk,
25 GraphEntry,
26 Pointer,
27 Scratchpad,
28}
29
30impl DataTypes {
31 pub fn get_index(&self) -> u32 {
32 match self {
33 Self::Chunk => 0,
34 Self::GraphEntry => 1,
35 Self::Pointer => 2,
36 Self::Scratchpad => 3,
37 }
38 }
39
40 pub fn from_index(index: u32) -> Option<Self> {
41 match index {
42 0 => Some(Self::Chunk),
43 1 => Some(Self::GraphEntry),
44 2 => Some(Self::Pointer),
45 3 => Some(Self::Scratchpad),
46 _ => None,
47 }
48 }
49}
50
51#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, PartialOrd, Hash)]
55pub enum ValidationType {
56 Chunk,
57 NonChunk(XorName),
58}
59
60#[derive(Debug, Serialize, Deserialize)]
61pub struct RecordHeader {
62 pub kind: RecordKind,
63}
64
65#[derive(Debug, Eq, PartialEq, Clone, Copy)]
67pub enum RecordKind {
68 DataOnly(DataTypes),
69 DataWithPayment(DataTypes),
70 DataWithMerklePayment(DataTypes),
73}
74
75pub const RECORD_KIND_PAYMENT_STARTING_INDEX: u32 = 10;
77
78pub const RECORD_KIND_MERKLE_PAYMENT_STARTING_INDEX: u32 = 20;
80
81impl Serialize for RecordKind {
82 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83 where
84 S: serde::Serializer,
85 {
86 let index = match self {
87 Self::DataOnly(data_types) => data_types.get_index(),
88 Self::DataWithPayment(data_types) => {
89 RECORD_KIND_PAYMENT_STARTING_INDEX + data_types.get_index()
90 }
91 Self::DataWithMerklePayment(data_types) => {
92 RECORD_KIND_MERKLE_PAYMENT_STARTING_INDEX + data_types.get_index()
93 }
94 };
95 serializer.serialize_u32(index)
96 }
97}
98
99impl<'de> Deserialize<'de> for RecordKind {
100 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
101 where
102 D: serde::Deserializer<'de>,
103 {
104 let num = u32::deserialize(deserializer)?;
105
106 let (kind_type, data_type_index) = if num < RECORD_KIND_PAYMENT_STARTING_INDEX {
107 ("DataOnly", num)
108 } else if num < RECORD_KIND_MERKLE_PAYMENT_STARTING_INDEX {
109 ("DataWithPayment", num - RECORD_KIND_PAYMENT_STARTING_INDEX)
110 } else {
111 (
112 "DataWithMerklePayment",
113 num - RECORD_KIND_MERKLE_PAYMENT_STARTING_INDEX,
114 )
115 };
116
117 let data_type = DataTypes::from_index(data_type_index).ok_or_else(|| {
118 serde::de::Error::custom(format!("Unexpected index {num} for RecordKind variant"))
119 })?;
120
121 Ok(match kind_type {
122 "DataOnly" => Self::DataOnly(data_type),
123 "DataWithPayment" => Self::DataWithPayment(data_type),
124 "DataWithMerklePayment" => Self::DataWithMerklePayment(data_type),
125 _ => unreachable!(),
126 })
127 }
128}
129impl Display for RecordKind {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 write!(f, "RecordKind({self:?})")
132 }
133}
134
135impl RecordHeader {
136 pub const SIZE: usize = 2;
137
138 pub fn try_serialize(self) -> Result<BytesMut, Error> {
139 let bytes = BytesMut::new();
140 let mut buf = bytes.writer();
141
142 self.serialize(&mut Serializer::new(&mut buf))
143 .map_err(|err| {
144 error!("Failed to serialized RecordHeader {self:?} with error: {err:?}");
145 Error::RecordHeaderParsingFailed
146 })?;
147
148 let b = buf.into_inner();
149
150 Ok(b)
151 }
152
153 pub fn try_deserialize(bytes: &[u8]) -> Result<Self, Error> {
154 rmp_serde::from_slice(bytes).map_err(|err| {
155 error!("Failed to deserialize RecordHeader with error: {err:?}");
156 Error::RecordHeaderParsingFailed
157 })
158 }
159
160 pub fn from_record(record: &Record) -> Result<Self, Error> {
161 if record.value.len() < RecordHeader::SIZE + 1 {
162 return Err(Error::RecordHeaderParsingFailed);
163 }
164 Self::try_deserialize(&record.value[..RecordHeader::SIZE + 1])
165 }
166
167 pub fn is_record_of_type_chunk(record: &Record) -> Result<bool, Error> {
168 let kind = Self::from_record(record)?.kind;
169 Ok(kind == RecordKind::DataOnly(DataTypes::Chunk))
170 }
171
172 pub fn get_data_type(record: &Record) -> Result<DataTypes, Error> {
173 let kind = Self::from_record(record)?.kind;
174 match kind {
175 RecordKind::DataOnly(data_type)
176 | RecordKind::DataWithPayment(data_type)
177 | RecordKind::DataWithMerklePayment(data_type) => Ok(data_type),
178 }
179 }
180}
181
182pub fn try_deserialize_record<T: serde::de::DeserializeOwned>(record: &Record) -> Result<T, Error> {
185 let bytes = if record.value.len() > RecordHeader::SIZE {
186 &record.value[RecordHeader::SIZE..]
187 } else {
188 return Err(Error::RecordParsingFailed);
189 };
190 rmp_serde::from_slice(bytes).map_err(|err| {
191 error!(
192 "Failed to deserialized record {} with error: {err:?}",
193 PrettyPrintRecordKey::from(&record.key)
194 );
195 Error::RecordParsingFailed
196 })
197}
198
199pub fn try_serialize_record<T: serde::Serialize>(
202 data: &T,
203 record_kind: RecordKind,
204) -> Result<Bytes, Error> {
205 let mut buf = RecordHeader { kind: record_kind }.try_serialize()?.writer();
206 data.serialize(&mut Serializer::new(&mut buf))
207 .map_err(|err| {
208 error!("Failed to serialized Records with error: {err:?}");
209 Error::RecordParsingFailed
210 })?;
211 let bytes = buf.into_inner();
212 Ok(bytes.freeze())
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218 use crate::error::Result;
219
220 #[test]
221 fn verify_record_header_encoded_size() -> Result<()> {
222 let chunk_with_payment = RecordHeader {
223 kind: RecordKind::DataWithPayment(DataTypes::Chunk),
224 }
225 .try_serialize()?;
226 assert_eq!(chunk_with_payment.len(), RecordHeader::SIZE);
227
228 let chunk = RecordHeader {
229 kind: RecordKind::DataOnly(DataTypes::Chunk),
230 }
231 .try_serialize()?;
232 assert_eq!(chunk.len(), RecordHeader::SIZE);
233
234 let graphentry = RecordHeader {
235 kind: RecordKind::DataOnly(DataTypes::GraphEntry),
236 }
237 .try_serialize()?;
238 assert_eq!(graphentry.len(), RecordHeader::SIZE);
239
240 let scratchpad = RecordHeader {
241 kind: RecordKind::DataOnly(DataTypes::Scratchpad),
242 }
243 .try_serialize()?;
244 assert_eq!(scratchpad.len(), RecordHeader::SIZE);
245
246 let scratchpad_with_payment = RecordHeader {
247 kind: RecordKind::DataWithPayment(DataTypes::Scratchpad),
248 }
249 .try_serialize()?;
250 assert_eq!(scratchpad_with_payment.len(), RecordHeader::SIZE);
251
252 let pointer = RecordHeader {
253 kind: RecordKind::DataOnly(DataTypes::Pointer),
254 }
255 .try_serialize()?;
256 assert_eq!(pointer.len(), RecordHeader::SIZE);
257
258 let pointer_with_payment = RecordHeader {
259 kind: RecordKind::DataWithPayment(DataTypes::Pointer),
260 }
261 .try_serialize()?;
262 assert_eq!(pointer_with_payment.len(), RecordHeader::SIZE);
263
264 let chunk_with_merkle_payment = RecordHeader {
266 kind: RecordKind::DataWithMerklePayment(DataTypes::Chunk),
267 }
268 .try_serialize()?;
269 assert_eq!(chunk_with_merkle_payment.len(), RecordHeader::SIZE);
270
271 let graphentry_with_merkle_payment = RecordHeader {
272 kind: RecordKind::DataWithMerklePayment(DataTypes::GraphEntry),
273 }
274 .try_serialize()?;
275 assert_eq!(graphentry_with_merkle_payment.len(), RecordHeader::SIZE);
276
277 let pointer_with_merkle_payment = RecordHeader {
278 kind: RecordKind::DataWithMerklePayment(DataTypes::Pointer),
279 }
280 .try_serialize()?;
281 assert_eq!(pointer_with_merkle_payment.len(), RecordHeader::SIZE);
282
283 let scratchpad_with_merkle_payment = RecordHeader {
284 kind: RecordKind::DataWithMerklePayment(DataTypes::Scratchpad),
285 }
286 .try_serialize()?;
287 assert_eq!(scratchpad_with_merkle_payment.len(), RecordHeader::SIZE);
288
289 Ok(())
290 }
291
292 #[test]
293 fn test_record_kind_serialization() -> Result<()> {
294 let kinds = vec![
295 RecordKind::DataOnly(DataTypes::Chunk),
296 RecordKind::DataWithPayment(DataTypes::Chunk),
297 RecordKind::DataWithMerklePayment(DataTypes::Chunk),
298 RecordKind::DataOnly(DataTypes::GraphEntry),
299 RecordKind::DataWithPayment(DataTypes::GraphEntry),
300 RecordKind::DataWithMerklePayment(DataTypes::GraphEntry),
301 RecordKind::DataOnly(DataTypes::Scratchpad),
302 RecordKind::DataWithPayment(DataTypes::Scratchpad),
303 RecordKind::DataWithMerklePayment(DataTypes::Scratchpad),
304 RecordKind::DataOnly(DataTypes::Pointer),
305 RecordKind::DataWithPayment(DataTypes::Pointer),
306 RecordKind::DataWithMerklePayment(DataTypes::Pointer),
307 ];
308
309 for kind in kinds {
310 let header = RecordHeader { kind };
311 let header2 = RecordHeader { kind };
312
313 let serialized = header.try_serialize()?;
314 let deserialized = RecordHeader::try_deserialize(&serialized)?;
315 assert_eq!(header2.kind, deserialized.kind);
316 }
317
318 Ok(())
319 }
320
321 #[test]
322 fn test_merkle_payment_record_kind_indices() -> Result<()> {
323 let test_cases = vec![
325 (RecordKind::DataWithMerklePayment(DataTypes::Chunk), 20u32),
326 (
327 RecordKind::DataWithMerklePayment(DataTypes::GraphEntry),
328 21u32,
329 ),
330 (RecordKind::DataWithMerklePayment(DataTypes::Pointer), 22u32),
331 (
332 RecordKind::DataWithMerklePayment(DataTypes::Scratchpad),
333 23u32,
334 ),
335 ];
336
337 for (kind, expected_index) in test_cases {
338 let header = RecordHeader { kind };
339 let serialized = header.try_serialize()?;
340
341 let deserialized = RecordHeader::try_deserialize(&serialized)?;
345
346 match (kind, deserialized.kind) {
348 (
349 RecordKind::DataWithMerklePayment(expected_type),
350 RecordKind::DataWithMerklePayment(actual_type),
351 ) => {
352 assert_eq!(expected_type, actual_type);
353 let actual_index =
355 RECORD_KIND_MERKLE_PAYMENT_STARTING_INDEX + actual_type.get_index();
356 assert_eq!(
357 actual_index, expected_index,
358 "RecordKind {kind:?} should serialize to index {expected_index}"
359 );
360 }
361 _ => panic!("Expected DataWithMerklePayment variant"),
362 }
363 }
364
365 Ok(())
366 }
367
368 #[test]
369 fn test_record_kind_index_ranges() -> Result<()> {
370 assert_eq!(
372 RecordKind::DataOnly(DataTypes::Chunk),
373 RecordHeader::try_deserialize(
374 &RecordHeader {
375 kind: RecordKind::DataOnly(DataTypes::Chunk)
376 }
377 .try_serialize()?
378 )?
379 .kind
380 );
381
382 assert_eq!(
384 RecordKind::DataWithPayment(DataTypes::Chunk),
385 RecordHeader::try_deserialize(
386 &RecordHeader {
387 kind: RecordKind::DataWithPayment(DataTypes::Chunk)
388 }
389 .try_serialize()?
390 )?
391 .kind
392 );
393
394 assert_eq!(
396 RecordKind::DataWithMerklePayment(DataTypes::Chunk),
397 RecordHeader::try_deserialize(
398 &RecordHeader {
399 kind: RecordKind::DataWithMerklePayment(DataTypes::Chunk)
400 }
401 .try_serialize()?
402 )?
403 .kind
404 );
405
406 Ok(())
407 }
408
409 #[test]
410 fn test_merkle_payment_roundtrip() -> Result<()> {
411 let data_types = vec![
413 DataTypes::Chunk,
414 DataTypes::GraphEntry,
415 DataTypes::Pointer,
416 DataTypes::Scratchpad,
417 ];
418
419 for data_type in data_types {
420 let original = RecordKind::DataWithMerklePayment(data_type);
421 let header = RecordHeader { kind: original };
422
423 let serialized = header.try_serialize()?;
424 let deserialized = RecordHeader::try_deserialize(&serialized)?;
425
426 assert_eq!(
427 original, deserialized.kind,
428 "Merkle payment variant for {data_type:?} should roundtrip correctly"
429 );
430 }
431
432 Ok(())
433 }
434}