casper_types/block/
block_header.rs

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
26/// Tag for block header v1.
27pub const BLOCK_HEADER_V1_TAG: u8 = 0;
28/// Tag for block header v2.
29pub const BLOCK_HEADER_V2_TAG: u8 = 1;
30
31/// The versioned header portion of a block. It encapsulates different variants of the BlockHeader
32/// struct.
33#[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    /// The legacy, initial version of the header portion of a block.
39    #[cfg_attr(any(feature = "std", test), serde(rename = "Version1"))]
40    V1(BlockHeaderV1),
41    /// The version 2 of the header portion of a block.
42    #[cfg_attr(any(feature = "std", test), serde(rename = "Version2"))]
43    V2(BlockHeaderV2),
44}
45
46impl BlockHeader {
47    /// Returns the hash of this block header.
48    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    /// Returns the parent block's hash.
56    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    /// Returns the root hash of global state after the deploys in this block have been executed.
64    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    /// Returns the hash of the block's body.
72    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    /// Returns a random bit needed for initializing a future era.
80    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    /// Returns a seed needed for initializing a future era.
88    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    /// Returns the `EraEnd` of a block if it is a switch block.
96    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    /// Returns equivocators if the header is of a switch block.
104    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    /// Returns equivocators if the header is of a switch block.
112    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    /// Returns the timestamp from when the block was proposed.
120    pub fn timestamp(&self) -> Timestamp {
121        match self {
122            BlockHeader::V1(v1) => v1.timestamp(),
123            BlockHeader::V2(v2) => v2.timestamp(),
124        }
125    }
126
127    /// Returns the era ID in which this block was created.
128    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    /// Returns the era ID in which the next block would be created (i.e. this block's era ID, or
136    /// its successor if this is a switch block).
137    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    /// Returns the height of this block, i.e. the number of ancestors.
145    pub fn height(&self) -> u64 {
146        match self {
147            BlockHeader::V1(v1) => v1.height(),
148            BlockHeader::V2(v2) => v2.height(),
149        }
150    }
151
152    /// Returns the protocol version of the network from when this block was created.
153    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    /// Returns `true` if this block is the last one in the current era.
161    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    /// Returns the validators for the upcoming era and their respective weights (if this is a
169    /// switch block).
170    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    /// Returns `true` if this block is the Genesis block, i.e. has height 0 and era 0.
178    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    /// Returns `true` if this block belongs to the last block before the upgrade to the
186    /// current protocol version.
187    #[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    // This method is not intended to be used by third party crates.
196    //
197    // Sets the block hash without recomputing it. Must only be called with the correct hash.
198    #[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}