tendermint/block/
parts.rs

1//! Block parts
2
3use serde::{Deserialize, Serialize};
4use tendermint_proto::v0_37::types::PartSetHeader as RawPartSetHeader;
5
6use crate::{error::Error, prelude::*, Hash};
7
8/// Block parts header
9#[derive(
10    Clone, Copy, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize,
11)]
12#[serde(try_from = "RawPartSetHeader", into = "RawPartSetHeader")] // Used by KMS state file
13#[non_exhaustive]
14pub struct Header {
15    /// Number of parts in this block
16    pub total: u32,
17
18    /// Hash of the parts set header,
19    pub hash: Hash,
20}
21
22tendermint_pb_modules! {
23    use pb::types::{
24        CanonicalPartSetHeader as RawCanonicalPartSetHeader, PartSetHeader as RawPartSetHeader,
25    };
26    use crate::{
27        error::Error,
28        hash::{Algorithm, SHA256_HASH_SIZE},
29        prelude::*,
30        Hash,
31    };
32    use super::Header;
33
34    impl Protobuf<RawPartSetHeader> for Header {}
35
36    impl TryFrom<RawPartSetHeader> for Header {
37        type Error = Error;
38
39        fn try_from(value: RawPartSetHeader) -> Result<Self, Self::Error> {
40            if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE {
41                return Err(Error::invalid_hash_size());
42            }
43            Ok(Self {
44                total: value.total,
45                hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?,
46            })
47        }
48    }
49
50    impl From<Header> for RawPartSetHeader {
51        fn from(value: Header) -> Self {
52            RawPartSetHeader {
53                total: value.total,
54                hash: value.hash.into(),
55            }
56        }
57    }
58
59    impl TryFrom<RawCanonicalPartSetHeader> for Header {
60        type Error = Error;
61
62        fn try_from(value: RawCanonicalPartSetHeader) -> Result<Self, Self::Error> {
63            if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE {
64                return Err(Error::invalid_hash_size());
65            }
66            Ok(Self {
67                total: value.total,
68                hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?,
69            })
70        }
71    }
72
73    impl From<Header> for RawCanonicalPartSetHeader {
74        fn from(value: Header) -> Self {
75            RawCanonicalPartSetHeader {
76                total: value.total,
77                hash: value.hash.into(),
78            }
79        }
80    }
81}
82
83impl Header {
84    /// constructor
85    pub fn new(total: u32, hash: Hash) -> Result<Self, Error> {
86        if total == 0 && hash != Hash::None {
87            return Err(Error::invalid_part_set_header(
88                "zero total with existing hash".to_string(),
89            ));
90        }
91        if total != 0 && hash == Hash::None {
92            return Err(Error::invalid_part_set_header(
93                "non-zero total with empty hash".to_string(),
94            ));
95        }
96        Ok(Header { total, hash })
97    }
98}