casper_types/transaction/
transaction_hash.rs1use alloc::{string::String, vec::Vec};
2use core::fmt::{self, Display, Formatter};
3
4#[cfg(feature = "datasize")]
5use datasize::DataSize;
6#[cfg(any(feature = "testing", test))]
7use rand::Rng;
8#[cfg(feature = "json-schema")]
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11
12use super::{DeployHash, TransactionV1Hash};
13#[cfg(any(feature = "testing", test))]
14use crate::testing::TestRng;
15use crate::{
16 bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
17 Digest,
18};
19
20const DEPLOY_TAG: u8 = 0;
21const V1_TAG: u8 = 1;
22const TAG_LENGTH: u8 = 1;
23
24#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize, Debug)]
26#[cfg_attr(feature = "datasize", derive(DataSize))]
27#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
28#[serde(deny_unknown_fields)]
29pub enum TransactionHash {
30 Deploy(DeployHash),
32 #[serde(rename = "Version1")]
34 V1(TransactionV1Hash),
35}
36
37impl TransactionHash {
38 pub const LENGTH: usize = TAG_LENGTH as usize + Digest::LENGTH;
40 pub fn digest(&self) -> Digest {
42 match self {
43 TransactionHash::Deploy(deploy_hash) => *deploy_hash.inner(),
44 TransactionHash::V1(transaction_hash) => *transaction_hash.inner(),
45 }
46 }
47
48 pub fn to_hex_string(&self) -> String {
50 base16::encode_lower(&self.digest())
51 }
52
53 #[cfg(any(feature = "testing", test))]
55 pub fn random(rng: &mut TestRng) -> Self {
56 match rng.gen_range(0..2) {
57 0 => TransactionHash::from(DeployHash::random(rng)),
58 1 => TransactionHash::from(TransactionV1Hash::random(rng)),
59 _ => panic!(),
60 }
61 }
62
63 pub const fn from_raw(raw_digest: [u8; TransactionV1Hash::LENGTH]) -> Self {
66 TransactionHash::V1(TransactionV1Hash::from_raw(raw_digest))
67 }
68}
69
70impl From<DeployHash> for TransactionHash {
71 fn from(hash: DeployHash) -> Self {
72 Self::Deploy(hash)
73 }
74}
75
76impl From<&DeployHash> for TransactionHash {
77 fn from(hash: &DeployHash) -> Self {
78 Self::from(*hash)
79 }
80}
81
82impl From<TransactionV1Hash> for TransactionHash {
83 fn from(hash: TransactionV1Hash) -> Self {
84 Self::V1(hash)
85 }
86}
87
88impl From<&TransactionV1Hash> for TransactionHash {
89 fn from(hash: &TransactionV1Hash) -> Self {
90 Self::from(*hash)
91 }
92}
93
94impl Default for TransactionHash {
95 fn default() -> Self {
96 TransactionHash::V1(TransactionV1Hash::default())
97 }
98}
99
100impl Display for TransactionHash {
101 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
102 match self {
103 TransactionHash::Deploy(hash) => Display::fmt(hash, formatter),
104 TransactionHash::V1(hash) => Display::fmt(hash, formatter),
105 }
106 }
107}
108
109impl AsRef<[u8]> for TransactionHash {
110 fn as_ref(&self) -> &[u8] {
111 match self {
112 TransactionHash::Deploy(hash) => hash.as_ref(),
113 TransactionHash::V1(hash) => hash.as_ref(),
114 }
115 }
116}
117
118impl ToBytes for TransactionHash {
119 fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
120 let mut buffer = bytesrepr::allocate_buffer(self)?;
121 self.write_bytes(&mut buffer)?;
122 Ok(buffer)
123 }
124
125 fn serialized_length(&self) -> usize {
126 U8_SERIALIZED_LENGTH
127 + match self {
128 TransactionHash::Deploy(hash) => hash.serialized_length(),
129 TransactionHash::V1(hash) => hash.serialized_length(),
130 }
131 }
132
133 fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
134 match self {
135 TransactionHash::Deploy(hash) => {
136 DEPLOY_TAG.write_bytes(writer)?;
137 hash.write_bytes(writer)
138 }
139 TransactionHash::V1(hash) => {
140 V1_TAG.write_bytes(writer)?;
141 hash.write_bytes(writer)
142 }
143 }
144 }
145}
146
147impl FromBytes for TransactionHash {
148 fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
149 let (tag, remainder) = u8::from_bytes(bytes)?;
150 match tag {
151 DEPLOY_TAG => {
152 let (hash, remainder) = DeployHash::from_bytes(remainder)?;
153 Ok((TransactionHash::Deploy(hash), remainder))
154 }
155 V1_TAG => {
156 let (hash, remainder) = TransactionV1Hash::from_bytes(remainder)?;
157 Ok((TransactionHash::V1(hash), remainder))
158 }
159 _ => Err(bytesrepr::Error::Formatting),
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use crate::testing::TestRng;
168 #[test]
169 fn bytesrepr_roundtrip() {
170 let rng = &mut TestRng::new();
171
172 let hash = TransactionHash::from(DeployHash::random(rng));
173 bytesrepr::test_serialization_roundtrip(&hash);
174
175 let hash = TransactionHash::from(TransactionV1Hash::random(rng));
176 bytesrepr::test_serialization_roundtrip(&hash);
177 }
178}