casper_types/block/
block_hash.rs

1use 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/// The cryptographic hash of a [`Block`].
30#[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    /// The number of bytes in a `BlockHash` digest.
44    pub const LENGTH: usize = Digest::LENGTH;
45
46    /// Constructs a new `BlockHash`.
47    pub fn new(hash: Digest) -> Self {
48        BlockHash(hash)
49    }
50
51    /// Returns the wrapped inner digest.
52    pub fn inner(&self) -> &Digest {
53        &self.0
54    }
55
56    /// Hexadecimal representation of the hash.
57    pub fn to_hex_string(&self) -> String {
58        base16::encode_lower(self.inner())
59    }
60
61    // This method is not intended to be used by third party crates.
62    #[doc(hidden)]
63    #[cfg(feature = "json-schema")]
64    pub fn example() -> &'static Self {
65        &BLOCK_HASH
66    }
67
68    /// Returns a new `DeployHash` directly initialized with the provided bytes; no hashing is done.
69    #[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    /// Returns a random `DeployHash`.
75    #[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}