1use std::future::Future;
4use std::marker::{Send, Sync};
5
6use celestia_types::namespace_data::NamespaceData;
7use celestia_types::nmt::Namespace;
8use celestia_types::sample::{RawSample, Sample, SampleId};
9use celestia_types::{ExtendedDataSquare, RawShare, Share, ShareProof};
10use jsonrpsee::core::client::{ClientT, Error};
11use jsonrpsee::proc_macros::rpc;
12use serde::{Deserialize, Serialize};
13
14use crate::custom_client_error;
15
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18#[serde(rename_all = "PascalCase")]
19pub struct GetRangeResponse {
20 pub shares: Vec<Share>,
22 pub proof: ShareProof,
24}
25
26#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28#[serde(rename_all = "UPPERCASE")]
29pub enum RowSide {
30 Left,
32 Right,
34 Both,
36}
37
38#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
40pub struct GetRowResponse {
41 pub shares: Vec<Share>,
43 pub side: RowSide,
45}
46
47#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
49pub struct SampleCoordinates {
50 pub row: u16,
52 #[serde(rename = "col")]
54 pub column: u16,
55}
56
57impl SampleCoordinates {
58 pub fn new(row: u16, column: u16) -> Self {
60 SampleCoordinates { row, column }
61 }
62}
63
64impl From<(u16, u16)> for SampleCoordinates {
65 fn from(value: (u16, u16)) -> Self {
66 SampleCoordinates::new(value.0, value.1)
67 }
68}
69
70mod rpc {
71 use super::*;
72 use celestia_types::eds::RawExtendedDataSquare;
73 use jsonrpsee::core::RpcResult;
74
75 #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
76 pub struct RawGetRowResponse {
77 pub(crate) shares: Vec<RawShare>,
78 pub(crate) side: RowSide,
79 }
80
81 #[rpc(client, server, namespace = "share", namespace_separator = ".")]
83 trait Share {
84 #[method(name = "GetEDS")]
86 async fn share_get_eds(&self, height: u64) -> RpcResult<RawExtendedDataSquare>;
87
88 #[method(name = "GetRange")]
90 async fn share_get_range(
91 &self,
92 height: u64,
93 start: u64,
94 end: u64,
95 ) -> RpcResult<GetRangeResponse>; #[method(name = "GetSamples")]
99 async fn share_get_samples(
100 &self,
101 height: u64,
102 indices: Vec<SampleCoordinates>, ) -> RpcResult<Vec<RawSample>>; #[method(name = "GetRow")]
107 async fn share_get_row(&self, height: u64, row: u16) -> RpcResult<RawGetRowResponse>;
108
109 #[method(name = "GetShare")]
111 async fn share_get_share(&self, height: u64, row: u16, col: u16) -> RpcResult<RawShare>;
112
113 #[method(name = "GetNamespaceData")]
115 async fn share_get_namespace_data(
116 &self,
117 height: u64,
118 namespace: Namespace,
119 ) -> RpcResult<NamespaceData>;
120
121 #[method(name = "SharesAvailable")]
123 async fn share_shares_available(&self, height: u64) -> RpcResult<()>;
124 }
125}
126
127pub trait ShareClient: ClientT {
129 fn share_get_eds<'a, 'fut>(
131 &'a self,
132 height: u64,
133 ) -> impl Future<Output = Result<ExtendedDataSquare, Error>> + Send + 'fut
134 where
135 'a: 'fut,
136 Self: Sized + Sync + 'fut,
137 {
138 async move {
139 let raw_eds = rpc::ShareClient::share_get_eds(self, height).await?;
140 ExtendedDataSquare::from_raw(raw_eds).map_err(custom_client_error)
142 }
143 }
144
145 fn share_get_range<'a, 'fut>(
149 &'a self,
150 height: u64,
151 start: u64,
152 end: u64,
153 ) -> impl Future<Output = Result<GetRangeResponse, Error>> + Send + 'fut
154 where
155 'a: 'fut,
156 Self: Sized + Sync + 'fut,
157 {
158 rpc::ShareClient::share_get_range(self, height, start, end)
159 }
160 fn share_get_samples<'a, 'fut, I, C>(
165 &'a self,
166 height: u64,
167 coordinates: I,
168 ) -> impl Future<Output = Result<Vec<Sample>, Error>> + Send + 'fut
169 where
170 'a: 'fut,
171 Self: Sized + Sync + 'fut,
172 I: IntoIterator<Item = C>,
173 C: Into<SampleCoordinates>,
174 {
175 let coordinates = coordinates
176 .into_iter()
177 .map(|c| c.into())
178 .collect::<Vec<_>>();
179
180 async move {
181 let raw_samples =
182 rpc::ShareClient::share_get_samples(self, height, coordinates.clone()).await?;
183 let mut samples = Vec::with_capacity(raw_samples.len());
184
185 for (coords, raw_sample) in coordinates.iter().zip(raw_samples.into_iter()) {
186 let sample_id = SampleId::new(coords.row, coords.column, height)
187 .map_err(custom_client_error)?;
188
189 let sample =
191 Sample::from_raw(sample_id, raw_sample).map_err(custom_client_error)?;
192
193 samples.push(sample);
194 }
195
196 Ok(samples)
197 }
198 }
199
200 fn share_get_row<'a, 'fut>(
202 &'a self,
203 height: u64,
204 square_width: u16,
205 row: u16,
206 ) -> impl Future<Output = Result<GetRowResponse, Error>> + Send + 'fut
207 where
208 'a: 'fut,
209 Self: Sized + Sync + 'fut,
210 {
211 async move {
212 let resp = rpc::ShareClient::share_get_row(self, height, row).await?;
213
214 let expected_len = match resp.side {
215 RowSide::Left | RowSide::Right => square_width / 2,
216 RowSide::Both => square_width,
217 };
218
219 if resp.shares.len() != usize::from(expected_len) {
220 return Err(Error::Custom(format!(
221 "GetRowResponse::shares should have length of {} but received {}",
222 expected_len,
223 resp.shares.len(),
224 )));
225 }
226
227 let shares = resp
228 .shares
229 .into_iter()
230 .enumerate()
231 .map(|(relative_col, raw_share)| {
232 let relative_col = u16::try_from(relative_col)
233 .expect("square_width and expected_len already validated this");
234
235 let col = match resp.side {
236 RowSide::Left | RowSide::Both => relative_col,
237 RowSide::Right => (square_width / 2) + relative_col,
238 };
239
240 let share = if is_ods_square(row, col, square_width) {
241 Share::from_raw(&raw_share.data)
242 } else {
243 Share::parity(&raw_share.data)
244 }
245 .map_err(custom_client_error)?;
246
247 Ok(share)
248 })
249 .collect::<Result<Vec<_>, Error>>()?;
250
251 Ok(GetRowResponse {
252 shares,
253 side: resp.side,
254 })
255 }
256 }
257
258 fn share_get_share<'a, 'fut>(
260 &'a self,
261 height: u64,
262 square_width: u16,
263 row: u16,
264 col: u16,
265 ) -> impl Future<Output = Result<Share, Error>> + Send + 'fut
266 where
267 'a: 'fut,
268 Self: Sized + Sync + 'fut,
269 {
270 async move {
271 let share = rpc::ShareClient::share_get_share(self, height, row, col).await?;
272 let share = if is_ods_square(row, col, square_width) {
273 Share::from_raw(&share.data)
274 } else {
275 Share::parity(&share.data)
276 }
277 .map_err(custom_client_error)?;
278
279 Ok(share)
280 }
281 }
282
283 fn share_get_namespace_data<'a, 'fut>(
289 &'a self,
290 height: u64,
291 namespace: Namespace,
292 ) -> impl Future<Output = Result<NamespaceData, Error>> + Send + 'fut
293 where
294 'a: 'fut,
295 Self: Sized + Sync + 'fut,
296 {
297 rpc::ShareClient::share_get_namespace_data(self, height, namespace)
298 }
299
300 fn share_shares_available<'a, 'fut>(
302 &'a self,
303 height: u64,
304 ) -> impl Future<Output = Result<(), Error>> + Send + 'fut
305 where
306 'a: 'fut,
307 Self: Sized + Sync + 'fut,
308 {
309 rpc::ShareClient::share_shares_available(self, height)
310 }
311}
312
313impl<T> ShareClient for T where T: ClientT {}
314
315fn is_ods_square(row: u16, column: u16, square_width: u16) -> bool {
316 let ods_width = square_width / 2;
317 row < ods_width && column < ods_width
318}
319
320pub trait ShareServer: rpc::ShareServer {}
322
323impl<T> ShareServer for T where T: rpc::ShareServer {}
324
325pub use rpc::ShareServer as ShareRpcServer;