massa_pos_exports/
deferred_credits.rs

1use massa_models::{
2    address::{Address, AddressDeserializer, AddressSerializer},
3    amount::{Amount, AmountDeserializer, AmountSerializer},
4    prehash::PreHashMap,
5    slot::Slot,
6};
7use massa_serialization::{
8    Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer,
9};
10use nom::{
11    error::{context, ContextError, ParseError},
12    multi::length_count,
13    sequence::tuple,
14    IResult, Parser,
15};
16use serde::{Deserialize, Serialize};
17use std::{
18    collections::BTreeMap,
19    fmt::Debug,
20    ops::{Bound::Included, RangeBounds},
21};
22
23#[derive(Clone, Serialize, Deserialize)]
24/// Structure containing all the PoS deferred credits information
25pub struct DeferredCredits {
26    /// Deferred credits
27    pub credits: BTreeMap<Slot, PreHashMap<Address, Amount>>,
28}
29
30impl Debug for DeferredCredits {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        write!(f, "{:?}", self.credits)
33    }
34}
35
36impl Default for DeferredCredits {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42impl DeferredCredits {
43    /// Check if the credits list is empty
44    pub fn is_empty(&self) -> bool {
45        self.credits.is_empty()
46    }
47
48    /// Create a new DeferredCredits with hash tracking
49    pub fn new() -> Self {
50        Self {
51            credits: Default::default(),
52        }
53    }
54
55    /// Apply a function to each element
56    pub fn for_each<F>(&mut self, mut f: F)
57    where
58        F: FnMut(&Slot, &Address, &mut Amount),
59    {
60        for (slot, credits) in &mut self.credits {
61            for (address, amount) in credits {
62                f(slot, address, amount);
63            }
64        }
65    }
66
67    /// Get all deferred credits within a slot range.
68    pub fn get_slot_range<R>(&self, range: R) -> DeferredCredits
69    where
70        R: RangeBounds<Slot>,
71    {
72        DeferredCredits {
73            credits: self
74                .credits
75                .range(range)
76                .map(|(s, map)| (*s, map.clone()))
77                .collect(),
78        }
79    }
80
81    /// Extends the current `DeferredCredits` with another and replace the amounts for existing addresses
82    pub fn extend(&mut self, other: Self) {
83        for (slot, credits) in other.credits {
84            for (address, amount) in credits {
85                self.insert(slot, address, amount);
86            }
87        }
88    }
89
90    /// Remove credits set to zero, use only on finality
91    pub fn remove_zeros(&mut self) {
92        let mut empty_slots = Vec::new();
93
94        // We need to destructure self to be able to mutate both credits and the hash_tracker during iteration
95        // Without it, the borrow-checker is angry that we try to mutate self twice.
96        let Self {
97            ref mut credits, ..
98        } = self;
99
100        for (slot, credits) in credits {
101            credits.retain(|_, amount| {
102                // do not retain if amount is zero
103                !amount.is_zero()
104            });
105            if credits.is_empty() {
106                empty_slots.push(*slot);
107            }
108        }
109        for slot in empty_slots {
110            self.credits.remove(&slot);
111        }
112    }
113
114    /// Gets the deferred credits for a given address that will be credited at a given slot
115    pub fn get_address_credits_for_slot(&self, addr: &Address, slot: &Slot) -> Option<Amount> {
116        self.credits
117            .get(slot)
118            .and_then(|slot_credits| slot_credits.get(addr))
119            .copied()
120    }
121
122    /// Insert an element
123    pub fn insert(&mut self, slot: Slot, address: Address, amount: Amount) -> Option<Amount> {
124        self.credits
125            .entry(slot)
126            .or_default()
127            .insert(address, amount)
128    }
129}
130
131#[derive(Clone)]
132#[allow(missing_docs)]
133/// Inner serializer for one slot's deferred credits (Address -> Amount map) within `DeferredCredits`
134pub struct DeferredCreditSerializer {
135    pub u64_ser: U64VarIntSerializer,
136    pub address_ser: AddressSerializer,
137    pub amount_ser: AmountSerializer,
138}
139
140impl Default for DeferredCreditSerializer {
141    fn default() -> Self {
142        Self::new()
143    }
144}
145
146impl DeferredCreditSerializer {
147    /// Creates a new inner deferred credit serializer
148    pub fn new() -> Self {
149        Self {
150            u64_ser: U64VarIntSerializer::new(),
151            address_ser: AddressSerializer::new(),
152            amount_ser: AmountSerializer::new(),
153        }
154    }
155}
156
157impl Serializer<PreHashMap<Address, Amount>> for DeferredCreditSerializer {
158    fn serialize(
159        &self,
160        value: &PreHashMap<Address, Amount>,
161        buffer: &mut Vec<u8>,
162    ) -> Result<(), SerializeError> {
163        // slot credits length
164        self.u64_ser.serialize(&(value.len() as u64), buffer)?;
165        // slot credits
166        for (addr, amount) in value {
167            // address
168            self.address_ser.serialize(addr, buffer)?;
169            // credited amount
170            self.amount_ser.serialize(amount, buffer)?;
171        }
172        Ok(())
173    }
174}
175
176#[derive(Clone)]
177#[allow(missing_docs)]
178/// Inner deserializer for one slot's deferred credits (Address -> Amount map) within `DeferredCredits`
179pub struct DeferredCreditDeserializer {
180    u64_deserializer: U64VarIntDeserializer,
181    pub address_deserializer: AddressDeserializer,
182    pub amount_deserializer: AmountDeserializer,
183}
184
185impl DeferredCreditDeserializer {
186    /// Creates a new inner deferred credit deserializer
187    pub fn new(max_credits_length: u64) -> DeferredCreditDeserializer {
188        DeferredCreditDeserializer {
189            u64_deserializer: U64VarIntDeserializer::new(
190                Included(u64::MIN),
191                Included(max_credits_length),
192            ),
193            address_deserializer: AddressDeserializer::new(),
194            amount_deserializer: AmountDeserializer::new(
195                Included(Amount::MIN),
196                Included(Amount::MAX),
197            ),
198        }
199    }
200}
201
202impl Deserializer<PreHashMap<Address, Amount>> for DeferredCreditDeserializer {
203    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
204        &self,
205        buffer: &'a [u8],
206    ) -> IResult<&'a [u8], PreHashMap<Address, Amount>, E> {
207        context(
208            "Failed Credit deserialization",
209            length_count(
210                context("Failed length deserialization", |input| {
211                    self.u64_deserializer.deserialize(input)
212                }),
213                tuple((
214                    context("Failed address deserialization", |input| {
215                        self.address_deserializer.deserialize(input)
216                    }),
217                    context("Failed amount deserialization", |input| {
218                        self.amount_deserializer.deserialize(input)
219                    }),
220                )),
221            ),
222        )
223        .map(|elements| elements.into_iter().collect())
224        .parse(buffer)
225    }
226}