1use bitvec::vec::BitVec;
2use massa_hash::{HashXof, HashXofDeserializer, HashXofSerializer, HASH_XOF_SIZE_BYTES};
3use massa_models::{
4 address::{Address, AddressDeserializer, AddressSerializer},
5 prehash::PreHashMap,
6 serialization::{BitVecDeserializer, BitVecSerializer},
7};
8use massa_serialization::{
9 Deserializer, OptionDeserializer, OptionSerializer, SerializeError, Serializer,
10 U64VarIntDeserializer, U64VarIntSerializer,
11};
12use nom::{
13 branch::alt,
14 bytes::complete::tag,
15 combinator::value,
16 error::{context, ContextError, ParseError},
17 multi::length_count,
18 sequence::tuple,
19 IResult, Parser,
20};
21use num::rational::Ratio;
22use serde::{Deserialize, Serialize};
23use std::collections::BTreeMap;
24use std::ops::Bound::Included;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct CycleInfo {
29 pub cycle: u64,
31 pub complete: bool,
33 pub roll_counts: BTreeMap<Address, u64>,
35 pub rng_seed: BitVec<u8>,
37 pub production_stats: PreHashMap<Address, ProductionStats>,
39 pub final_state_hash_snapshot: Option<HashXof<HASH_XOF_SIZE_BYTES>>,
42}
43
44impl CycleInfo {
45 pub fn new(
47 cycle: u64,
48 complete: bool,
49 roll_counts: BTreeMap<Address, u64>,
50 rng_seed: BitVec<u8>,
51 production_stats: PreHashMap<Address, ProductionStats>,
52 ) -> Self {
53 CycleInfo {
55 cycle,
56 complete,
57 roll_counts,
58 rng_seed,
59 production_stats,
60 final_state_hash_snapshot: None,
61 }
62 }
63}
64
65#[derive(Clone)]
66#[allow(missing_docs)]
67pub struct CycleInfoSerializer {
69 pub u64_ser: U64VarIntSerializer,
70 pub bitvec_ser: BitVecSerializer,
71 pub production_stats_ser: ProductionStatsSerializer,
72 pub address_ser: AddressSerializer,
73 pub opt_hash_ser: OptionSerializer<HashXof<HASH_XOF_SIZE_BYTES>, HashXofSerializer>,
74}
75
76impl Default for CycleInfoSerializer {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82impl CycleInfoSerializer {
83 pub fn new() -> Self {
85 Self {
86 u64_ser: U64VarIntSerializer::new(),
87 bitvec_ser: BitVecSerializer::new(),
88 production_stats_ser: ProductionStatsSerializer::new(),
89 address_ser: AddressSerializer::new(),
90 opt_hash_ser: OptionSerializer::new(HashXofSerializer::new()),
91 }
92 }
93}
94
95impl Serializer<CycleInfo> for CycleInfoSerializer {
96 fn serialize(&self, value: &CycleInfo, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
97 self.u64_ser.serialize(&value.cycle, buffer)?;
99
100 buffer.push(u8::from(value.complete));
102
103 self.u64_ser
105 .serialize(&(value.roll_counts.len() as u64), buffer)?;
106 for (addr, count) in &value.roll_counts {
107 self.address_ser.serialize(addr, buffer)?;
108 self.u64_ser.serialize(count, buffer)?;
109 }
110
111 self.bitvec_ser.serialize(&value.rng_seed, buffer)?;
113
114 self.production_stats_ser
116 .serialize(&value.production_stats, buffer)?;
117
118 self.opt_hash_ser
120 .serialize(&value.final_state_hash_snapshot, buffer)?;
121
122 Ok(())
123 }
124}
125
126#[derive(Clone)]
127#[allow(missing_docs)]
128pub struct CycleInfoDeserializer {
130 pub u64_deser: U64VarIntDeserializer,
131 pub rolls_deser: RollsDeserializer,
132 pub bitvec_deser: BitVecDeserializer,
133 pub production_stats_deser: ProductionStatsDeserializer,
134 pub opt_hash_deser: OptionDeserializer<HashXof<HASH_XOF_SIZE_BYTES>, HashXofDeserializer>,
135}
136
137impl CycleInfoDeserializer {
138 pub fn new(max_rolls_length: u64, max_production_stats_length: u64) -> CycleInfoDeserializer {
140 CycleInfoDeserializer {
141 u64_deser: U64VarIntDeserializer::new(Included(u64::MIN), Included(u64::MAX)),
142 rolls_deser: RollsDeserializer::new(max_rolls_length),
143 bitvec_deser: BitVecDeserializer::new(),
144 production_stats_deser: ProductionStatsDeserializer::new(max_production_stats_length),
145 opt_hash_deser: OptionDeserializer::new(HashXofDeserializer::new()),
146 }
147 }
148}
149
150impl Deserializer<CycleInfo> for CycleInfoDeserializer {
151 fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
152 &self,
153 buffer: &'a [u8],
154 ) -> IResult<&'a [u8], CycleInfo, E> {
155 context(
156 "cycle_history",
157 tuple((
158 context("cycle", |input| self.u64_deser.deserialize(input)),
159 context(
160 "complete",
161 alt((value(true, tag(&[1])), value(false, tag(&[0])))),
162 ),
163 context("roll_counts", |input| self.rolls_deser.deserialize(input)),
164 context("rng_seed", |input| self.bitvec_deser.deserialize(input)),
165 context("production_stats", |input| {
166 self.production_stats_deser.deserialize(input)
167 }),
168 context("final_state_hash_snapshot", |input| {
169 self.opt_hash_deser.deserialize(input)
170 }),
171 )),
172 )
173 .map(
174 #[allow(clippy::type_complexity)]
175 |(cycle, complete, roll_counts, rng_seed, production_stats, opt_hash): (
176 u64, bool, Vec<(Address, u64)>, BitVec<u8>, PreHashMap<Address, ProductionStats>, Option<HashXof<HASH_XOF_SIZE_BYTES>>, )| {
183 let mut cycle = CycleInfo::new(
184 cycle,
185 complete,
186 roll_counts.into_iter().collect(),
187 rng_seed,
188 production_stats,
189 );
190 cycle.final_state_hash_snapshot = opt_hash;
191 cycle
192 },
193 )
194 .parse(buffer)
195 }
196}
197
198#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
200pub struct ProductionStats {
201 pub block_success_count: u64,
203 pub block_failure_count: u64,
205}
206
207impl ProductionStats {
208 pub fn is_satisfying(&self, max_miss_ratio: &Ratio<u64>) -> bool {
210 let opportunities_count = self.block_success_count + self.block_failure_count;
211 if opportunities_count == 0 {
212 return true;
213 }
214 &Ratio::new(self.block_failure_count, opportunities_count) <= max_miss_ratio
215 }
216
217 pub fn extend(&mut self, stats: &ProductionStats) {
219 self.block_success_count = self
220 .block_success_count
221 .saturating_add(stats.block_success_count);
222 self.block_failure_count = self
223 .block_failure_count
224 .saturating_add(stats.block_failure_count);
225 }
226}
227
228#[derive(Clone)]
229#[allow(missing_docs)]
230pub struct ProductionStatsSerializer {
232 pub u64_ser: U64VarIntSerializer,
233 address_ser: AddressSerializer,
234}
235
236impl Default for ProductionStatsSerializer {
237 fn default() -> Self {
238 Self::new()
239 }
240}
241
242impl ProductionStatsSerializer {
243 pub fn new() -> Self {
245 Self {
246 u64_ser: U64VarIntSerializer::new(),
247 address_ser: AddressSerializer::new(),
248 }
249 }
250}
251
252impl Serializer<PreHashMap<Address, ProductionStats>> for ProductionStatsSerializer {
253 fn serialize(
254 &self,
255 value: &PreHashMap<Address, ProductionStats>,
256 buffer: &mut Vec<u8>,
257 ) -> Result<(), SerializeError> {
258 self.u64_ser.serialize(&(value.len() as u64), buffer)?;
259 for (
260 addr,
261 ProductionStats {
262 block_success_count,
263 block_failure_count,
264 },
265 ) in value.iter()
266 {
267 self.address_ser.serialize(addr, buffer)?;
268 self.u64_ser.serialize(block_success_count, buffer)?;
269 self.u64_ser.serialize(block_failure_count, buffer)?;
270 }
271 Ok(())
272 }
273}
274
275#[derive(Clone)]
276#[allow(missing_docs)]
277pub struct ProductionStatsDeserializer {
279 length_deserializer: U64VarIntDeserializer,
280 pub address_deserializer: AddressDeserializer,
281 pub u64_deserializer: U64VarIntDeserializer,
282}
283
284impl ProductionStatsDeserializer {
285 pub fn new(max_production_stats_length: u64) -> ProductionStatsDeserializer {
287 ProductionStatsDeserializer {
288 length_deserializer: U64VarIntDeserializer::new(
289 Included(u64::MIN),
290 Included(max_production_stats_length),
291 ),
292 address_deserializer: AddressDeserializer::new(),
293 u64_deserializer: U64VarIntDeserializer::new(Included(u64::MIN), Included(u64::MAX)),
294 }
295 }
296}
297
298impl Deserializer<PreHashMap<Address, ProductionStats>> for ProductionStatsDeserializer {
299 fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
300 &self,
301 buffer: &'a [u8],
302 ) -> IResult<&'a [u8], PreHashMap<Address, ProductionStats>, E> {
303 context(
304 "Failed ProductionStats deserialization",
305 length_count(
306 context("Failed length deserialization", |input| {
307 self.length_deserializer.deserialize(input)
308 }),
309 tuple((
310 context("Failed address deserialization", |input| {
311 self.address_deserializer.deserialize(input)
312 }),
313 context("Failed block_success_count deserialization", |input| {
314 self.u64_deserializer.deserialize(input)
315 }),
316 context("Failed block_failure_count deserialization", |input| {
317 self.u64_deserializer.deserialize(input)
318 }),
319 )),
320 ),
321 )
322 .map(|elements| {
323 elements
324 .into_iter()
325 .map(|(addr, block_success_count, block_failure_count)| {
326 (
327 addr,
328 ProductionStats {
329 block_success_count,
330 block_failure_count,
331 },
332 )
333 })
334 .collect()
335 })
336 .parse(buffer)
337 }
338}
339
340#[derive(Clone)]
341#[allow(missing_docs)]
342pub struct RollsDeserializer {
344 length_deserializer: U64VarIntDeserializer,
345 pub address_deserializer: AddressDeserializer,
346 pub u64_deserializer: U64VarIntDeserializer,
347}
348
349impl RollsDeserializer {
350 pub fn new(max_rolls_length: u64) -> RollsDeserializer {
352 RollsDeserializer {
353 length_deserializer: U64VarIntDeserializer::new(
354 Included(u64::MIN),
355 Included(max_rolls_length),
356 ),
357 address_deserializer: AddressDeserializer::new(),
358 u64_deserializer: U64VarIntDeserializer::new(Included(u64::MIN), Included(u64::MAX)),
359 }
360 }
361}
362
363impl Deserializer<Vec<(Address, u64)>> for RollsDeserializer {
364 fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
365 &self,
366 buffer: &'a [u8],
367 ) -> IResult<&'a [u8], Vec<(Address, u64)>, E> {
368 context(
369 "Failed rolls deserialization",
370 length_count(
371 context("Failed length deserialization", |input| {
372 self.length_deserializer.deserialize(input)
373 }),
374 tuple((
375 context("Failed address deserialization", |input| {
376 self.address_deserializer.deserialize(input)
377 }),
378 context("Failed number deserialization", |input| {
379 self.u64_deserializer.deserialize(input)
380 }),
381 )),
382 ),
383 )
384 .parse(buffer)
385 }
386}
387
388#[cfg(test)]
389mod test {
390 use super::*;
391 use massa_models::config::{MAX_PRODUCTION_STATS_LENGTH, MAX_ROLLS_COUNT_LENGTH};
392 use massa_serialization::DeserializeError;
393 use std::str::FromStr;
394
395 fn create_cycle_info() -> (CycleInfo, Address, Address) {
396 let addr1 =
397 Address::from_str("AU1jUbxeXW49QRT6Le5aPuNdcGWQV2kpnDyQkKoka4MmEUW3m8Xm").unwrap();
398 let addr2 =
399 Address::from_str("AU12nfJdBNotWffSEDDCS9mMXAxDbHbAVM9GW7pvVJoLxdCeeroX8").unwrap();
400 let mut prod_stats = PreHashMap::default();
401 prod_stats.insert(addr1, ProductionStats::default());
402 prod_stats.insert(
403 addr2,
404 ProductionStats {
405 block_success_count: 65539,
406 block_failure_count: 2,
407 },
408 );
409
410 let mut cycle_info1 = CycleInfo::new(
411 0,
412 false,
413 BTreeMap::from([(addr1, 1), (addr2, 100)]),
414 BitVec::new(),
415 prod_stats,
416 );
417 cycle_info1.final_state_hash_snapshot = Some(HashXof::from_bytes(&[2u8; 512]));
418
419 (cycle_info1, addr1, addr2)
420 }
421
422 #[test]
423 fn test_cycle_info_ser_der() {
424 let (cycle_info1, _, _) = create_cycle_info();
425
426 let mut buf = Vec::new();
427 let serializer = CycleInfoSerializer::new();
428 let deserializer =
429 CycleInfoDeserializer::new(MAX_ROLLS_COUNT_LENGTH, MAX_PRODUCTION_STATS_LENGTH);
430
431 serializer.serialize(&cycle_info1, &mut buf).unwrap();
432 let (rem, cycle_der) = deserializer.deserialize::<DeserializeError>(&buf).unwrap();
433 assert!(rem.is_empty());
434 assert_eq!(cycle_der, cycle_info1);
435
436 let deserializer2 = CycleInfoDeserializer::new(1, MAX_PRODUCTION_STATS_LENGTH);
438 let deserializer3 = CycleInfoDeserializer::new(MAX_ROLLS_COUNT_LENGTH, 1);
439
440 buf.clear();
441 serializer.serialize(&cycle_info1, &mut buf).unwrap();
442 let res2 = deserializer2.deserialize::<DeserializeError>(&buf);
443 assert!(res2.is_err());
444 buf.clear();
445 serializer.serialize(&cycle_info1, &mut buf).unwrap();
446 let res3 = deserializer3.deserialize::<DeserializeError>(&buf);
447 assert!(res3.is_err());
448 }
449}