1use blockstore::block::CidError;
10use bytes::{BufMut, BytesMut};
11use celestia_proto::shwap::{RowNamespaceData as RawRowNamespaceData, Share as RawShare};
12use cid::CidGeneric;
13use multihash::Multihash;
14use prost::Message;
15use serde::{Deserialize, Serialize};
16
17use crate::nmt::{NS_SIZE, Namespace, NamespaceProof};
18use crate::row::{ROW_ID_SIZE, RowId};
19use crate::{DataAvailabilityHeader, Error, Result, Share, bail_validation};
20
21pub const ROW_NAMESPACE_DATA_ID_SIZE: usize = ROW_ID_SIZE + NS_SIZE;
23pub const ROW_NAMESPACE_DATA_ID_MULTIHASH_CODE: u64 = 0x7821;
25pub const ROW_NAMESPACE_DATA_CODEC: u64 = 0x7820;
27
28#[derive(Debug, PartialEq, Clone, Copy)]
34pub struct RowNamespaceDataId {
35 row_id: RowId,
36 namespace: Namespace,
37}
38
39#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
44#[serde(into = "RawRowNamespaceData", try_from = "RawRowNamespaceData")]
45pub struct RowNamespaceData {
46 pub proof: NamespaceProof,
48 #[serde(deserialize_with = "celestia_proto::serializers::null_default::deserialize")]
50 pub shares: Vec<Share>,
51}
52
53impl RowNamespaceData {
54 pub fn verify(&self, id: RowNamespaceDataId, dah: &DataAvailabilityHeader) -> Result<()> {
82 if (self.shares.is_empty() && self.proof.is_of_presence())
83 || (!self.shares.is_empty() && self.proof.is_of_absence())
84 {
85 return Err(Error::WrongProofType);
86 }
87
88 let namespace = id.namespace();
89 let row = id.row_index();
90 let root = dah.row_root(row).ok_or(Error::EdsIndexOutOfRange(row, 0))?;
91
92 self.proof
93 .verify_complete_namespace(&root, &self.shares, *namespace)
94 .map_err(Error::RangeProofError)
95 }
96
97 pub fn encode(&self, bytes: &mut BytesMut) {
99 let raw = RawRowNamespaceData::from(self.clone());
100
101 bytes.reserve(raw.encoded_len());
102 raw.encode(bytes).expect("capacity reserved");
103 }
104
105 pub fn decode(id: RowNamespaceDataId, buffer: &[u8]) -> Result<Self> {
112 let raw = RawRowNamespaceData::decode(buffer)?;
113 Self::from_raw(id, raw)
114 }
115
116 pub fn from_raw(id: RowNamespaceDataId, namespace_data: RawRowNamespaceData) -> Result<Self> {
123 let Some(proof) = namespace_data.proof else {
124 return Err(Error::MissingProof);
125 };
126
127 let shares: Vec<_> = namespace_data
129 .shares
130 .into_iter()
131 .map(|shr| {
132 if id.namespace != Namespace::PARITY_SHARE {
133 Share::from_raw(&shr.data)
134 } else {
135 Share::parity(&shr.data)
136 }
137 })
138 .collect::<Result<_>>()?;
139
140 if !shares.iter().all(|shr| shr.namespace() == id.namespace) {
142 bail_validation!("Namespace data must have equal namespaces");
143 }
144
145 Ok(RowNamespaceData {
146 shares,
147 proof: proof.try_into()?,
148 })
149 }
150}
151
152impl From<RowNamespaceData> for RawRowNamespaceData {
153 fn from(namespaced_data: RowNamespaceData) -> RawRowNamespaceData {
154 RawRowNamespaceData {
155 shares: namespaced_data
156 .shares
157 .into_iter()
158 .map(|shr| RawShare { data: shr.to_vec() })
159 .collect(),
160 proof: Some(namespaced_data.proof.into()),
161 }
162 }
163}
164
165impl TryFrom<RawRowNamespaceData> for RowNamespaceData {
166 type Error = Error;
167
168 fn try_from(value: RawRowNamespaceData) -> std::result::Result<Self, Self::Error> {
169 let Some(proof) = value.proof else {
170 return Err(Error::MissingProof);
171 };
172 let proof = proof.try_into()?;
173
174 let mut shares = Vec::with_capacity(value.shares.len());
175 for raw_share in value.shares {
176 shares.push(Share::try_from(raw_share)?);
177 }
178 Ok(RowNamespaceData { proof, shares })
179 }
180}
181
182impl RowNamespaceDataId {
183 pub fn new(namespace: Namespace, row_index: u16, block_height: u64) -> Result<Self> {
190 Ok(Self {
191 row_id: RowId::new(row_index, block_height)?,
192 namespace,
193 })
194 }
195
196 pub fn block_height(&self) -> u64 {
198 self.row_id.block_height()
199 }
200
201 pub fn row_index(&self) -> u16 {
205 self.row_id.index()
206 }
207
208 pub fn namespace(&self) -> Namespace {
212 self.namespace
213 }
214
215 pub fn encode(&self, bytes: &mut BytesMut) {
217 bytes.reserve(ROW_NAMESPACE_DATA_ID_SIZE);
218 self.row_id.encode(bytes);
219 bytes.put(self.namespace.as_bytes());
220 }
221
222 pub fn decode(buffer: &[u8]) -> Result<Self> {
224 if buffer.len() != ROW_NAMESPACE_DATA_ID_SIZE {
225 return Err(Error::InvalidLength(
226 buffer.len(),
227 ROW_NAMESPACE_DATA_ID_SIZE,
228 ));
229 }
230
231 let (row_bytes, ns_bytes) = buffer.split_at(ROW_ID_SIZE);
232 let row_id = RowId::decode(row_bytes)?;
233 let namespace = Namespace::from_raw(ns_bytes)?;
234
235 Ok(Self { row_id, namespace })
236 }
237}
238
239impl<const S: usize> TryFrom<CidGeneric<S>> for RowNamespaceDataId {
240 type Error = CidError;
241
242 fn try_from(cid: CidGeneric<S>) -> Result<Self, Self::Error> {
243 let codec = cid.codec();
244 if codec != ROW_NAMESPACE_DATA_CODEC {
245 return Err(CidError::InvalidCidCodec(codec));
246 }
247
248 let hash = cid.hash();
249
250 let size = hash.size() as usize;
251 if size != ROW_NAMESPACE_DATA_ID_SIZE {
252 return Err(CidError::InvalidMultihashLength(size));
253 }
254
255 let code = hash.code();
256 if code != ROW_NAMESPACE_DATA_ID_MULTIHASH_CODE {
257 return Err(CidError::InvalidMultihashCode(
258 code,
259 ROW_NAMESPACE_DATA_ID_MULTIHASH_CODE,
260 ));
261 }
262
263 RowNamespaceDataId::decode(hash.digest()).map_err(|e| CidError::InvalidCid(e.to_string()))
264 }
265}
266
267impl From<RowNamespaceDataId> for CidGeneric<ROW_NAMESPACE_DATA_ID_SIZE> {
268 fn from(namespaced_data_id: RowNamespaceDataId) -> Self {
269 let mut bytes = BytesMut::with_capacity(ROW_NAMESPACE_DATA_ID_SIZE);
270 namespaced_data_id.encode(&mut bytes);
271 let mh = Multihash::wrap(ROW_NAMESPACE_DATA_ID_MULTIHASH_CODE, &bytes[..]).unwrap();
273
274 CidGeneric::new_v1(ROW_NAMESPACE_DATA_CODEC, mh)
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281 use crate::Blob;
282 use crate::consts::appconsts::AppVersion;
283 use crate::test_utils::{generate_dummy_eds, generate_eds};
284
285 #[test]
286 fn round_trip() {
287 let ns = Namespace::new_v0(&[0, 1]).unwrap();
288 let data_id = RowNamespaceDataId::new(ns, 5, 100).unwrap();
289 let cid = CidGeneric::from(data_id);
290
291 let multihash = cid.hash();
292 assert_eq!(multihash.code(), ROW_NAMESPACE_DATA_ID_MULTIHASH_CODE);
293 assert_eq!(multihash.size(), ROW_NAMESPACE_DATA_ID_SIZE as u8);
294
295 let deserialized_data_id = RowNamespaceDataId::try_from(cid).unwrap();
296 assert_eq!(data_id, deserialized_data_id);
297 }
298
299 #[test]
300 fn from_buffer() {
301 let bytes = [
302 0x01, 0xA0, 0xF0, 0x01, 0xA1, 0xF0, 0x01, 0x27, 0, 0, 0, 0, 0, 0, 0, 64, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
309 1, ];
311
312 let cid = CidGeneric::<ROW_NAMESPACE_DATA_ID_SIZE>::read_bytes(bytes.as_ref()).unwrap();
313 assert_eq!(cid.codec(), ROW_NAMESPACE_DATA_CODEC);
314 let mh = cid.hash();
315 assert_eq!(mh.code(), ROW_NAMESPACE_DATA_ID_MULTIHASH_CODE);
316 assert_eq!(mh.size(), ROW_NAMESPACE_DATA_ID_SIZE as u8);
317 let data_id = RowNamespaceDataId::try_from(cid).unwrap();
318 assert_eq!(data_id.namespace(), Namespace::new_v0(&[1]).unwrap());
319 assert_eq!(data_id.block_height(), 64);
320 assert_eq!(data_id.row_index(), 7);
321 }
322
323 #[test]
324 fn namespaced_data_id_size() {
325 assert_eq!(ROW_NAMESPACE_DATA_ID_SIZE, 39);
327
328 let data_id = RowNamespaceDataId::new(Namespace::new_v0(&[1]).unwrap(), 0, 1).unwrap();
329 let mut bytes = BytesMut::new();
330 data_id.encode(&mut bytes);
331 assert_eq!(bytes.len(), ROW_NAMESPACE_DATA_ID_SIZE);
332 }
333
334 #[test]
335 fn multihash_invalid_code() {
336 let multihash =
337 Multihash::<ROW_NAMESPACE_DATA_ID_SIZE>::wrap(888, &[0; ROW_NAMESPACE_DATA_ID_SIZE])
338 .unwrap();
339 let cid =
340 CidGeneric::<ROW_NAMESPACE_DATA_ID_SIZE>::new_v1(ROW_NAMESPACE_DATA_CODEC, multihash);
341 let axis_err = RowNamespaceDataId::try_from(cid).unwrap_err();
342 assert_eq!(
343 axis_err,
344 CidError::InvalidMultihashCode(888, ROW_NAMESPACE_DATA_ID_MULTIHASH_CODE)
345 );
346 }
347
348 #[test]
349 fn cid_invalid_codec() {
350 let multihash = Multihash::<ROW_NAMESPACE_DATA_ID_SIZE>::wrap(
351 ROW_NAMESPACE_DATA_ID_MULTIHASH_CODE,
352 &[0; ROW_NAMESPACE_DATA_ID_SIZE],
353 )
354 .unwrap();
355 let cid = CidGeneric::<ROW_NAMESPACE_DATA_ID_SIZE>::new_v1(4321, multihash);
356 let axis_err = RowNamespaceDataId::try_from(cid).unwrap_err();
357 assert_eq!(axis_err, CidError::InvalidCidCodec(4321));
358 }
359
360 #[test]
361 fn test_roundtrip_verify() {
362 for _ in 0..5 {
364 let eds = generate_dummy_eds(2 << (rand::random::<usize>() % 8), AppVersion::V2);
365 let dah = DataAvailabilityHeader::from_eds(&eds);
366
367 let namespace = eds.share(1, 1).unwrap().namespace();
368
369 for (id, row) in eds.get_namespace_data(namespace, &dah, 1).unwrap() {
370 let mut buf = BytesMut::new();
371 row.encode(&mut buf);
372 let decoded = RowNamespaceData::decode(id, &buf).unwrap();
373
374 decoded.verify(id, &dah).unwrap();
375 }
376 }
377
378 let eds = generate_dummy_eds(2 << (rand::random::<usize>() % 8), AppVersion::V2);
380 let dah = DataAvailabilityHeader::from_eds(&eds);
381 for (id, row) in eds
382 .get_namespace_data(Namespace::PARITY_SHARE, &dah, 1)
383 .unwrap()
384 {
385 let mut buf = BytesMut::new();
386 row.encode(&mut buf);
387 let decoded = RowNamespaceData::decode(id, &buf).unwrap();
388
389 decoded.verify(id, &dah).unwrap();
390 }
391 }
392
393 #[test]
394 fn verify_absent_ns() {
395 let eds = generate_dummy_eds(2 << (rand::random::<usize>() % 8), AppVersion::V2);
397 let dah = DataAvailabilityHeader::from_eds(&eds);
398
399 let ns = Namespace::const_v0([0, 0, 0, 0, 0, 0, 0, 0, 0, 5]);
402 for (id, row) in eds.get_namespace_data(ns, &dah, 1).unwrap() {
403 assert!(row.shares.is_empty());
404 row.verify(id, &dah).unwrap();
405 }
406 }
407
408 #[test]
409 fn reconstruct_all() {
410 for _ in 0..3 {
411 let eds = generate_eds(8 << (rand::random::<usize>() % 6), AppVersion::V2);
412 let dah = DataAvailabilityHeader::from_eds(&eds);
413
414 let mut namespaces: Vec<_> = eds
415 .data_square()
416 .iter()
417 .map(|shr| shr.namespace())
418 .filter(|ns| !ns.is_reserved())
419 .collect();
420 namespaces.dedup();
421
422 let namespace_data = eds.get_namespace_data(namespaces[0], &dah, 1).unwrap();
424 assert_eq!(namespace_data.len(), 3);
425 let shares = namespace_data.iter().flat_map(|(_, row)| row.shares.iter());
426
427 let blobs = Blob::reconstruct_all(shares, AppVersion::V2).unwrap();
428 assert_eq!(blobs.len(), 2);
429
430 for ns in &namespaces[1..] {
432 let namespace_data = eds.get_namespace_data(*ns, &dah, 1).unwrap();
433 assert_eq!(namespace_data.len(), 1);
434 let shares = namespace_data.iter().flat_map(|(_, row)| row.shares.iter());
435
436 let blobs = Blob::reconstruct_all(shares, AppVersion::V2).unwrap();
437 assert_eq!(blobs.len(), 1);
438 }
439 }
440 }
441
442 #[test]
443 fn namespace_data_roundtrip() {
444 let proof = nmt_rs::nmt_proof::NamespaceProof::<
445 crate::nmt::NamespacedSha2Hasher,
446 { crate::nmt::NS_SIZE },
447 >::AbsenceProof {
448 proof: crate::nmt::Proof {
449 siblings: vec![
450 nmt_rs::NamespacedHash::new(
451 nmt_rs::NamespaceId([
452 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
453 0, 0, 0, 0, 4,
454 ]),
455 nmt_rs::NamespaceId([
456 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
457 0, 0, 0, 0, 4,
458 ]),
459 [
460 180, 43, 29, 197, 134, 127, 103, 202, 217, 240, 11, 18, 15, 47, 140,
461 136, 58, 134, 117, 174, 162, 95, 216, 114, 31, 71, 90, 238, 49, 228,
462 95, 89,
463 ],
464 ),
465 nmt_rs::NamespacedHash::new(
466 nmt_rs::NamespaceId::MAX_ID,
467 nmt_rs::NamespaceId::MAX_ID,
468 [
469 126, 112, 141, 49, 103, 177, 23, 186, 153, 245, 110, 62, 165, 4, 39,
470 125, 171, 55, 116, 176, 36, 153, 101, 171, 25, 253, 200, 61, 226, 43,
471 81, 52,
472 ],
473 ),
474 ],
475 range: 1..2,
476 },
477 ignore_max_ns: true,
478 leaf: Some(nmt_rs::NamespacedHash::new(
479 nmt_rs::NamespaceId([
480 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 111, 118, 45,
481 116, 101, 115, 116, 45, 112,
482 ]),
483 nmt_rs::NamespaceId([
484 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 111, 118, 45,
485 116, 101, 115, 116, 45, 112,
486 ]),
487 [
488 132, 118, 183, 139, 217, 27, 43, 49, 209, 15, 142, 136, 209, 205, 230, 67, 247,
489 102, 202, 206, 118, 16, 124, 41, 208, 225, 148, 103, 192, 184, 59, 155,
490 ],
491 )),
492 };
493
494 let row = RowNamespaceData {
495 proof: proof.into(),
496 shares: vec![],
497 };
498
499 let row_j = serde_json::to_value(&row).unwrap();
501 let d_from_json: RowNamespaceData = serde_json::from_value(row_j).unwrap();
502 assert_eq!(d_from_json, row);
503
504 let s_row = postcard::to_allocvec(&row).unwrap();
506 let d_row: RowNamespaceData = postcard::from_bytes(&s_row).unwrap();
507 assert_eq!(row, d_row);
508 }
509}