mod block_id_flag;
mod commit;
pub mod commit_sig;
pub mod header;
mod height;
mod id;
mod meta;
pub mod parts;
mod round;
pub mod signed_header;
mod size;
use serde::{Deserialize, Serialize};
use tendermint_proto::v0_37::types::Block as RawBlock;
pub use self::{
block_id_flag::BlockIdFlag,
commit::*,
commit_sig::*,
header::Header,
height::*,
id::{Id, ParseId},
meta::Meta,
round::*,
size::Size,
};
use crate::{error::Error, evidence, prelude::*};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
#[serde(try_from = "RawBlock", into = "RawBlock")]
pub struct Block {
pub header: Header,
pub data: Vec<Vec<u8>>,
pub evidence: evidence::List,
pub last_commit: Option<Commit>,
}
tendermint_pb_modules! {
use super::{Block, Header, Commit};
use crate::{Error, prelude::*};
use pb::types::Block as RawBlock;
impl Protobuf<RawBlock> for Block {}
impl TryFrom<RawBlock> for Block {
type Error = Error;
fn try_from(value: RawBlock) -> Result<Self, Self::Error> {
let header: Header = value.header.ok_or_else(Error::missing_header)?.try_into()?;
let last_commit = value
.last_commit
.map(TryInto::try_into)
.transpose()?
.filter(|c| c != &Commit::default());
if last_commit.is_none() && header.height.value() != 1 {
return Err(Error::invalid_block(
"last_commit is empty on non-first block".to_string(),
));
}
Ok(Block {
header,
data: value.data.ok_or_else(Error::missing_data)?.txs,
evidence: value.evidence.map(TryInto::try_into).transpose()?.unwrap_or_default(),
last_commit,
})
}
}
impl From<Block> for RawBlock {
fn from(value: Block) -> Self {
use pb::types::Data as RawData;
RawBlock {
header: Some(value.header.into()),
data: Some(RawData { txs: value.data }),
evidence: Some(value.evidence.into()),
last_commit: value.last_commit.map(Into::into),
}
}
}
}
impl Block {
pub fn new(
header: Header,
data: Vec<Vec<u8>>,
evidence: evidence::List,
last_commit: Option<Commit>,
) -> Result<Self, Error> {
if last_commit.is_none() && header.height.value() != 1 {
return Err(Error::invalid_block(
"last_commit is empty on non-first block".to_string(),
));
}
if last_commit.is_some() && header.height.value() == 1 {
return Err(Error::invalid_block(
"last_commit is filled on first block".to_string(),
));
}
Ok(Block {
header,
data,
evidence,
last_commit,
})
}
pub fn header(&self) -> &Header {
&self.header
}
pub fn data(&self) -> &Vec<Vec<u8>> {
&self.data
}
pub fn evidence(&self) -> &evidence::List {
&self.evidence
}
pub fn last_commit(&self) -> &Option<Commit> {
&self.last_commit
}
}