celestia_client/share.rs
1use std::sync::Arc;
2
3use celestia_rpc::ShareClient;
4
5use crate::Result;
6use crate::api::share::{GetRangeResponse, GetRowResponse, SampleCoordinates};
7use crate::client::ClientInner;
8use crate::types::namespace_data::NamespaceData;
9use crate::types::nmt::Namespace;
10use crate::types::sample::Sample;
11use crate::types::{ExtendedDataSquare, Share};
12
13/// Share API for quering bridge nodes.
14pub struct ShareApi {
15 inner: Arc<ClientInner>,
16}
17
18impl ShareApi {
19 pub(crate) fn new(inner: Arc<ClientInner>) -> ShareApi {
20 ShareApi { inner }
21 }
22
23 /// Performs a subjective validation to check if the shares committed to the
24 /// header at the specified height are available and retrievable from the network.
25 ///
26 /// Returns `Ok(())` if shares are available.
27 pub async fn shares_available(&self, height: u64) -> Result<()> {
28 Ok(self.inner.rpc.share_shares_available(height).await?)
29 }
30
31 /// Retrieves a specific share from the [`ExtendedDataSquare`] at the given
32 /// height using its row and column coordinates.
33 pub async fn get(
34 &self,
35 height: u64,
36 square_width: u16,
37 row: u16,
38 column: u16,
39 ) -> Result<Share> {
40 Ok(self
41 .inner
42 .rpc
43 .share_get_share(height, square_width, row, column)
44 .await?)
45 }
46
47 /// Retrieves a specific share from the [`ExtendedDataSquare`] at the given
48 /// height using its row and column coordinates.
49 ///
50 /// # NOTE
51 ///
52 /// This method will first fetch and validate the header at a given height and
53 /// then use it to provide necessary data for validation and post-processing.
54 ///
55 /// If you already have access to the necessary data, it is recommended to use
56 /// the equivalent method without the `_with_root` suffix.
57 pub async fn get_with_root(&self, height: u64, row: u16, column: u16) -> Result<Share> {
58 let header = self.inner.get_header_validated(height).await?;
59 Ok(self
60 .inner
61 .rpc
62 .share_get_share(header.height(), header.square_width(), row, column)
63 .await?)
64 }
65
66 /// Retrieves multiple shares from the [`ExtendedDataSquare`] at the given
67 /// sample coordinates.
68 ///
69 /// `coordinates` is a list of `(row, column)`.
70 pub async fn get_samples<I, C>(&self, height: u64, coordinates: I) -> Result<Vec<Sample>>
71 where
72 I: IntoIterator<Item = C>,
73 C: Into<SampleCoordinates>,
74 {
75 Ok(self
76 .inner
77 .rpc
78 .share_get_samples(height, coordinates)
79 .await?)
80 }
81
82 /// Retrieves multiple shares from the [`ExtendedDataSquare`] at the given
83 /// sample coordinates.
84 ///
85 /// `coordinates` is a list of `(row, column)`.
86 ///
87 /// # NOTE
88 ///
89 /// This method will first fetch and validate the header at a given height and
90 /// then use it to provide necessary data for validation and post-processing.
91 ///
92 /// If you already have access to the necessary data, it is recommended to use
93 /// the equivalent method without the `_with_root` suffix.
94 pub async fn get_samples_with_root<I, C>(
95 &self,
96 height: u64,
97 coordinates: I,
98 ) -> Result<Vec<Sample>>
99 where
100 I: IntoIterator<Item = C>,
101 C: Into<SampleCoordinates>,
102 {
103 let header = self.inner.get_header_validated(height).await?;
104 Ok(self
105 .inner
106 .rpc
107 .share_get_samples(header.height(), coordinates)
108 .await?)
109 }
110
111 /// Retrieves the complete [`ExtendedDataSquare`] for the specified height.
112 pub async fn get_eds(&self, height: u64) -> Result<ExtendedDataSquare> {
113 Ok(self.inner.rpc.share_get_eds(height).await?)
114 }
115
116 /// Retrieves the complete [`ExtendedDataSquare`] for the specified height.
117 ///
118 /// # NOTE
119 ///
120 /// This method will first fetch and validate the header at a given height and
121 /// then use it to provide necessary data for validation and post-processing.
122 ///
123 /// If you already have access to the necessary data, it is recommended to use
124 /// the equivalent method without the `_with_root` suffix.
125 pub async fn get_eds_with_root(&self, height: u64) -> Result<ExtendedDataSquare> {
126 let header = self.inner.get_header_validated(height).await?;
127 Ok(self.inner.rpc.share_get_eds(header.height()).await?)
128 }
129
130 /// Retrieves all shares from a specific row of the [`ExtendedDataSquare`]
131 /// at the given height.
132 pub async fn get_row(
133 &self,
134 height: u64,
135 square_width: u16,
136 row: u16,
137 ) -> Result<GetRowResponse> {
138 Ok(self
139 .inner
140 .rpc
141 .share_get_row(height, square_width, row)
142 .await?)
143 }
144
145 /// Retrieves all shares from a specific row of the [`ExtendedDataSquare`]
146 /// at the given height.
147 ///
148 /// # NOTE
149 ///
150 /// This method will first fetch and validate the header at a given height and
151 /// then use it to provide necessary data for validation and post-processing.
152 ///
153 /// If you already have access to the necessary data, it is recommended to use
154 /// the equivalent method without the `_with_root` suffix.
155 pub async fn get_row_with_root(&self, height: u64, row: u16) -> Result<GetRowResponse> {
156 let header = self.inner.get_header_validated(height).await?;
157 Ok(self
158 .inner
159 .rpc
160 .share_get_row(header.height(), header.square_width(), row)
161 .await?)
162 }
163
164 /// Retrieves all shares that belong to the specified namespace within the
165 /// [`ExtendedDataSquare`] at the given height.
166 ///
167 /// The shares are returned in a row-by-row order, maintaining the original
168 /// layout if the namespace spans multiple rows.
169 pub async fn get_namespace_data(
170 &self,
171 height: u64,
172 namespace: Namespace,
173 ) -> Result<NamespaceData> {
174 Ok(self
175 .inner
176 .rpc
177 .share_get_namespace_data(height, namespace)
178 .await?)
179 }
180
181 /// Retrieves all shares that belong to the specified namespace within the
182 /// [`ExtendedDataSquare`] at the given height.
183 ///
184 /// The shares are returned in a row-by-row order, maintaining the original
185 /// layout if the namespace spans multiple rows.
186 ///
187 /// # NOTE
188 ///
189 /// This method will first fetch and validate the header at a given height and
190 /// then use it to provide necessary data for validation and post-processing.
191 ///
192 /// If you already have access to the necessary data, it is recommended to use
193 /// the equivalent method without the `_with_root` suffix.
194 pub async fn get_namespace_data_with_root(
195 &self,
196 height: u64,
197 namespace: Namespace,
198 ) -> Result<NamespaceData> {
199 let header = self.inner.get_header_validated(height).await?;
200
201 Ok(self
202 .inner
203 .rpc
204 .share_get_namespace_data(header.height(), namespace)
205 .await?)
206 }
207
208 /// Retrieves a list of shares and their corresponding proof.
209 ///
210 /// The start and end index ignores parity shares and corresponds to ODS.
211 pub async fn get_range(&self, height: u64, start: u64, end: u64) -> Result<GetRangeResponse> {
212 Ok(self.inner.rpc.share_get_range(height, start, end).await?)
213 }
214
215 /// Retrieves a list of shares and their corresponding proof.
216 ///
217 /// The start and end index ignores parity shares and corresponds to ODS.
218 ///
219 /// # NOTE
220 ///
221 /// This method will first fetch and validate the header at a given height and
222 /// then use it to provide necessary data for validation and post-processing.
223 ///
224 /// If you already have access to the necessary data, it is recommended to use
225 /// the equivalent method without the `_with_root` suffix.
226 pub async fn get_range_with_root(
227 &self,
228 height: u64,
229 start: u64,
230 end: u64,
231 ) -> Result<GetRangeResponse> {
232 let header = self.inner.get_header_validated(height).await?;
233 Ok(self
234 .inner
235 .rpc
236 .share_get_range(header.height(), start, end)
237 .await?)
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244
245 use crate::test_utils::{ensure_serializable, ensure_serializable_deserializable};
246
247 #[allow(dead_code)]
248 #[allow(unused_variables)]
249 #[allow(unreachable_code)]
250 #[allow(clippy::diverging_sub_expression)]
251 async fn enforce_serde_bounds() {
252 // intentionally no-run, compile only test
253 let api = ShareApi::new(unimplemented!());
254
255 let _: () = api.shares_available(0).await.unwrap();
256
257 let coordinates: Vec<SampleCoordinates> =
258 ensure_serializable_deserializable(unimplemented!());
259 ensure_serializable(api.get_samples(0, coordinates).await.unwrap());
260
261 ensure_serializable(api.get_eds(0).await.unwrap());
262
263 ensure_serializable_deserializable(api.get(0, 0, 0, 0).await.unwrap());
264
265 ensure_serializable_deserializable(api.get_row(0, 0, 0).await.unwrap());
266
267 let namespace = ensure_serializable_deserializable(unimplemented!());
268 ensure_serializable_deserializable(api.get_namespace_data(0, namespace).await.unwrap());
269
270 ensure_serializable_deserializable(api.get_range(0, 0, 0).await.unwrap());
271 }
272}