Skip to main content

iq_cometbft/block/
parts.rs

1//! Block parts
2
3use cometbft_proto::types::v1::PartSetHeader as RawPartSetHeader;
4use serde::{Deserialize, Serialize};
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
22cometbft_old_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
83mod v1 {
84    use super::Header;
85    use crate::{
86        error::Error,
87        hash::{Algorithm, SHA256_HASH_SIZE},
88        prelude::*,
89        Hash,
90    };
91    use cometbft_proto::types::v1::{
92        CanonicalPartSetHeader as RawCanonicalPartSetHeader, PartSetHeader as RawPartSetHeader,
93    };
94    use cometbft_proto::Protobuf;
95
96    impl Protobuf<RawPartSetHeader> for Header {}
97
98    impl TryFrom<RawPartSetHeader> for Header {
99        type Error = Error;
100
101        fn try_from(value: RawPartSetHeader) -> Result<Self, Self::Error> {
102            if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE {
103                return Err(Error::invalid_hash_size());
104            }
105            Ok(Self {
106                total: value.total,
107                hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?,
108            })
109        }
110    }
111
112    impl From<Header> for RawPartSetHeader {
113        fn from(value: Header) -> Self {
114            RawPartSetHeader {
115                total: value.total,
116                hash: value.hash.into(),
117            }
118        }
119    }
120
121    impl TryFrom<RawCanonicalPartSetHeader> for Header {
122        type Error = Error;
123
124        fn try_from(value: RawCanonicalPartSetHeader) -> Result<Self, Self::Error> {
125            if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE {
126                return Err(Error::invalid_hash_size());
127            }
128            Ok(Self {
129                total: value.total,
130                hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?,
131            })
132        }
133    }
134
135    impl From<Header> for RawCanonicalPartSetHeader {
136        fn from(value: Header) -> Self {
137            RawCanonicalPartSetHeader {
138                total: value.total,
139                hash: value.hash.into(),
140            }
141        }
142    }
143}
144
145mod v1beta1 {
146    use super::Header;
147    use crate::{
148        error::Error,
149        hash::{Algorithm, SHA256_HASH_SIZE},
150        prelude::*,
151        Hash,
152    };
153    use cometbft_proto::types::v1beta1::{
154        CanonicalPartSetHeader as RawCanonicalPartSetHeader, PartSetHeader as RawPartSetHeader,
155    };
156    use cometbft_proto::Protobuf;
157
158    impl Protobuf<RawPartSetHeader> for Header {}
159
160    impl TryFrom<RawPartSetHeader> for Header {
161        type Error = Error;
162
163        fn try_from(value: RawPartSetHeader) -> Result<Self, Self::Error> {
164            if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE {
165                return Err(Error::invalid_hash_size());
166            }
167            Ok(Self {
168                total: value.total,
169                hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?,
170            })
171        }
172    }
173
174    impl From<Header> for RawPartSetHeader {
175        fn from(value: Header) -> Self {
176            RawPartSetHeader {
177                total: value.total,
178                hash: value.hash.into(),
179            }
180        }
181    }
182
183    impl TryFrom<RawCanonicalPartSetHeader> for Header {
184        type Error = Error;
185
186        fn try_from(value: RawCanonicalPartSetHeader) -> Result<Self, Self::Error> {
187            if !value.hash.is_empty() && value.hash.len() != SHA256_HASH_SIZE {
188                return Err(Error::invalid_hash_size());
189            }
190            Ok(Self {
191                total: value.total,
192                hash: Hash::from_bytes(Algorithm::Sha256, &value.hash)?,
193            })
194        }
195    }
196
197    impl From<Header> for RawCanonicalPartSetHeader {
198        fn from(value: Header) -> Self {
199            RawCanonicalPartSetHeader {
200                total: value.total,
201                hash: value.hash.into(),
202            }
203        }
204    }
205}
206
207impl Header {
208    /// constructor
209    pub fn new(total: u32, hash: Hash) -> Result<Self, Error> {
210        if total == 0 && hash != Hash::None {
211            return Err(Error::invalid_part_set_header(
212                "zero total with existing hash".to_string(),
213            ));
214        }
215        if total != 0 && hash == Hash::None {
216            return Err(Error::invalid_part_set_header(
217                "non-zero total with empty hash".to_string(),
218            ));
219        }
220        Ok(Header { total, hash })
221    }
222}