1use crate::error::ModelsError;
2use crate::prehash::PreHashed;
3use crate::secure_share::Id;
4use massa_hash::{Hash, HashDeserializer};
5use massa_serialization::{
6 DeserializeError, Deserializer, SerializeError, Serializer, U64VarIntDeserializer,
7 U64VarIntSerializer,
8};
9use nom::{
10 error::{context, ContextError, ErrorKind, ParseError},
11 IResult,
12};
13use serde_with::{DeserializeFromStr, SerializeDisplay};
14use std::collections::Bound::Included;
15use std::str::FromStr;
16use transition::Versioned;
17
18#[allow(missing_docs)]
20#[transition::versioned(versions("0"))]
21#[derive(
22 Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, SerializeDisplay, DeserializeFromStr,
23)]
24pub struct BlockId(pub Hash);
25
26impl PreHashed for BlockId {}
27
28impl Id for BlockId {
29 fn new(hash: Hash) -> Self {
30 BlockId::BlockIdV0(BlockIdV0(hash))
31 }
32
33 fn get_hash(&self) -> &Hash {
34 match self {
35 BlockId::BlockIdV0(block_id) => block_id.get_hash(),
36 }
37 }
38}
39
40impl BlockId {
41 pub fn get_first_bit(&self) -> bool {
43 match self {
44 BlockId::BlockIdV0(block_id) => block_id.get_first_bit(),
45 }
46 }
47
48 pub fn get_version(&self) -> u64 {
50 match self {
51 BlockId::BlockIdV0(block_id) => block_id.get_version(),
52 }
53 }
54
55 #[cfg(any(test, feature = "test-exports"))]
57 pub fn generate_from_hash(hash: Hash) -> BlockId {
58 BlockId::BlockIdV0(BlockIdV0(hash))
59 }
60}
61
62#[transition::impl_version(versions("0"))]
63impl BlockId {
64 fn get_hash(&self) -> &Hash {
65 &self.0
66 }
67
68 pub fn get_first_bit(&self) -> bool {
70 self.0.to_bytes()[0] >> 7 == 1
71 }
72
73 pub fn get_version(&self) -> u64 {
75 Self::VERSION
76 }
77}
78
79const BLOCKID_PREFIX: char = 'B';
80
81impl std::fmt::Display for BlockId {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 match self {
84 BlockId::BlockIdV0(block_id) => write!(f, "{}", block_id),
85 }
86 }
87}
88
89#[transition::impl_version(versions("0"))]
90impl std::fmt::Display for BlockId {
91 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
92 let u64_serializer = U64VarIntSerializer::new();
93 let mut bytes: Vec<u8> = Vec::new();
95 u64_serializer
96 .serialize(&Self::VERSION, &mut bytes)
97 .map_err(|_| std::fmt::Error)?;
98 bytes.extend(self.0.to_bytes());
99 write!(
100 f,
101 "{}{}",
102 BLOCKID_PREFIX,
103 bs58::encode(bytes).with_check().into_string()
104 )
105 }
106}
107
108impl std::fmt::Debug for BlockId {
109 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
110 write!(f, "{}", self)
111 }
112}
113
114impl FromStr for BlockId {
115 type Err = ModelsError;
116 fn from_str(s: &str) -> Result<Self, Self::Err> {
129 let mut chars = s.chars();
130 match chars.next() {
131 Some(prefix) if prefix == BLOCKID_PREFIX => {
132 let data = chars.collect::<String>();
133 let decoded_bs58_check = bs58::decode(data)
134 .with_check(None)
135 .into_vec()
136 .map_err(|_| ModelsError::BlockIdParseError)?;
137 let block_id_deserializer = BlockIdDeserializer::new();
138 let (rest, block_id) = block_id_deserializer
139 .deserialize::<DeserializeError>(&decoded_bs58_check[..])
140 .map_err(|_| ModelsError::OperationIdParseError)?;
141 if rest.is_empty() {
142 Ok(block_id)
143 } else {
144 Err(ModelsError::OperationIdParseError)
145 }
146 }
147 _ => Err(ModelsError::BlockIdParseError),
148 }
149 }
150}
151
152#[transition::impl_version(versions("0"))]
153impl FromStr for BlockId {
154 type Err = ModelsError;
155 fn from_str(s: &str) -> Result<Self, Self::Err> {
156 let mut chars = s.chars();
157 match chars.next() {
158 Some(prefix) if prefix == BLOCKID_PREFIX => {
159 let data = chars.collect::<String>();
160 let decoded_bs58_check = bs58::decode(data)
161 .with_check(None)
162 .into_vec()
163 .map_err(|_| ModelsError::BlockIdParseError)?;
164 let block_id_deserializer = BlockIdDeserializer::new();
165 let (rest, block_id) = block_id_deserializer
166 .deserialize::<DeserializeError>(&decoded_bs58_check[..])
167 .map_err(|_| ModelsError::OperationIdParseError)?;
168 if rest.is_empty() {
169 Ok(block_id)
170 } else {
171 Err(ModelsError::OperationIdParseError)
172 }
173 }
174 _ => Err(ModelsError::BlockIdParseError),
175 }
176 }
177}
178
179#[derive(Default, Clone)]
181pub struct BlockIdSerializer {
182 version_serializer: U64VarIntSerializer,
183}
184
185impl BlockIdSerializer {
186 pub fn new() -> Self {
188 Self {
189 version_serializer: U64VarIntSerializer::new(),
190 }
191 }
192}
193
194impl Serializer<BlockId> for BlockIdSerializer {
195 fn serialize(&self, value: &BlockId, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
196 self.version_serializer
197 .serialize(&value.get_version(), buffer)?;
198 match value {
199 BlockId::BlockIdV0(block_id) => self.serialize(block_id, buffer),
200 }
201 }
202}
203
204#[transition::impl_version(versions("0"), structures("BlockId"))]
205impl Serializer<BlockId> for BlockIdSerializer {
206 fn serialize(&self, value: &BlockId, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
207 buffer.extend(value.0.to_bytes());
208 Ok(())
209 }
210}
211
212#[derive(Clone)]
214pub struct BlockIdDeserializer {
215 hash_deserializer: HashDeserializer,
216 version_deserializer: U64VarIntDeserializer,
217}
218
219impl Default for BlockIdDeserializer {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224
225impl BlockIdDeserializer {
226 pub fn new() -> Self {
228 Self {
229 hash_deserializer: HashDeserializer::new(),
230 version_deserializer: U64VarIntDeserializer::new(Included(0), Included(u64::MAX)),
231 }
232 }
233}
234
235impl Deserializer<BlockId> for BlockIdDeserializer {
236 fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
237 &self,
238 buffer: &'a [u8],
239 ) -> IResult<&'a [u8], BlockId, E> {
240 if buffer.len() < 2 {
242 return Err(nom::Err::Error(E::from_error_kind(buffer, ErrorKind::Eof)));
243 }
244 let (rest, op_id_version) =
245 self.version_deserializer
246 .deserialize(buffer)
247 .map_err(|_: nom::Err<E>| {
248 nom::Err::Error(E::from_error_kind(buffer, ErrorKind::Eof))
249 })?;
250 match op_id_version {
251 <BlockId!["0"]>::VERSION => {
252 let (rest, op_id) = self.deserialize(rest)?;
253 Ok((rest, BlockIdVariant))
254 }
255 _ => Err(nom::Err::Error(E::from_error_kind(buffer, ErrorKind::Eof))),
256 }
257 }
258}
259
260#[transition::impl_version(versions("0"), structures("BlockId"))]
261impl Deserializer<BlockId> for BlockIdDeserializer {
262 fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
263 &self,
264 buffer: &'a [u8],
265 ) -> IResult<&'a [u8], BlockId, E> {
266 context("Failed BlockId deserialization", |input| {
267 let (rest, hash) = self.hash_deserializer.deserialize(input)?;
268 Ok((rest, BlockId(hash)))
269 })(buffer)
270 }
271}
272
273#[cfg(test)]
274mod test {
275 use super::*;
276
277 #[test]
278 fn test_block_id() {
279 let expected_block_id =
280 BlockId::from_str("B12iL52kye2CraMXdkdKDxjZJXF9it6E4hz8KEj656QnhvwocvBX").unwrap();
281 let actual_block_id = BlockId::generate_from_hash(Hash::compute_from("blk".as_bytes()));
282
283 assert_eq!(actual_block_id, expected_block_id);
284 }
285
286 #[test]
287 fn test_block_id_errors() {
288 let actual_error = BlockId::from_str("SomeInvalidBlockId")
289 .unwrap_err()
290 .to_string();
291 let expected_error = "block id parsing error".to_string();
292
293 assert_eq!(actual_error, expected_error);
294 }
295
296 #[test]
297 fn test_block_id_serde() {
298 let expected_block_id =
299 BlockId::from_str("B12DvrcQkzF1Wi8BVoNfc4n93CD3E2qhCNe7nVhnEQGWHZ24fEmg").unwrap();
300
301 let serialized = serde_json::to_string(&expected_block_id).unwrap();
302 let actual_block_id: BlockId = serde_json::from_str(&serialized).unwrap();
303
304 assert_eq!(actual_block_id, expected_block_id);
305 }
306}