iq_cometbft/
block.rs

1//! Blocks within the chains of a CometBFT network
2
3mod block_id_flag;
4mod commit;
5pub mod commit_sig;
6pub mod header;
7mod height;
8mod id;
9mod meta;
10pub mod parts;
11mod round;
12pub mod signed_header;
13mod size;
14
15use cometbft_proto::types::v1::Block as RawBlock;
16use serde::{Deserialize, Serialize};
17
18pub use self::{
19    block_id_flag::BlockIdFlag,
20    commit::*,
21    commit_sig::*,
22    header::Header,
23    height::*,
24    id::{Id, ParseId},
25    meta::Meta,
26    round::*,
27    size::Size,
28};
29use crate::{evidence, prelude::*};
30
31/// Blocks consist of a header, transactions, votes (the commit), and a list of
32/// evidence of malfeasance (i.e. signing conflicting votes).
33///
34/// <https://github.com/cometbft/cometbft/blob/v1.0.0-alpha.1/spec/core/data_structures.md#block>
35// Default serialization - all fields serialize; used by /block endpoint
36#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
37#[non_exhaustive]
38#[serde(try_from = "RawBlock", into = "RawBlock")]
39pub struct Block {
40    /// Block header
41    pub header: Header,
42
43    /// Transaction data
44    pub data: Vec<Vec<u8>>,
45
46    /// Evidence of malfeasance
47    pub evidence: evidence::List,
48
49    /// Last commit, should be `None` for the initial block.
50    pub last_commit: Option<Commit>,
51}
52
53// =============================================================================
54// Protobuf conversions
55// =============================================================================
56
57cometbft_old_pb_modules! {
58    use super::{Block, Header, Commit};
59    use crate::{Error, prelude::*};
60    use pb::types::Block as RawBlock;
61
62    impl Protobuf<RawBlock> for Block {}
63
64    impl TryFrom<RawBlock> for Block {
65        type Error = Error;
66
67        fn try_from(value: RawBlock) -> Result<Self, Self::Error> {
68            let header: Header = value.header.ok_or_else(Error::missing_header)?.try_into()?;
69            // If last_commit is the default Commit, it is considered nil by Go.
70            let last_commit = value
71                .last_commit
72                .map(TryInto::try_into)
73                .transpose()?
74                .filter(|c| c != &Commit::default());
75
76            Ok(Block::new(
77                header,
78                value.data.ok_or_else(Error::missing_data)?.txs,
79                value
80                    .evidence
81                    .map(TryInto::try_into)
82                    .transpose()?
83                    .unwrap_or_default(),
84                last_commit,
85            ))
86        }
87    }
88
89    impl From<Block> for RawBlock {
90        fn from(value: Block) -> Self {
91            use pb::types::Data as RawData;
92            RawBlock {
93                header: Some(value.header.into()),
94                data: Some(RawData { txs: value.data }),
95                evidence: Some(value.evidence.into()),
96                last_commit: value.last_commit.map(Into::into),
97            }
98        }
99    }
100}
101
102mod v1 {
103    use super::{Block, Commit, Header};
104    use crate::{prelude::*, Error};
105    use cometbft_proto::types::v1 as pb;
106    use cometbft_proto::Protobuf;
107
108    impl Protobuf<pb::Block> for Block {}
109
110    impl TryFrom<pb::Block> for Block {
111        type Error = Error;
112
113        fn try_from(value: pb::Block) -> Result<Self, Self::Error> {
114            let header: Header = value.header.ok_or_else(Error::missing_header)?.try_into()?;
115            // If last_commit is the default Commit, it is considered nil by Go.
116            let last_commit = value
117                .last_commit
118                .map(TryInto::try_into)
119                .transpose()?
120                .filter(|c| c != &Commit::default());
121
122            Ok(Block::new(
123                header,
124                value.data.ok_or_else(Error::missing_data)?.txs,
125                value
126                    .evidence
127                    .map(TryInto::try_into)
128                    .transpose()?
129                    .unwrap_or_default(),
130                last_commit,
131            ))
132        }
133    }
134
135    impl From<Block> for pb::Block {
136        fn from(value: Block) -> Self {
137            pb::Block {
138                header: Some(value.header.into()),
139                data: Some(pb::Data { txs: value.data }),
140                evidence: Some(value.evidence.into()),
141                last_commit: value.last_commit.map(Into::into),
142            }
143        }
144    }
145}
146
147mod v1beta1 {
148    use super::{Block, Commit, Header};
149    use crate::{prelude::*, Error};
150    use cometbft_proto::types::v1beta1 as pb;
151    use cometbft_proto::Protobuf;
152
153    impl Protobuf<pb::Block> for Block {}
154
155    impl TryFrom<pb::Block> for Block {
156        type Error = Error;
157
158        fn try_from(value: pb::Block) -> Result<Self, Self::Error> {
159            let header: Header = value.header.ok_or_else(Error::missing_header)?.try_into()?;
160            // If last_commit is the default Commit, it is considered nil by Go.
161            let last_commit = value
162                .last_commit
163                .map(TryInto::try_into)
164                .transpose()?
165                .filter(|c| c != &Commit::default());
166
167            Ok(Block::new(
168                header,
169                value.data.ok_or_else(Error::missing_data)?.txs,
170                value
171                    .evidence
172                    .map(TryInto::try_into)
173                    .transpose()?
174                    .unwrap_or_default(),
175                last_commit,
176            ))
177        }
178    }
179
180    impl From<Block> for pb::Block {
181        fn from(value: Block) -> Self {
182            pb::Block {
183                header: Some(value.header.into()),
184                data: Some(pb::Data { txs: value.data }),
185                evidence: Some(value.evidence.into()),
186                last_commit: value.last_commit.map(Into::into),
187            }
188        }
189    }
190}
191
192impl Block {
193    /// Builds a new [`Block`], based on the given [`Header`], data, evidence, and last commit.
194    pub fn new(
195        header: Header,
196        data: Vec<Vec<u8>>,
197        evidence: evidence::List,
198        last_commit: Option<Commit>,
199    ) -> Self {
200        Self {
201            header,
202            data,
203            evidence,
204            last_commit,
205        }
206    }
207
208    /// Get header
209    pub fn header(&self) -> &Header {
210        &self.header
211    }
212
213    /// Get data
214    pub fn data(&self) -> &Vec<Vec<u8>> {
215        &self.data
216    }
217
218    /// Get evidence
219    pub fn evidence(&self) -> &evidence::List {
220        &self.evidence
221    }
222
223    /// Get last commit
224    pub fn last_commit(&self) -> &Option<Commit> {
225        &self.last_commit
226    }
227}