1mod block_header_v1;
2mod block_header_v2;
3
4pub use block_header_v1::BlockHeaderV1;
5pub use block_header_v2::BlockHeaderV2;
6
7use alloc::{collections::BTreeMap, vec::Vec};
8use core::fmt::{self, Display, Formatter};
9
10#[cfg(feature = "std")]
11use crate::ProtocolConfig;
12#[cfg(feature = "datasize")]
13use datasize::DataSize;
14#[cfg(feature = "json-schema")]
15use schemars::JsonSchema;
16#[cfg(any(feature = "std", test))]
17use serde::{Deserialize, Serialize};
18
19use crate::{
20 bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
21 BlockHash, Digest, EraEnd, EraId, ProtocolVersion, PublicKey, Timestamp, U512,
22};
23
24const TAG_LENGTH: usize = U8_SERIALIZED_LENGTH;
25
26pub const BLOCK_HEADER_V1_TAG: u8 = 0;
28pub const BLOCK_HEADER_V2_TAG: u8 = 1;
30
31#[derive(Clone, Debug, Eq, PartialEq)]
34#[cfg_attr(any(feature = "std", test), derive(Serialize, Deserialize))]
35#[cfg_attr(feature = "datasize", derive(DataSize))]
36#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
37pub enum BlockHeader {
38 #[cfg_attr(any(feature = "std", test), serde(rename = "Version1"))]
40 V1(BlockHeaderV1),
41 #[cfg_attr(any(feature = "std", test), serde(rename = "Version2"))]
43 V2(BlockHeaderV2),
44}
45
46impl BlockHeader {
47 pub fn block_hash(&self) -> BlockHash {
49 match self {
50 BlockHeader::V1(v1) => v1.block_hash(),
51 BlockHeader::V2(v2) => v2.block_hash(),
52 }
53 }
54
55 pub fn parent_hash(&self) -> &BlockHash {
57 match self {
58 BlockHeader::V1(v1) => v1.parent_hash(),
59 BlockHeader::V2(v2) => v2.parent_hash(),
60 }
61 }
62
63 pub fn state_root_hash(&self) -> &Digest {
65 match self {
66 BlockHeader::V1(v1) => v1.state_root_hash(),
67 BlockHeader::V2(v2) => v2.state_root_hash(),
68 }
69 }
70
71 pub fn body_hash(&self) -> &Digest {
73 match self {
74 BlockHeader::V1(v1) => v1.body_hash(),
75 BlockHeader::V2(v2) => v2.body_hash(),
76 }
77 }
78
79 pub fn random_bit(&self) -> bool {
81 match self {
82 BlockHeader::V1(v1) => v1.random_bit(),
83 BlockHeader::V2(v2) => v2.random_bit(),
84 }
85 }
86
87 pub fn accumulated_seed(&self) -> &Digest {
89 match self {
90 BlockHeader::V1(v1) => v1.accumulated_seed(),
91 BlockHeader::V2(v2) => v2.accumulated_seed(),
92 }
93 }
94
95 pub fn clone_era_end(&self) -> Option<EraEnd> {
97 match self {
98 BlockHeader::V1(v1) => v1.era_end().map(|ee| ee.clone().into()),
99 BlockHeader::V2(v2) => v2.era_end().map(|ee| ee.clone().into()),
100 }
101 }
102
103 pub fn maybe_equivocators(&self) -> Option<&[PublicKey]> {
105 match self {
106 BlockHeader::V1(v1) => v1.era_end().map(|ee| ee.equivocators()),
107 BlockHeader::V2(v2) => v2.era_end().map(|ee| ee.equivocators()),
108 }
109 }
110
111 pub fn maybe_inactive_validators(&self) -> Option<&[PublicKey]> {
113 match self {
114 BlockHeader::V1(v1) => v1.era_end().map(|ee| ee.inactive_validators()),
115 BlockHeader::V2(v2) => v2.era_end().map(|ee| ee.inactive_validators()),
116 }
117 }
118
119 pub fn timestamp(&self) -> Timestamp {
121 match self {
122 BlockHeader::V1(v1) => v1.timestamp(),
123 BlockHeader::V2(v2) => v2.timestamp(),
124 }
125 }
126
127 pub fn era_id(&self) -> EraId {
129 match self {
130 BlockHeader::V1(v1) => v1.era_id(),
131 BlockHeader::V2(v2) => v2.era_id(),
132 }
133 }
134
135 pub fn next_block_era_id(&self) -> EraId {
138 match self {
139 BlockHeader::V1(v1) => v1.next_block_era_id(),
140 BlockHeader::V2(v2) => v2.next_block_era_id(),
141 }
142 }
143
144 pub fn height(&self) -> u64 {
146 match self {
147 BlockHeader::V1(v1) => v1.height(),
148 BlockHeader::V2(v2) => v2.height(),
149 }
150 }
151
152 pub fn protocol_version(&self) -> ProtocolVersion {
154 match self {
155 BlockHeader::V1(v1) => v1.protocol_version(),
156 BlockHeader::V2(v2) => v2.protocol_version(),
157 }
158 }
159
160 pub fn is_switch_block(&self) -> bool {
162 match self {
163 BlockHeader::V1(v1) => v1.is_switch_block(),
164 BlockHeader::V2(v2) => v2.is_switch_block(),
165 }
166 }
167
168 pub fn next_era_validator_weights(&self) -> Option<&BTreeMap<PublicKey, U512>> {
171 match self {
172 BlockHeader::V1(v1) => v1.next_era_validator_weights(),
173 BlockHeader::V2(v2) => v2.next_era_validator_weights(),
174 }
175 }
176
177 pub fn is_genesis(&self) -> bool {
179 match self {
180 BlockHeader::V1(v1) => v1.is_genesis(),
181 BlockHeader::V2(v2) => v2.is_genesis(),
182 }
183 }
184
185 #[cfg(feature = "std")]
188 pub fn is_last_block_before_activation(&self, protocol_config: &ProtocolConfig) -> bool {
189 match self {
190 BlockHeader::V1(v1) => v1.is_last_block_before_activation(protocol_config),
191 BlockHeader::V2(v2) => v2.is_last_block_before_activation(protocol_config),
192 }
193 }
194
195 #[doc(hidden)]
199 #[cfg(any(feature = "once_cell", test))]
200 pub fn set_block_hash(&self, block_hash: BlockHash) {
201 match self {
202 BlockHeader::V1(v1) => v1.set_block_hash(block_hash),
203 BlockHeader::V2(v2) => v2.set_block_hash(block_hash),
204 }
205 }
206}
207
208impl Display for BlockHeader {
209 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
210 match self {
211 BlockHeader::V1(v1) => Display::fmt(&v1, formatter),
212 BlockHeader::V2(v2) => Display::fmt(&v2, formatter),
213 }
214 }
215}
216
217impl From<BlockHeaderV1> for BlockHeader {
218 fn from(header: BlockHeaderV1) -> Self {
219 BlockHeader::V1(header)
220 }
221}
222
223impl From<BlockHeaderV2> for BlockHeader {
224 fn from(header: BlockHeaderV2) -> Self {
225 BlockHeader::V2(header)
226 }
227}
228
229impl ToBytes for BlockHeader {
230 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
231 let mut buffer = bytesrepr::allocate_buffer(self)?;
232 match self {
233 BlockHeader::V1(v1) => {
234 buffer.insert(0, BLOCK_HEADER_V1_TAG);
235 buffer.extend(v1.to_bytes()?);
236 }
237 BlockHeader::V2(v2) => {
238 buffer.insert(0, BLOCK_HEADER_V2_TAG);
239 buffer.extend(v2.to_bytes()?);
240 }
241 }
242 Ok(buffer)
243 }
244
245 fn serialized_length(&self) -> usize {
246 TAG_LENGTH
247 + match self {
248 BlockHeader::V1(v1) => v1.serialized_length(),
249 BlockHeader::V2(v2) => v2.serialized_length(),
250 }
251 }
252}
253
254impl FromBytes for BlockHeader {
255 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
256 let (tag, remainder) = u8::from_bytes(bytes)?;
257 match tag {
258 BLOCK_HEADER_V1_TAG => {
259 let (header, remainder): (BlockHeaderV1, _) = FromBytes::from_bytes(remainder)?;
260 Ok((Self::V1(header), remainder))
261 }
262 BLOCK_HEADER_V2_TAG => {
263 let (header, remainder): (BlockHeaderV2, _) = FromBytes::from_bytes(remainder)?;
264 Ok((Self::V2(header), remainder))
265 }
266 _ => Err(bytesrepr::Error::Formatting),
267 }
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use crate::{bytesrepr, testing::TestRng, TestBlockBuilder, TestBlockV1Builder};
274
275 #[test]
276 fn bytesrepr_roundtrip() {
277 let rng = &mut TestRng::new();
278
279 let block_header_v1 = TestBlockV1Builder::new()
280 .build_versioned(rng)
281 .clone_header();
282 bytesrepr::test_serialization_roundtrip(&block_header_v1);
283
284 let block_header_v2 = TestBlockBuilder::new().build_versioned(rng).clone_header();
285 bytesrepr::test_serialization_roundtrip(&block_header_v2);
286 }
287}