Skip to main content

celestia_types/
namespace_data.rs

1//! Types related to namespace data
2//!
3//! Namespace data in Celestia is understood as all the [`Share`]s in a particular
4//! namespace inside the [`ExtendedDataSquare`]. It may span over multiple rows.
5//!
6//! [`Share`]: crate::Share
7//! [`ExtendedDataSquare`]: crate::eds::ExtendedDataSquare
8
9use bytes::{BufMut, BytesMut};
10use celestia_proto::shwap::RowNamespaceData as RawRowNamespaceData;
11use serde::{Deserialize, Serialize};
12
13use crate::eds::{EDS_ID_SIZE, EdsId};
14use crate::nmt::{NS_SIZE, Namespace};
15use crate::row_namespace_data::{RowNamespaceData, RowNamespaceDataId};
16use crate::{DataAvailabilityHeader, Error, Result, bail_verification};
17
18/// Number of bytes needed to represent [`RowNamespaceDataId`] in `multihash`.
19pub const NAMESPACE_DATA_ID_SIZE: usize = EDS_ID_SIZE + NS_SIZE;
20
21/// Identifies [`Share`]s within a [`Namespace`] located on block's [`ExtendedDataSquare`].
22///
23/// [`Share`]: crate::Share
24/// [`ExtendedDataSquare`]: crate::eds::ExtendedDataSquare
25#[derive(Debug, PartialEq, Clone, Copy)]
26pub struct NamespaceDataId {
27    eds_id: EdsId,
28    namespace: Namespace,
29}
30
31/// A collection of rows of [`Share`]s from a particular [`Namespace`].
32///
33/// [`Share`]: crate::Share
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35#[serde(transparent)]
36pub struct NamespaceData {
37    rows: Vec<RowNamespaceData>,
38}
39
40impl NamespaceData {
41    /// Create namespace data from one or many rows.
42    pub fn new(rows: Vec<RowNamespaceData>) -> Self {
43        NamespaceData { rows }
44    }
45
46    /// All rows containing shares within some namespace.
47    pub fn rows(&self) -> &[RowNamespaceData] {
48        &self.rows[..]
49    }
50
51    /// Extract inner rows namespace data
52    pub fn into_inner(self) -> Vec<RowNamespaceData> {
53        self.rows
54    }
55
56    /// Verify the namespace data against roots from DAH
57    pub fn verify(&self, id: NamespaceDataId, dah: &DataAvailabilityHeader) -> Result<()> {
58        if self.rows.len() > u16::MAX as usize {
59            return Err(Error::NamespaceDataTooLarge);
60        }
61
62        let row_idxs = (0..dah.square_width())
63            .filter(|&row| dah.row_contains(row, id.namespace).unwrap_or(false))
64            .collect::<Vec<_>>();
65
66        if row_idxs.len() != self.rows.len() {
67            bail_verification!(
68                "expected {} rows, found {} rows",
69                row_idxs.len(),
70                self.rows.len()
71            );
72        }
73
74        for (row, row_index) in self.rows.iter().zip(row_idxs.into_iter()) {
75            let ns_row_id = RowNamespaceDataId::new(id.namespace, row_index, id.block_height())?;
76            row.verify(ns_row_id, dah)?;
77        }
78
79        Ok(())
80    }
81
82    /// Recover namespace data from it's raw representation.
83    pub fn from_raw(id: NamespaceDataId, namespace_data: Vec<RawRowNamespaceData>) -> Result<Self> {
84        if namespace_data.len() > u16::MAX as usize {
85            return Err(Error::NamespaceDataTooLarge);
86        }
87
88        let mut rows = Vec::with_capacity(namespace_data.len());
89
90        for (row_index, raw_ns_data) in namespace_data.into_iter().enumerate() {
91            let ns_row_id =
92                RowNamespaceDataId::new(id.namespace, row_index as u16, id.block_height())?;
93            let ns_data = RowNamespaceData::from_raw(ns_row_id, raw_ns_data)?;
94            rows.push(ns_data);
95        }
96
97        Ok(NamespaceData::new(rows))
98    }
99}
100
101impl NamespaceDataId {
102    /// Create a new [`NamespaceDataId`] for given block and the [`Namespace`].
103    ///
104    /// # Errors
105    ///
106    /// This function will return an error if the block height is invalid.
107    pub fn new(namespace: Namespace, block_height: u64) -> Result<Self> {
108        Ok(Self {
109            eds_id: EdsId::new(block_height)?,
110            namespace,
111        })
112    }
113
114    /// A height of the block which contains the shares.
115    pub fn block_height(&self) -> u64 {
116        self.eds_id.block_height()
117    }
118
119    /// A namespace of the [`Share`]s.
120    ///
121    /// [`Share`]: crate::Share
122    pub fn namespace(&self) -> Namespace {
123        self.namespace
124    }
125
126    /// Encode row namespace data id into the byte representation.
127    pub fn encode(&self, bytes: &mut BytesMut) {
128        bytes.reserve(NAMESPACE_DATA_ID_SIZE);
129        self.eds_id.encode(bytes);
130        bytes.put(self.namespace.as_bytes());
131    }
132
133    /// Decode namespace data id from the byte representation.
134    pub fn decode(buffer: &[u8]) -> Result<Self> {
135        if buffer.len() != NAMESPACE_DATA_ID_SIZE {
136            return Err(Error::InvalidLength(buffer.len(), NAMESPACE_DATA_ID_SIZE));
137        }
138
139        let (eds_bytes, ns_bytes) = buffer.split_at(EDS_ID_SIZE);
140        let eds_id = EdsId::decode(eds_bytes)?;
141        let namespace = Namespace::from_raw(ns_bytes)?;
142
143        Ok(Self { eds_id, namespace })
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn decode_namespaced_shares() {
153        let get_shares_by_namespace_response = r#"[
154          {
155            "shares": [
156              "AAAAAAAAAAAAAAAAAAAAAAAAAAAADCBNOWAP3dMBAAAAG/HyDKgAfpEKO/iy5h2g8mvKB+94cXpupUFl9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
157            ],
158            "proof": {
159              "start": 1,
160              "end": 2,
161              "nodes": [
162                "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFmTiyJVvgoyHdw7JGii/wyMfMbSdN3Nbi6Uj0Lcprk+",
163                "/////////////////////////////////////////////////////////////////////////////0WE8jz9lbFjpXWj9v7/QgdAxYEqy4ew9TMdqil/UFZm"
164              ],
165              "leaf_hash": null,
166              "is_max_namespace_ignored": true
167            }
168          }
169        ]"#;
170
171        let ns_shares: NamespaceData =
172            serde_json::from_str(get_shares_by_namespace_response).unwrap();
173
174        assert_eq!(ns_shares.rows()[0].shares.len(), 1);
175        assert!(!ns_shares.rows()[0].proof.is_of_absence());
176    }
177}