1mod commit;
4pub mod commit_sig;
5mod data;
6pub mod header;
7mod height;
8mod id;
9mod meta;
10pub mod parts;
11mod round;
12pub mod signed_header;
13mod size;
14
15use celestia_core_proto::v0_34::types::Block as RawBlock;
16use serde::{Deserialize, Serialize};
17
18pub use self::{
19 commit::*,
20 commit_sig::*,
21 data::Data,
22 header::Header,
23 height::*,
24 id::{Id, ParseId},
25 meta::Meta,
26 round::*,
27 size::Size,
28};
29use crate::{error::Error, evidence, prelude::*};
30
31#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
37#[non_exhaustive]
38#[serde(try_from = "RawBlock", into = "RawBlock")]
39pub struct Block {
40 pub header: Header,
42
43 pub data: Data,
45
46 pub evidence: evidence::List,
48
49 pub last_commit: Option<Commit>,
51}
52
53mod v0_34 {
54 use super::{Block, Commit, Header};
55 use crate::{prelude::*, Error};
56 use celestia_core_proto::v0_34::types::Block as RawBlock;
57 use celestia_core_proto::Protobuf;
58
59 impl Protobuf<RawBlock> for Block {}
60
61 impl TryFrom<RawBlock> for Block {
62 type Error = Error;
63
64 fn try_from(value: RawBlock) -> Result<Self, Self::Error> {
65 let header: Header = value.header.ok_or_else(Error::missing_header)?.try_into()?;
66 let last_commit = value
68 .last_commit
69 .map(TryInto::try_into)
70 .transpose()?
71 .filter(|c| c != &Commit::default());
72 if last_commit.is_none() && header.height.value() != 1 {
73 return Err(Error::invalid_block(
74 "last_commit is empty on non-first block".to_string(),
75 ));
76 }
77
78 Ok(Block {
85 header,
86 data: value.data.ok_or_else(Error::missing_data)?.try_into()?,
87 evidence: value
88 .evidence
89 .map(TryInto::try_into)
90 .transpose()?
91 .unwrap_or_default(),
92 last_commit,
93 })
94 }
95 }
96
97 impl From<Block> for RawBlock {
98 fn from(value: Block) -> Self {
99 RawBlock {
100 header: Some(value.header.into()),
101 data: Some(value.data.into()),
102 evidence: Some(value.evidence.into()),
103 last_commit: value.last_commit.map(Into::into),
104 }
105 }
106 }
107}
108
109impl Block {
110 pub fn new(
112 header: Header,
113 data: Data,
114 evidence: evidence::List,
115 last_commit: Option<Commit>,
116 ) -> Result<Self, Error> {
117 if last_commit.is_none() && header.height.value() != 1 {
118 return Err(Error::invalid_block(
119 "last_commit is empty on non-first block".to_string(),
120 ));
121 }
122 if last_commit.is_some() && header.height.value() == 1 {
123 return Err(Error::invalid_block(
124 "last_commit is filled on first block".to_string(),
125 ));
126 }
127 Ok(Block {
128 header,
129 data,
130 evidence,
131 last_commit,
132 })
133 }
134
135 pub fn header(&self) -> &Header {
137 &self.header
138 }
139
140 pub fn data(&self) -> &Data {
142 &self.data
143 }
144
145 pub fn evidence(&self) -> &evidence::List {
147 &self.evidence
148 }
149
150 pub fn last_commit(&self) -> &Option<Commit> {
152 &self.last_commit
153 }
154}