casper_types/block/
block_hash.rs1use alloc::{string::String, vec::Vec};
2use core::fmt::{self, Display, Formatter};
3
4#[cfg(feature = "datasize")]
5use datasize::DataSize;
6#[cfg(feature = "json-schema")]
7use once_cell::sync::Lazy;
8#[cfg(any(feature = "testing", test))]
9use rand::Rng;
10#[cfg(feature = "json-schema")]
11use schemars::JsonSchema;
12use serde::{Deserialize, Serialize};
13
14#[cfg(doc)]
15use super::Block;
16#[cfg(doc)]
17use super::BlockV2;
18#[cfg(any(feature = "testing", test))]
19use crate::testing::TestRng;
20use crate::{
21 bytesrepr::{self, FromBytes, ToBytes},
22 Digest,
23};
24
25#[cfg(feature = "json-schema")]
26static BLOCK_HASH: Lazy<BlockHash> =
27 Lazy::new(|| BlockHash::new(Digest::from([7; BlockHash::LENGTH])));
28
29#[derive(
31 Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize, Debug, Default,
32)]
33#[cfg_attr(feature = "datasize", derive(DataSize))]
34#[cfg_attr(
35 feature = "json-schema",
36 derive(JsonSchema),
37 schemars(description = "Hex-encoded cryptographic hash of a block.")
38)]
39#[serde(deny_unknown_fields)]
40pub struct BlockHash(Digest);
41
42impl BlockHash {
43 pub const LENGTH: usize = Digest::LENGTH;
45
46 pub fn new(hash: Digest) -> Self {
48 BlockHash(hash)
49 }
50
51 pub fn inner(&self) -> &Digest {
53 &self.0
54 }
55
56 pub fn to_hex_string(&self) -> String {
58 base16::encode_lower(self.inner())
59 }
60
61 #[doc(hidden)]
63 #[cfg(feature = "json-schema")]
64 pub fn example() -> &'static Self {
65 &BLOCK_HASH
66 }
67
68 #[cfg(any(feature = "testing", test))]
70 pub const fn from_raw(raw_digest: [u8; Self::LENGTH]) -> Self {
71 BlockHash(Digest::from_raw(raw_digest))
72 }
73
74 #[cfg(any(feature = "testing", test))]
76 pub fn random(rng: &mut TestRng) -> Self {
77 let hash = rng.gen::<[u8; Self::LENGTH]>().into();
78 BlockHash(hash)
79 }
80}
81
82impl From<Digest> for BlockHash {
83 fn from(digest: Digest) -> Self {
84 Self(digest)
85 }
86}
87
88impl From<BlockHash> for Digest {
89 fn from(block_hash: BlockHash) -> Self {
90 block_hash.0
91 }
92}
93
94impl Display for BlockHash {
95 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
96 write!(formatter, "block-hash({})", self.0)
97 }
98}
99
100impl AsRef<[u8]> for BlockHash {
101 fn as_ref(&self) -> &[u8] {
102 self.0.as_ref()
103 }
104}
105
106impl ToBytes for BlockHash {
107 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
108 self.0.write_bytes(writer)
109 }
110
111 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
112 self.0.to_bytes()
113 }
114
115 fn serialized_length(&self) -> usize {
116 self.0.serialized_length()
117 }
118}
119
120impl FromBytes for BlockHash {
121 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
122 Digest::from_bytes(bytes).map(|(inner, remainder)| (BlockHash(inner), remainder))
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn bytesrepr_roundtrip() {
132 let rng = &mut TestRng::new();
133 let hash = BlockHash::random(rng);
134 bytesrepr::test_serialization_roundtrip(&hash);
135 }
136}