1#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
4use crate::evidence::JsEvidence;
5use crate::{Error, Result};
6use celestia_proto::tendermint_celestia_mods::types::Block as RawBlock;
7use serde::{Deserialize, Serialize};
8use tendermint::block::{Commit, Header};
9use tendermint::evidence;
10use tendermint_proto::Protobuf;
11#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
12use wasm_bindgen::prelude::*;
13
14mod commit;
15mod data;
16pub(crate) mod header;
17
18pub use commit::CommitExt;
19#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
20pub use commit::{JsCommit, JsCommitSig};
21pub use data::Data;
22#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
23pub use header::{JsHeader, JsHeaderVersion, JsPartsHeader, JsSignedHeader};
24
25pub(crate) const GENESIS_HEIGHT: u64 = 1;
26
27pub type Height = tendermint::block::Height;
29
30#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
38#[serde(try_from = "RawBlock", into = "RawBlock")]
39#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
40#[cfg_attr(
41 all(target_arch = "wasm32", feature = "wasm-bindgen"),
42 wasm_bindgen(getter_with_clone)
43)]
44pub struct Block {
45 #[cfg_attr(
47 all(target_arch = "wasm32", feature = "wasm-bindgen"),
48 wasm_bindgen(skip)
49 )]
50 pub header: Header,
51
52 pub data: Data,
54
55 #[cfg_attr(
57 all(target_arch = "wasm32", feature = "wasm-bindgen"),
58 wasm_bindgen(skip)
59 )]
60 pub evidence: evidence::List,
61
62 #[cfg_attr(
64 all(target_arch = "wasm32", feature = "wasm-bindgen"),
65 wasm_bindgen(skip)
66 )]
67 pub last_commit: Option<Commit>,
68}
69
70impl Block {
71 pub fn new(
73 header: Header,
74 data: Data,
75 evidence: evidence::List,
76 last_commit: Option<Commit>,
77 ) -> Self {
78 Block {
79 header,
80 data,
81 evidence,
82 last_commit,
83 }
84 }
85
86 pub fn header(&self) -> &Header {
88 &self.header
89 }
90
91 pub fn data(&self) -> &Data {
93 &self.data
94 }
95
96 pub fn evidence(&self) -> &evidence::List {
98 &self.evidence
99 }
100
101 pub fn last_commit(&self) -> &Option<Commit> {
103 &self.last_commit
104 }
105}
106
107impl Protobuf<RawBlock> for Block {}
108
109impl TryFrom<RawBlock> for Block {
110 type Error = Error;
111
112 fn try_from(value: RawBlock) -> Result<Self, Self::Error> {
113 let header: Header = value
114 .header
115 .ok_or_else(tendermint::Error::missing_header)?
116 .try_into()?;
117
118 let last_commit = value
120 .last_commit
121 .map(TryInto::try_into)
122 .transpose()?
123 .filter(|c| c != &Commit::default());
124
125 Ok(Block::new(
126 header,
127 value
128 .data
129 .ok_or_else(tendermint::Error::missing_data)?
130 .try_into()?,
131 value
132 .evidence
133 .map(TryInto::try_into)
134 .transpose()?
135 .unwrap_or_default(),
136 last_commit,
137 ))
138 }
139}
140
141impl From<Block> for RawBlock {
142 fn from(value: Block) -> Self {
143 RawBlock {
144 header: Some(value.header.into()),
145 data: Some(value.data.into()),
146 evidence: Some(value.evidence.into()),
147 last_commit: value.last_commit.map(Into::into),
148 }
149 }
150}
151
152#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
153#[wasm_bindgen]
154impl Block {
155 #[wasm_bindgen(getter, js_name = header)]
157 pub fn js_get_header(&self) -> JsHeader {
158 self.header.clone().into()
159 }
160
161 #[wasm_bindgen(getter, js_name = evidence)]
163 pub fn js_get_evidence(&self) -> Vec<JsEvidence> {
164 self.evidence
165 .iter()
166 .map(|e| JsEvidence::from(e.clone()))
167 .collect()
168 }
169
170 #[wasm_bindgen(getter, js_name = lastCommit)]
172 pub fn js_get_last_commit(&self) -> Option<JsCommit> {
173 self.last_commit.clone().map(Into::into)
174 }
175}
176
177#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
178pub use wbg::*;
179
180#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]
181mod wbg {
182 use tendermint::block;
183 use wasm_bindgen::prelude::*;
184
185 use crate::block::header::JsPartsHeader;
186
187 #[derive(Clone, Debug)]
189 #[wasm_bindgen(getter_with_clone, js_name = "BlockId")]
190 pub struct JsBlockId {
191 pub hash: String,
193 pub part_set_header: JsPartsHeader,
207 }
208
209 impl From<block::Id> for JsBlockId {
210 fn from(value: block::Id) -> Self {
211 JsBlockId {
212 hash: value.hash.to_string(),
213 part_set_header: value.part_set_header.into(),
214 }
215 }
216 }
217}
218
219#[cfg(feature = "uniffi")]
221pub mod uniffi_types {
222 use tendermint::block::Height as TendermintHeight;
223 use tendermint::block::Id as TendermintBlockId;
224 use tendermint::hash::Hash;
225 use uniffi::Record;
226
227 use crate::block::header::uniffi_types::PartsHeader;
228 use crate::error::UniffiConversionError;
229
230 #[derive(Record)]
232 pub struct BlockId {
233 pub hash: Hash,
235 pub part_set_header: PartsHeader,
249 }
250
251 impl TryFrom<BlockId> for TendermintBlockId {
252 type Error = UniffiConversionError;
253
254 fn try_from(value: BlockId) -> Result<Self, Self::Error> {
255 Ok(TendermintBlockId {
256 hash: value.hash,
257 part_set_header: value.part_set_header.try_into()?,
258 })
259 }
260 }
261
262 impl From<TendermintBlockId> for BlockId {
263 fn from(value: TendermintBlockId) -> Self {
264 BlockId {
265 hash: value.hash,
266 part_set_header: value.part_set_header.into(),
267 }
268 }
269 }
270
271 uniffi::custom_type!(TendermintBlockId, BlockId, {
272 remote,
273 try_lift: |value| Ok(value.try_into()?),
274 lower: |value| value.into()
275 });
276
277 #[derive(Record)]
281 pub struct BlockHeight {
282 pub value: u64,
284 }
285
286 impl TryFrom<BlockHeight> for TendermintHeight {
287 type Error = UniffiConversionError;
288
289 fn try_from(value: BlockHeight) -> Result<Self, Self::Error> {
290 TendermintHeight::try_from(value.value)
291 .map_err(|_| UniffiConversionError::HeaderHeightOutOfRange)
292 }
293 }
294
295 impl From<TendermintHeight> for BlockHeight {
296 fn from(value: TendermintHeight) -> Self {
297 BlockHeight {
298 value: value.value(),
299 }
300 }
301 }
302
303 uniffi::custom_type!(TendermintHeight, BlockHeight, {
304 remote,
305 try_lift: |value| Ok(value.try_into()?),
306 lower: |value| value.into()
307 });
308}