tendermint/
block.rs

1//! Blocks within the chains of a Tendermint 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 serde::{Deserialize, Serialize};
16use tendermint_proto::v0_37::types::Block as RawBlock;
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
53tendermint_pb_modules! {
54    use super::{Block, Header, Commit};
55    use crate::{Error, prelude::*};
56    use pb::types::Block as RawBlock;
57
58    impl Protobuf<RawBlock> for Block {}
59
60    impl TryFrom<RawBlock> for Block {
61        type Error = Error;
62
63        fn try_from(value: RawBlock) -> Result<Self, Self::Error> {
64            let header: Header = value.header.ok_or_else(Error::missing_header)?.try_into()?;
65
66            // If last_commit is the default Commit, it is considered nil by Go.
67            let last_commit = value
68                .last_commit
69                .map(TryInto::try_into)
70                .transpose()?
71                .filter(|c| c != &Commit::default());
72
73            Ok(Block::new(
74                header,
75                value.data.ok_or_else(Error::missing_data)?.txs,
76                value.evidence.map(TryInto::try_into).transpose()?.unwrap_or_default(),
77                last_commit,
78            ))
79        }
80    }
81
82    impl From<Block> for RawBlock {
83        fn from(value: Block) -> Self {
84            use pb::types::Data as RawData;
85            RawBlock {
86                header: Some(value.header.into()),
87                data: Some(RawData { txs: value.data }),
88                evidence: Some(value.evidence.into()),
89                last_commit: value.last_commit.map(Into::into),
90            }
91        }
92    }
93}
94
95impl Block {
96    /// Builds a new [`Block`], based on the given [`Header`], data, evidence, and last commit.
97    pub fn new(
98        header: Header,
99        data: Vec<Vec<u8>>,
100        evidence: evidence::List,
101        last_commit: Option<Commit>,
102    ) -> Self {
103        Self {
104            header,
105            data,
106            evidence,
107            last_commit,
108        }
109    }
110
111    /// Get header
112    pub fn header(&self) -> &Header {
113        &self.header
114    }
115
116    /// Get data
117    pub fn data(&self) -> &Vec<Vec<u8>> {
118        &self.data
119    }
120
121    /// Get evidence
122    pub fn evidence(&self) -> &evidence::List {
123        &self.evidence
124    }
125
126    /// Get last commit
127    pub fn last_commit(&self) -> &Option<Commit> {
128        &self.last_commit
129    }
130}