1use std::cmp::Ordering;
4use std::fmt::Display;
5
6use bytes::{Buf, BufMut, BytesMut};
7use serde::{Deserialize, Serialize};
8
9use crate::consts::appconsts::{AppVersion, SHARE_SIZE};
10use crate::consts::data_availability_header::{
11 MIN_EXTENDED_SQUARE_WIDTH, max_extended_square_width,
12};
13use crate::nmt::{NS_SIZE, Namespace, Nmt, NmtExt};
14use crate::row_namespace_data::{RowNamespaceData, RowNamespaceDataId};
15use crate::{DataAvailabilityHeader, Error, InfoByte, Result, Share, bail_validation};
16
17pub const EDS_ID_SIZE: usize = 8;
19
20#[derive(Debug, PartialEq, Clone, Copy)]
27pub struct EdsId {
28 height: u64,
29}
30
31#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
35#[repr(u8)]
36pub enum AxisType {
37 Row = 0,
39 Col,
41}
42
43impl TryFrom<i32> for AxisType {
44 type Error = Error;
45
46 fn try_from(value: i32) -> Result<Self, Self::Error> {
47 match value {
48 0 => Ok(AxisType::Row),
49 1 => Ok(AxisType::Col),
50 n => Err(Error::InvalidAxis(n)),
51 }
52 }
53}
54
55impl Display for AxisType {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 AxisType::Row => write!(f, "Row"),
59 AxisType::Col => write!(f, "Column"),
60 }
61 }
62}
63
64#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
149#[serde(into = "RawExtendedDataSquare")]
150pub struct ExtendedDataSquare {
151 data_square: Vec<Share>,
153 codec: String,
155 square_width: u16,
157}
158
159impl ExtendedDataSquare {
160 pub fn new(shares: Vec<Vec<u8>>, codec: String, app_version: AppVersion) -> Result<Self> {
175 const MIN_SHARES: usize = MIN_EXTENDED_SQUARE_WIDTH * MIN_EXTENDED_SQUARE_WIDTH;
176
177 let max_extended_square_width = max_extended_square_width(app_version);
178 let max_shares = max_extended_square_width * max_extended_square_width;
179
180 if shares.len() < MIN_SHARES {
181 bail_validation!(
182 "shares len ({}) < MIN_SHARES ({})",
183 shares.len(),
184 MIN_SHARES
185 );
186 }
187 if shares.len() > max_shares {
188 bail_validation!(
189 "shares len ({}) > max shares ({})",
190 shares.len(),
191 max_shares
192 );
193 }
194
195 let square_width = f64::sqrt(shares.len() as f64) as usize;
196
197 if square_width * square_width != shares.len() {
198 return Err(Error::EdsInvalidDimentions);
199 }
200
201 let square_width = u16::try_from(square_width).map_err(|_| Error::EdsInvalidDimentions)?;
202
203 if square_width.count_ones() != 1 {
205 return Err(Error::EdsInvalidDimentions);
206 }
207
208 let check_share = |row, col, prev_ns: Option<Namespace>, axis| -> Result<Share> {
209 let idx = flatten_index(row, col, square_width);
210 let share = if is_ods_square(row, col, square_width) {
211 Share::from_raw(&shares[idx])?
212 } else {
213 Share::parity(&shares[idx])?
214 };
215 share.validate(app_version)?;
216
217 if prev_ns.is_some_and(|prev_ns| share.namespace() < prev_ns) {
218 let axis_idx = match axis {
219 AxisType::Row => row,
220 AxisType::Col => col,
221 };
222 bail_validation!("Shares of {axis} {axis_idx} are not sorted by their namespace");
223 }
224
225 Ok(share)
226 };
227
228 for col in 0..square_width {
230 let mut prev_ns = None;
231
232 for row in 0..square_width {
233 let share = check_share(row, col, prev_ns, AxisType::Col)?;
234 prev_ns = Some(share.namespace());
235 }
236 }
237 let mut data_square = Vec::with_capacity(shares.len());
239 for row in 0..square_width {
240 let mut prev_ns = None;
241
242 for col in 0..square_width {
243 let share = check_share(row, col, prev_ns, AxisType::Row)?;
244 prev_ns = Some(share.namespace());
245 data_square.push(share);
246 }
247 }
248
249 let eds = ExtendedDataSquare {
250 data_square,
251 codec,
252 square_width,
253 };
254
255 Ok(eds)
256 }
257
258 pub fn from_raw(raw_eds: RawExtendedDataSquare, app_version: AppVersion) -> Result<Self> {
260 ExtendedDataSquare::new(raw_eds.data_square, raw_eds.codec, app_version)
261 }
262
263 pub fn empty() -> ExtendedDataSquare {
265 let ods = vec![
267 [
268 Namespace::TAIL_PADDING.as_bytes(),
269 &[InfoByte::new(0, true).unwrap().as_u8()],
270 &[0; SHARE_SIZE - NS_SIZE - 1],
271 ]
272 .concat(),
273 ];
274
275 ExtendedDataSquare::from_ods(ods, AppVersion::V1).expect("invalid EDS")
278 }
279
280 pub fn from_ods(
294 mut ods_shares: Vec<Vec<u8>>,
295 app_version: AppVersion,
296 ) -> Result<ExtendedDataSquare> {
297 let ods_width = f64::sqrt(ods_shares.len() as f64) as usize;
298 if ods_width * ods_width != ods_shares.len() {
300 return Err(Error::EdsInvalidDimentions);
301 }
302
303 let eds_width = ods_width * 2;
304 let mut eds_shares = Vec::with_capacity(eds_width * eds_width);
305 for _ in 0..ods_width {
307 eds_shares.extend(ods_shares.drain(..ods_width));
308 for _ in 0..ods_width {
309 eds_shares.push(vec![0; SHARE_SIZE]);
310 }
311 }
312 eds_shares.resize(eds_width * eds_width, vec![0; SHARE_SIZE]);
314
315 for row in eds_shares.chunks_mut(eds_width).take(ods_width) {
317 leopard_codec::encode(row, ods_width)?;
318 }
319 for col in 0..ods_width {
321 let mut col: Vec<_> = eds_shares.iter_mut().skip(col).step_by(eds_width).collect();
322 leopard_codec::encode(&mut col, ods_width)?;
323 }
324 for row in eds_shares.chunks_mut(eds_width).skip(ods_width) {
326 leopard_codec::encode(row, ods_width)?;
327 }
328
329 ExtendedDataSquare::new(eds_shares, "Leopard".to_string(), app_version)
330 }
331
332 pub fn data_square(&self) -> &[Share] {
334 &self.data_square
335 }
336
337 pub fn codec(&self) -> &str {
339 self.codec.as_str()
340 }
341
342 pub fn share(&self, row: u16, column: u16) -> Result<&Share> {
344 let index = usize::from(row) * usize::from(self.square_width) + usize::from(column);
345
346 self.data_square
347 .get(index)
348 .ok_or(Error::EdsIndexOutOfRange(row, column))
349 }
350
351 #[cfg(any(test, feature = "test-utils"))]
353 pub(crate) fn share_mut(&mut self, row: u16, column: u16) -> Result<&mut Share> {
354 let index = flatten_index(row, column, self.square_width);
355
356 self.data_square
357 .get_mut(index)
358 .ok_or(Error::EdsIndexOutOfRange(row, column))
359 }
360
361 pub fn row(&self, index: u16) -> Result<Vec<Share>> {
363 self.axis(AxisType::Row, index)
364 }
365
366 pub fn row_nmt(&self, index: u16) -> Result<Nmt> {
368 self.axis_nmt(AxisType::Row, index)
369 }
370
371 pub fn column(&self, index: u16) -> Result<Vec<Share>> {
373 self.axis(AxisType::Col, index)
374 }
375
376 pub fn column_nmt(&self, index: u16) -> Result<Nmt> {
378 self.axis_nmt(AxisType::Col, index)
379 }
380
381 pub fn axis(&self, axis: AxisType, index: u16) -> Result<Vec<Share>> {
383 (0..self.square_width)
384 .map(|i| {
385 let (row, col) = match axis {
386 AxisType::Row => (index, i),
387 AxisType::Col => (i, index),
388 };
389
390 self.share(row, col).map(ToOwned::to_owned)
391 })
392 .collect()
393 }
394
395 pub fn axis_nmt(&self, axis: AxisType, index: u16) -> Result<Nmt> {
397 let mut tree = Nmt::default();
398
399 for i in 0..self.square_width {
400 let (row, col) = match axis {
401 AxisType::Row => (index, i),
402 AxisType::Col => (i, index),
403 };
404
405 let share = self.share(row, col)?;
406
407 tree.push_leaf(share.as_ref(), *share.namespace())
408 .map_err(Error::Nmt)?;
409 }
410
411 Ok(tree)
412 }
413
414 pub fn square_width(&self) -> u16 {
416 self.square_width
417 }
418
419 pub fn get_namespace_data(
422 &self,
423 namespace: Namespace,
424 dah: &DataAvailabilityHeader,
425 height: u64,
426 ) -> Result<Vec<(RowNamespaceDataId, RowNamespaceData)>> {
427 let mut rows = Vec::new();
428
429 for row in 0..self.square_width {
430 if !dah.row_contains(row, namespace)? {
431 continue;
432 }
433
434 let mut shares = Vec::with_capacity(self.square_width.into());
435
436 for col in 0..self.square_width {
437 let share = self.share(row, col)?;
438
439 match share.namespace().cmp(&namespace) {
442 Ordering::Less => {}
443 Ordering::Equal => shares.push(share.clone()),
444 Ordering::Greater => break,
445 }
446 }
447
448 let proof = self.row_nmt(row)?.get_namespace_proof(*namespace);
449 let id = RowNamespaceDataId::new(namespace, row, height)?;
450 let data = RowNamespaceData {
451 proof: proof.into(),
452 shares,
453 };
454
455 rows.push((id, data))
456 }
457
458 Ok(rows)
459 }
460}
461
462impl EdsId {
463 pub fn new(height: u64) -> Result<Self> {
465 if height == 0 {
466 return Err(Error::ZeroBlockHeight);
467 }
468
469 Ok(EdsId { height })
470 }
471
472 pub fn block_height(&self) -> u64 {
474 self.height
475 }
476
477 pub fn encode(&self, bytes: &mut BytesMut) {
479 bytes.reserve(EDS_ID_SIZE);
480 bytes.put_u64(self.height);
481 }
482
483 pub fn decode(mut buffer: &[u8]) -> Result<Self> {
485 if buffer.len() != EDS_ID_SIZE {
486 return Err(Error::InvalidLength(buffer.len(), EDS_ID_SIZE));
487 }
488
489 let height = buffer.get_u64();
490
491 EdsId::new(height)
492 }
493}
494
495#[derive(Serialize, Deserialize)]
497pub struct RawExtendedDataSquare {
498 #[serde(with = "tendermint_proto::serializers::bytes::vec_base64string")]
500 pub data_square: Vec<Vec<u8>>,
501 pub codec: String,
503}
504
505impl From<ExtendedDataSquare> for RawExtendedDataSquare {
506 fn from(eds: ExtendedDataSquare) -> RawExtendedDataSquare {
507 RawExtendedDataSquare {
508 data_square: eds
509 .data_square
510 .into_iter()
511 .map(|shr| shr.to_vec())
512 .collect(),
513 codec: eds.codec,
514 }
515 }
516}
517
518pub(crate) fn is_ods_square(row: u16, column: u16, square_width: u16) -> bool {
521 let ods_width = square_width / 2;
522 row < ods_width && column < ods_width
523}
524
525fn flatten_index(row: u16, col: u16, square_width: u16) -> usize {
526 usize::from(row) * usize::from(square_width) + usize::from(col)
527}
528
529#[cfg(test)]
530mod tests {
531 use super::*;
532 use crate::consts::appconsts;
533 use crate::test_utils::generate_eds;
534 use crate::{Blob, ExtendedHeader};
535
536 #[test]
537 fn axis_type_serialization() {
538 assert_eq!(AxisType::Row as u8, 0);
539 assert_eq!(AxisType::Col as u8, 1);
540 }
541
542 #[test]
543 fn axis_type_deserialization() {
544 assert_eq!(AxisType::try_from(0).unwrap(), AxisType::Row);
545 assert_eq!(AxisType::try_from(1).unwrap(), AxisType::Col);
546
547 let axis_type_err = AxisType::try_from(2).unwrap_err();
548 assert!(matches!(axis_type_err, Error::InvalidAxis(2)));
549 let axis_type_err = AxisType::try_from(99).unwrap_err();
550 assert!(matches!(axis_type_err, Error::InvalidAxis(99)));
551 }
552
553 #[test]
554 fn get_namespaced_data() {
555 let eds_json = include_str!("../test_data/shwap_samples/eds.json");
556 let raw_eds: RawExtendedDataSquare = serde_json::from_str(eds_json).unwrap();
557 let eds = ExtendedDataSquare::from_raw(raw_eds, AppVersion::V2).unwrap();
558
559 let dah_json = include_str!("../test_data/shwap_samples/dah.json");
560 let dah: DataAvailabilityHeader = serde_json::from_str(dah_json).unwrap();
561
562 let height = 45577;
563
564 let rows = eds
565 .get_namespace_data(Namespace::new_v0(&[1, 170]).unwrap(), &dah, height)
566 .unwrap();
567 assert_eq!(rows.len(), 1);
568 let (id, row) = &rows[0];
569 row.verify(*id, &dah).unwrap();
570 assert_eq!(row.shares.len(), 2);
571
572 let rows = eds
573 .get_namespace_data(Namespace::new_v0(&[1, 187]).unwrap(), &dah, height)
574 .unwrap();
575 assert_eq!(rows.len(), 2);
576 assert_eq!(rows[0].1.shares.len(), 1);
577 assert_eq!(rows[1].1.shares.len(), 4);
578 for (id, row) in rows {
579 row.verify(id, &dah).unwrap();
580 }
581 }
582
583 #[test]
584 fn nmt_roots() {
585 let eds_json = include_str!("../test_data/shwap_samples/eds.json");
586 let raw_eds: RawExtendedDataSquare = serde_json::from_str(eds_json).unwrap();
587 let eds = ExtendedDataSquare::from_raw(raw_eds, AppVersion::V2).unwrap();
588
589 let dah_json = include_str!("../test_data/shwap_samples/dah.json");
590 let dah: DataAvailabilityHeader = serde_json::from_str(dah_json).unwrap();
591
592 assert_eq!(dah.row_roots().len(), usize::from(eds.square_width()));
593 assert_eq!(dah.column_roots().len(), usize::from(eds.square_width()));
594
595 for (i, root) in dah.row_roots().iter().enumerate() {
596 let mut tree = eds.row_nmt(i as u16).unwrap();
597 assert_eq!(*root, tree.root());
598
599 let mut tree = eds.axis_nmt(AxisType::Row, i as u16).unwrap();
600 assert_eq!(*root, tree.root());
601 }
602
603 for (i, root) in dah.column_roots().iter().enumerate() {
604 let mut tree = eds.column_nmt(i as u16).unwrap();
605 assert_eq!(*root, tree.root());
606
607 let mut tree = eds.axis_nmt(AxisType::Col, i as u16).unwrap();
608 assert_eq!(*root, tree.root());
609 }
610 }
611
612 #[test]
613 fn ods_square() {
614 assert!(is_ods_square(0, 0, 4));
615 assert!(is_ods_square(0, 1, 4));
616 assert!(is_ods_square(1, 0, 4));
617 assert!(is_ods_square(1, 1, 4));
618
619 assert!(!is_ods_square(0, 2, 4));
620 assert!(!is_ods_square(0, 3, 4));
621 assert!(!is_ods_square(1, 2, 4));
622 assert!(!is_ods_square(1, 3, 4));
623
624 assert!(!is_ods_square(2, 0, 4));
625 assert!(!is_ods_square(2, 1, 4));
626 assert!(!is_ods_square(3, 0, 4));
627 assert!(!is_ods_square(3, 1, 4));
628
629 assert!(!is_ods_square(2, 2, 4));
630 assert!(!is_ods_square(2, 3, 4));
631 assert!(!is_ods_square(3, 2, 4));
632 assert!(!is_ods_square(3, 3, 4));
633 }
634
635 #[test]
636 fn get_row_and_col() {
637 let raw_share = |x, y| {
638 [
639 Namespace::new_v0(&[x, y]).unwrap().as_bytes(),
640 &[0u8; SHARE_SIZE - NS_SIZE][..],
641 ]
642 .concat()
643 };
644 let share = |x, y, parity: bool| {
645 if !parity {
646 Share::from_raw(&raw_share(x, y)).unwrap()
647 } else {
648 Share::parity(&raw_share(x, y)).unwrap()
649 }
650 };
651
652 #[rustfmt::skip]
653 let shares = vec![
654 raw_share(0, 0), raw_share(0, 1), raw_share(0, 2), raw_share(0, 3),
655 raw_share(1, 0), raw_share(1, 1), raw_share(1, 2), raw_share(1, 3),
656 raw_share(2, 0), raw_share(2, 1), raw_share(2, 2), raw_share(2, 3),
657 raw_share(3, 0), raw_share(3, 1), raw_share(3, 2), raw_share(3, 3),
658 ];
659
660 let eds = ExtendedDataSquare::new(shares, "fake".to_string(), AppVersion::V2).unwrap();
661
662 assert_eq!(
663 eds.row(0).unwrap(),
664 vec![
665 share(0, 0, false),
666 share(0, 1, false),
667 share(0, 2, true),
668 share(0, 3, true)
669 ],
670 );
671 assert_eq!(
672 eds.row(1).unwrap(),
673 vec![
674 share(1, 0, false),
675 share(1, 1, false),
676 share(1, 2, true),
677 share(1, 3, true)
678 ],
679 );
680 assert_eq!(
681 eds.row(2).unwrap(),
682 vec![
683 share(2, 0, true),
684 share(2, 1, true),
685 share(2, 2, true),
686 share(2, 3, true)
687 ],
688 );
689 assert_eq!(
690 eds.row(3).unwrap(),
691 vec![
692 share(3, 0, true),
693 share(3, 1, true),
694 share(3, 2, true),
695 share(3, 3, true)
696 ],
697 );
698
699 assert_eq!(
700 eds.axis(AxisType::Row, 0).unwrap(),
701 vec![
702 share(0, 0, false),
703 share(0, 1, false),
704 share(0, 2, true),
705 share(0, 3, true)
706 ],
707 );
708 assert_eq!(
709 eds.axis(AxisType::Row, 1).unwrap(),
710 vec![
711 share(1, 0, false),
712 share(1, 1, false),
713 share(1, 2, true),
714 share(1, 3, true)
715 ],
716 );
717 assert_eq!(
718 eds.axis(AxisType::Row, 2).unwrap(),
719 vec![
720 share(2, 0, true),
721 share(2, 1, true),
722 share(2, 2, true),
723 share(2, 3, true)
724 ],
725 );
726 assert_eq!(
727 eds.axis(AxisType::Row, 3).unwrap(),
728 vec![
729 share(3, 0, true),
730 share(3, 1, true),
731 share(3, 2, true),
732 share(3, 3, true)
733 ],
734 );
735
736 assert_eq!(
737 eds.column(0).unwrap(),
738 vec![
739 share(0, 0, false),
740 share(1, 0, false),
741 share(2, 0, true),
742 share(3, 0, true)
743 ],
744 );
745 assert_eq!(
746 eds.column(1).unwrap(),
747 vec![
748 share(0, 1, false),
749 share(1, 1, false),
750 share(2, 1, true),
751 share(3, 1, true)
752 ],
753 );
754 assert_eq!(
755 eds.column(2).unwrap(),
756 vec![
757 share(0, 2, true),
758 share(1, 2, true),
759 share(2, 2, true),
760 share(3, 2, true)
761 ],
762 );
763 assert_eq!(
764 eds.column(3).unwrap(),
765 vec![
766 share(0, 3, true),
767 share(1, 3, true),
768 share(2, 3, true),
769 share(3, 3, true)
770 ],
771 );
772
773 assert_eq!(
774 eds.axis(AxisType::Col, 0).unwrap(),
775 vec![
776 share(0, 0, false),
777 share(1, 0, false),
778 share(2, 0, true),
779 share(3, 0, true)
780 ],
781 );
782 assert_eq!(
783 eds.axis(AxisType::Col, 1).unwrap(),
784 vec![
785 share(0, 1, false),
786 share(1, 1, false),
787 share(2, 1, true),
788 share(3, 1, true)
789 ],
790 );
791 assert_eq!(
792 eds.axis(AxisType::Col, 2).unwrap(),
793 vec![
794 share(0, 2, true),
795 share(1, 2, true),
796 share(2, 2, true),
797 share(3, 2, true)
798 ],
799 );
800 assert_eq!(
801 eds.axis(AxisType::Col, 3).unwrap(),
802 vec![
803 share(0, 3, true),
804 share(1, 3, true),
805 share(2, 3, true),
806 share(3, 3, true)
807 ],
808 );
809 }
810
811 #[test]
812 fn validation() {
813 ExtendedDataSquare::new(vec![], "fake".to_string(), AppVersion::V2).unwrap_err();
814 ExtendedDataSquare::new(vec![vec![]], "fake".to_string(), AppVersion::V2).unwrap_err();
815 ExtendedDataSquare::new(vec![vec![]; 4], "fake".to_string(), AppVersion::V2).unwrap_err();
816
817 ExtendedDataSquare::new(
818 vec![vec![0u8; SHARE_SIZE]; 4],
819 "fake".to_string(),
820 AppVersion::V2,
821 )
822 .unwrap();
823 ExtendedDataSquare::new(
824 vec![vec![0u8; SHARE_SIZE]; 6],
825 "fake".to_string(),
826 AppVersion::V2,
827 )
828 .unwrap_err();
829 ExtendedDataSquare::new(
830 vec![vec![0u8; SHARE_SIZE]; 16],
831 "fake".to_string(),
832 AppVersion::V2,
833 )
834 .unwrap();
835
836 let share = |n| {
837 [
838 Namespace::new_v0(&[n]).unwrap().as_bytes(),
839 &[0u8; SHARE_SIZE - NS_SIZE][..],
840 ]
841 .concat()
842 };
843
844 ExtendedDataSquare::from_ods(
845 vec![
846 share(0), ],
849 AppVersion::V2,
850 )
851 .unwrap();
852
853 ExtendedDataSquare::from_ods(
854 vec![
855 share(1),
857 share(2),
858 share(1),
860 share(3),
861 ],
862 AppVersion::V2,
863 )
864 .unwrap();
865
866 ExtendedDataSquare::from_ods(
867 vec![
868 share(1),
870 share(2),
871 share(1),
873 share(1), ],
875 AppVersion::V2,
876 )
877 .unwrap_err();
878
879 ExtendedDataSquare::from_ods(
880 vec![
881 share(1),
883 share(1),
884 share(2),
886 share(1), ],
888 AppVersion::V2,
889 )
890 .unwrap_err();
891
892 ExtendedDataSquare::new(vec![share(1); 6 * 6], "fake".to_string(), AppVersion::V2)
894 .unwrap_err();
895
896 let square_width = max_extended_square_width(AppVersion::V2) * 2;
899 ExtendedDataSquare::new(
900 vec![share(1); square_width.pow(2)],
901 "fake".to_string(),
902 AppVersion::V2,
903 )
904 .unwrap_err();
905
906 let mut shr = share(1);
908 shr[NS_SIZE] = InfoByte::new(appconsts::SHARE_VERSION_ONE, false)
909 .unwrap()
910 .as_u8();
911 let shares = vec![shr, share(1), share(1), share(1)];
912 ExtendedDataSquare::new(shares.clone(), "fake".to_string(), AppVersion::V2).unwrap_err();
913 ExtendedDataSquare::new(shares, "fake".to_string(), AppVersion::V3).unwrap();
914 }
915
916 #[test]
917 fn empty_block_eds() {
918 let s = include_str!("../test_data/chain1/extended_header_block_1.json");
919 let genesis: ExtendedHeader = serde_json::from_str(s).unwrap();
920
921 let eds = ExtendedDataSquare::empty();
922 let dah = DataAvailabilityHeader::from_eds(&eds);
923 assert_eq!(dah, genesis.dah);
924 }
925
926 #[test]
927 fn reconstruct_all() {
928 let eds = generate_eds(8 << (rand::random::<usize>() % 6), AppVersion::V2);
929
930 let blobs = Blob::reconstruct_all(eds.data_square(), AppVersion::V2).unwrap();
931 let expected = eds.square_width() as usize / 2 - 2;
933 assert_eq!(blobs.len(), expected);
934 }
935}