massa_models/async_msg_id.rs
1#![allow(missing_docs)]
2
3use massa_serialization::{Deserializer, Serializer, U64VarIntDeserializer, U64VarIntSerializer};
4use nom::{
5 error::{context, ContextError, ParseError},
6 sequence::tuple,
7 IResult, Parser,
8};
9use num::rational::Ratio;
10use std::ops::Bound::{Excluded, Included};
11
12use crate::slot::{Slot, SlotDeserializer, SlotSerializer};
13
14const ASYNC_MESSAGE_ID_PREFIX: &str = "ASC";
15
16/// Unique identifier of a message.
17/// Also has the property of ordering by priority (highest first) following the triplet:
18/// `(rev(Ratio(msg.fee, max(msg.max_gas,1))), emission_slot, emission_index)`
19///
20/// From `MipComponent::Execution` version 2 (MIP-0002), batch selection and pool eviction
21/// re-rank with `fee / max(max_gas + async_msg_cst_gas_cost, 1)` via
22/// [`crate::async_msg::AsyncMessage::compute_priority_id`]; stored ids keep the historical
23/// formula so identity of already-emitted messages is unchanged.
24pub type AsyncMessageId = (std::cmp::Reverse<Ratio<u64>>, Slot, u64);
25
26#[derive(Clone)]
27pub struct AsyncMessageIdWrapper(pub AsyncMessageId);
28
29impl std::fmt::Display for AsyncMessageIdWrapper {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 let mut bytes = Vec::new();
32 let serializer = AsyncMessageIdSerializer::new();
33 serializer
34 .serialize(&self.0, &mut bytes)
35 .map_err(|_| std::fmt::Error)?;
36 write!(
37 f,
38 "{}{}",
39 ASYNC_MESSAGE_ID_PREFIX,
40 bs58::encode(&bytes).with_check().into_string()
41 )
42 }
43}
44
45#[derive(Clone)]
46pub struct AsyncMessageIdSerializer {
47 slot_serializer: SlotSerializer,
48 u64_serializer: U64VarIntSerializer,
49}
50
51impl AsyncMessageIdSerializer {
52 pub fn new() -> Self {
53 Self {
54 slot_serializer: SlotSerializer::new(),
55 u64_serializer: U64VarIntSerializer::new(),
56 }
57 }
58}
59
60impl Default for AsyncMessageIdSerializer {
61 fn default() -> Self {
62 Self::new()
63 }
64}
65
66impl Serializer<AsyncMessageId> for AsyncMessageIdSerializer {
67 /// ## Example
68 /// ```
69 /// use std::ops::Bound::Included;
70 /// use massa_serialization::Serializer;
71 /// use massa_models::{address::Address, amount::Amount, slot::Slot, async_msg_id::{AsyncMessageId, AsyncMessageIdSerializer}, async_msg::AsyncMessage};
72 /// use std::str::FromStr;
73 ///
74 /// let message = AsyncMessage::new(
75 /// Slot::new(1, 0),
76 /// 0,
77 /// Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(),
78 /// Address::from_str("AU12htxRWiEm8jDJpJptr6cwEhWNcCSFWstN1MLSa96DDkVM9Y42G").unwrap(),
79 /// String::from("test"),
80 /// 10000000,
81 /// Amount::from_str("1").unwrap(),
82 /// Amount::from_str("1").unwrap(),
83 /// Slot::new(2, 0),
84 /// Slot::new(3, 0),
85 /// vec![1, 2, 3, 4],
86 /// None,
87 /// None
88 /// );
89 /// let id: AsyncMessageId = message.compute_id();
90 /// let mut serialized = Vec::new();
91 /// let serializer = AsyncMessageIdSerializer::new();
92 /// serializer.serialize(&id, &mut serialized).unwrap();
93 /// ```
94 fn serialize(
95 &self,
96 value: &AsyncMessageId,
97 buffer: &mut Vec<u8>,
98 ) -> Result<(), massa_serialization::SerializeError> {
99 self.u64_serializer.serialize(value.0 .0.numer(), buffer)?;
100 self.u64_serializer.serialize(value.0 .0.denom(), buffer)?;
101 self.slot_serializer.serialize(&value.1, buffer)?;
102 self.u64_serializer.serialize(&value.2, buffer)?;
103 Ok(())
104 }
105}
106
107#[derive(Clone)]
108pub struct AsyncMessageIdDeserializer {
109 slot_deserializer: SlotDeserializer,
110 numerator_deserializer: U64VarIntDeserializer,
111 denominator_deserializer: U64VarIntDeserializer,
112 emission_index_deserializer: U64VarIntDeserializer,
113}
114
115impl AsyncMessageIdDeserializer {
116 pub fn new(thread_count: u8) -> Self {
117 Self {
118 slot_deserializer: SlotDeserializer::new(
119 (Included(u64::MIN), Included(u64::MAX)),
120 (Included(0), Excluded(thread_count)),
121 ),
122 numerator_deserializer: U64VarIntDeserializer::new(
123 Included(u64::MIN),
124 Included(u64::MAX),
125 ),
126 denominator_deserializer: U64VarIntDeserializer::new(Included(1), Included(u64::MAX)),
127 emission_index_deserializer: U64VarIntDeserializer::new(
128 Included(u64::MIN),
129 Included(u64::MAX),
130 ),
131 }
132 }
133}
134
135impl Deserializer<AsyncMessageId> for AsyncMessageIdDeserializer {
136 /// ## Example
137 /// ```
138 /// use std::ops::Bound::Included;
139 /// use massa_serialization::{Serializer, Deserializer, DeserializeError};
140 /// use massa_models::{address::Address, amount::Amount, slot::Slot, async_msg_id::{AsyncMessageId, AsyncMessageIdDeserializer, AsyncMessageIdSerializer}};
141 /// use massa_models::async_msg::AsyncMessage;
142 /// use std::str::FromStr;
143 ///
144 /// let message = AsyncMessage::new(
145 /// Slot::new(1, 0),
146 /// 0,
147 /// Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(),
148 /// Address::from_str("AU12htxRWiEm8jDJpJptr6cwEhWNcCSFWstN1MLSa96DDkVM9Y42G").unwrap(),
149 /// String::from("test"),
150 /// 10000000,
151 /// Amount::from_str("1").unwrap(),
152 /// Amount::from_str("1").unwrap(),
153 /// Slot::new(2, 0),
154 /// Slot::new(3, 0),
155 /// vec![1, 2, 3, 4],
156 /// None,
157 /// None
158 /// );
159 /// let id: AsyncMessageId = message.compute_id();
160 /// let mut serialized = Vec::new();
161 /// let serializer = AsyncMessageIdSerializer::new();
162 /// let deserializer = AsyncMessageIdDeserializer::new(10);
163 /// serializer.serialize(&id, &mut serialized).unwrap();
164 /// let (rest, id_deser) = deserializer.deserialize::<DeserializeError>(&serialized).unwrap();
165 /// assert!(rest.is_empty());
166 /// assert_eq!(id, id_deser);
167 /// ```
168 fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
169 &self,
170 buffer: &'a [u8],
171 ) -> IResult<&'a [u8], AsyncMessageId, E> {
172 context(
173 "Failed AsyncMessageId deserialization",
174 tuple((
175 context("Failed num deserialization", |input| {
176 self.numerator_deserializer.deserialize(input)
177 }),
178 context("Failed denum deserialization", |input| {
179 self.denominator_deserializer.deserialize(input)
180 }),
181 context("Failed emission_slot deserialization", |input| {
182 self.slot_deserializer.deserialize(input)
183 }),
184 context("Failed emission_index deserialization", |input| {
185 self.emission_index_deserializer.deserialize(input)
186 }),
187 )),
188 )
189 .map(|(fee, denom, slot, index)| (std::cmp::Reverse(Ratio::new(fee, denom)), slot, index))
190 .parse(buffer)
191 }
192}