casper_types/system/
auction.rs

1//! Contains implementation of the Auction contract functionality.
2mod bid;
3mod bid_addr;
4mod bid_kind;
5mod bridge;
6mod constants;
7mod delegator;
8mod delegator_bid;
9mod delegator_kind;
10mod entry_points;
11mod era_info;
12mod error;
13mod reservation;
14mod seigniorage_recipient;
15mod unbond;
16mod unbonding_purse;
17mod validator_bid;
18mod validator_credit;
19mod withdraw_purse;
20
21#[cfg(any(all(feature = "std", feature = "testing"), test))]
22use alloc::collections::btree_map::Entry;
23#[cfg(any(all(feature = "std", feature = "testing"), test))]
24use itertools::Itertools;
25
26use alloc::{boxed::Box, collections::BTreeMap, vec::Vec};
27
28pub use bid::{Bid, VESTING_SCHEDULE_LENGTH_MILLIS};
29pub use bid_addr::{BidAddr, BidAddrTag};
30pub use bid_kind::{BidKind, BidKindTag};
31pub use bridge::Bridge;
32pub use constants::*;
33pub use delegator::Delegator;
34pub use delegator_bid::DelegatorBid;
35pub use delegator_kind::DelegatorKind;
36pub use entry_points::auction_entry_points;
37pub use era_info::{EraInfo, SeigniorageAllocation};
38pub use error::Error;
39pub use reservation::Reservation;
40pub use seigniorage_recipient::{
41    SeigniorageRecipient, SeigniorageRecipientV1, SeigniorageRecipientV2,
42};
43pub use unbond::{Unbond, UnbondEra, UnbondKind};
44pub use unbonding_purse::UnbondingPurse;
45pub use validator_bid::ValidatorBid;
46pub use validator_credit::ValidatorCredit;
47pub use withdraw_purse::WithdrawPurse;
48
49#[cfg(any(feature = "testing", test))]
50pub(crate) mod gens {
51    pub use super::era_info::gens::*;
52}
53
54use crate::{account::AccountHash, EraId, PublicKey, U512};
55
56/// Representation of delegation rate of tokens. Range from 0..=100.
57pub type DelegationRate = u8;
58
59/// Validators mapped to their bids.
60pub type ValidatorBids = BTreeMap<PublicKey, Box<ValidatorBid>>;
61
62/// Delegator bids mapped to their validator.
63pub type DelegatorBids = BTreeMap<PublicKey, Vec<Box<DelegatorBid>>>;
64
65/// Reservations mapped to their validator.
66pub type Reservations = BTreeMap<PublicKey, Vec<Box<Reservation>>>;
67
68/// Validators mapped to their credits by era.
69pub type ValidatorCredits = BTreeMap<PublicKey, BTreeMap<EraId, Box<ValidatorCredit>>>;
70
71/// Weights of validators. "Weight" in this context means a sum of their stakes.
72pub type ValidatorWeights = BTreeMap<PublicKey, U512>;
73
74#[derive(Debug)]
75pub struct WeightsBreakout {
76    locked: ValidatorWeights,
77    unlocked_meets_min: ValidatorWeights,
78    unlocked_below_min: ValidatorWeights,
79}
80
81impl WeightsBreakout {
82    pub fn new() -> Self {
83        WeightsBreakout {
84            locked: BTreeMap::default(),
85            unlocked_meets_min: BTreeMap::default(),
86            unlocked_below_min: BTreeMap::default(),
87        }
88    }
89
90    pub fn register(
91        &mut self,
92        public_key: PublicKey,
93        weight: U512,
94        locked: bool,
95        meets_minimum: bool,
96    ) {
97        if locked {
98            self.locked.insert(public_key, weight);
99        } else if meets_minimum {
100            self.unlocked_meets_min.insert(public_key, weight);
101        } else {
102            self.unlocked_below_min.insert(public_key, weight);
103        }
104    }
105
106    /// The count of locked weights.
107    pub fn locked_count(&self) -> usize {
108        self.locked.len()
109    }
110
111    /// The count of unlocked weights with at least minimum bid amount.
112    pub fn unlocked_meets_min_count(&self) -> usize {
113        self.unlocked_meets_min.len()
114    }
115
116    /// The count of unlocked weights that do not meet minimum bid amount.
117    pub fn unlocked_below_min_count(&self) -> usize {
118        self.unlocked_below_min.len()
119    }
120
121    /// Takes all locked and remaining slots number of unlocked meets min.
122    pub fn take(self, validator_slots: usize, threshold: usize) -> ValidatorWeights {
123        let locked_count = self.locked.len();
124        if locked_count >= validator_slots {
125            // locked validators are taken even if exceeding validator_slots count
126            // they are literally locked in
127            return self.locked;
128        }
129        let remaining_auction_slots = validator_slots.saturating_sub(locked_count);
130        let mut unlocked_hi = self
131            .unlocked_meets_min
132            .iter()
133            .map(|(public_key, validator_bid)| (public_key.clone(), *validator_bid))
134            .collect::<Vec<(PublicKey, U512)>>();
135        // sort highest to lowest (rhs to lhs)
136        unlocked_hi.sort_by(|(_, lhs), (_, rhs)| rhs.cmp(lhs));
137        let unlocked_hi_count = unlocked_hi.len();
138        let combined_count = unlocked_hi_count.saturating_add(locked_count);
139        let unlocked_low_count = self.unlocked_below_min.len();
140        if unlocked_low_count == 0
141            || unlocked_hi_count >= remaining_auction_slots
142            || combined_count >= threshold
143        {
144            return self
145                .locked
146                .into_iter()
147                .chain(unlocked_hi.into_iter().take(remaining_auction_slots))
148                .collect();
149        }
150
151        // we have fewer locked bids and bids >= min bid than the safety threshold,
152        // so we will attempt to backfill slots up to the safety threshold from otherwise
153        // valid bids that have less than the min bid
154        let backfill_count = threshold.saturating_sub(combined_count);
155        let mut unlocked_low = self
156            .unlocked_below_min
157            .iter()
158            .map(|(public_key, validator_bid)| (public_key.clone(), *validator_bid))
159            .collect::<Vec<(PublicKey, U512)>>();
160        // sort highest to lowest (rhs to lhs)
161        unlocked_low.sort_by(|(_, lhs), (_, rhs)| rhs.cmp(lhs));
162        self.locked
163            .into_iter()
164            .chain(unlocked_hi.into_iter().take(remaining_auction_slots))
165            .chain(unlocked_low.into_iter().take(backfill_count))
166            .collect()
167    }
168}
169
170impl Default for WeightsBreakout {
171    fn default() -> Self {
172        Self::new()
173    }
174}
175
176/// List of era validators
177pub type EraValidators = BTreeMap<EraId, ValidatorWeights>;
178
179/// Collection of seigniorage recipients. Legacy version.
180pub type SeigniorageRecipientsV1 = BTreeMap<PublicKey, SeigniorageRecipientV1>;
181/// Collection of seigniorage recipients.
182pub type SeigniorageRecipientsV2 = BTreeMap<PublicKey, SeigniorageRecipientV2>;
183/// Wrapper enum for all variants of `SeigniorageRecipients`.
184#[allow(missing_docs)]
185pub enum SeigniorageRecipients {
186    V1(SeigniorageRecipientsV1),
187    V2(SeigniorageRecipientsV2),
188}
189
190/// Snapshot of `SeigniorageRecipients` for a given era. Legacy version.
191pub type SeigniorageRecipientsSnapshotV1 = BTreeMap<EraId, SeigniorageRecipientsV1>;
192/// Snapshot of `SeigniorageRecipients` for a given era.
193pub type SeigniorageRecipientsSnapshotV2 = BTreeMap<EraId, SeigniorageRecipientsV2>;
194/// Wrapper enum for all variants of `SeigniorageRecipientsSnapshot`.
195#[derive(Debug)]
196#[allow(missing_docs)]
197pub enum SeigniorageRecipientsSnapshot {
198    V1(SeigniorageRecipientsSnapshotV1),
199    V2(SeigniorageRecipientsSnapshotV2),
200}
201
202impl SeigniorageRecipientsSnapshot {
203    /// Returns rewards for given validator in a specified era
204    pub fn get_seignorage_recipient(
205        &self,
206        era_id: &EraId,
207        validator_public_key: &PublicKey,
208    ) -> Option<SeigniorageRecipient> {
209        match self {
210            Self::V1(snapshot) => snapshot.get(era_id).and_then(|era| {
211                era.get(validator_public_key)
212                    .map(|recipient| SeigniorageRecipient::V1(recipient.clone()))
213            }),
214            Self::V2(snapshot) => snapshot.get(era_id).and_then(|era| {
215                era.get(validator_public_key)
216                    .map(|recipient| SeigniorageRecipient::V2(recipient.clone()))
217            }),
218        }
219    }
220}
221
222/// Validators and delegators mapped to their withdraw purses.
223pub type WithdrawPurses = BTreeMap<AccountHash, Vec<WithdrawPurse>>;
224
225/// Aggregated representation of validator and associated delegator bids.
226pub type Staking = BTreeMap<PublicKey, (ValidatorBid, BTreeMap<DelegatorKind, DelegatorBid>)>;
227
228/// Utils for working with a vector of BidKind.
229#[cfg(any(all(feature = "std", feature = "testing"), test))]
230pub trait BidsExt {
231    /// Returns Bid matching public_key, if present.
232    fn unified_bid(&self, public_key: &PublicKey) -> Option<Bid>;
233
234    /// Returns ValidatorBid matching public_key, if present.
235    fn validator_bid(&self, public_key: &PublicKey) -> Option<ValidatorBid>;
236
237    /// Returns a bridge record matching old and new public key, if present.
238    fn bridge(
239        &self,
240        public_key: &PublicKey,
241        new_public_key: &PublicKey,
242        era_id: &EraId,
243    ) -> Option<Bridge>;
244
245    /// Returns ValidatorCredit matching public_key, if present.
246    fn credit(&self, public_key: &PublicKey) -> Option<ValidatorCredit>;
247
248    /// Returns total validator stake, if present.
249    fn validator_total_stake(&self, public_key: &PublicKey) -> Option<U512>;
250
251    /// Returns Delegator entries matching validator public key, if present.
252    fn delegators_by_validator_public_key(
253        &self,
254        public_key: &PublicKey,
255    ) -> Option<Vec<DelegatorBid>>;
256
257    /// Returns Delegator entry, if present.
258    fn delegator_by_kind(
259        &self,
260        validator_public_key: &PublicKey,
261        delegator_kind: &DelegatorKind,
262    ) -> Option<DelegatorBid>;
263
264    /// Returns Reservation entries matching validator public key, if present.
265    fn reservations_by_validator_public_key(
266        &self,
267        public_key: &PublicKey,
268    ) -> Option<Vec<Reservation>>;
269
270    /// Returns Reservation entry, if present.
271    fn reservation_by_kind(
272        &self,
273        validator_public_key: &PublicKey,
274        delegator_kind: &DelegatorKind,
275    ) -> Option<Reservation>;
276
277    /// Returns Unbond entry, if present.
278    fn unbond_by_kind(
279        &self,
280        validator_public_key: &PublicKey,
281        unbond_kind: &UnbondKind,
282    ) -> Option<Unbond>;
283
284    /// Returns true if containing any elements matching the provided validator public key.
285    fn contains_validator_public_key(&self, public_key: &PublicKey) -> bool;
286
287    /// Removes any items with a public key matching the provided validator public key.
288    fn remove_by_validator_public_key(&mut self, public_key: &PublicKey);
289
290    /// Creates a map of Validator public keys to associated Delegators.
291    fn delegator_map(&self) -> BTreeMap<PublicKey, Vec<DelegatorKind>>;
292
293    /// Inserts if bid_kind does not exist, otherwise replaces.
294    fn upsert(&mut self, bid_kind: BidKind);
295}
296
297#[cfg(any(all(feature = "std", feature = "testing"), test))]
298impl BidsExt for Vec<BidKind> {
299    fn unified_bid(&self, public_key: &PublicKey) -> Option<Bid> {
300        if let BidKind::Unified(bid) = self
301            .iter()
302            .find(|x| x.is_validator() && &x.validator_public_key() == public_key)?
303        {
304            Some(*bid.clone())
305        } else {
306            None
307        }
308    }
309
310    fn validator_bid(&self, public_key: &PublicKey) -> Option<ValidatorBid> {
311        if let BidKind::Validator(validator_bid) = self
312            .iter()
313            .find(|x| x.is_validator() && &x.validator_public_key() == public_key)?
314        {
315            Some(*validator_bid.clone())
316        } else {
317            None
318        }
319    }
320
321    fn bridge(
322        &self,
323        public_key: &PublicKey,
324        new_public_key: &PublicKey,
325        era_id: &EraId,
326    ) -> Option<Bridge> {
327        self.iter().find_map(|x| match x {
328            BidKind::Bridge(bridge)
329                if bridge.old_validator_public_key() == public_key
330                    && bridge.new_validator_public_key() == new_public_key
331                    && bridge.era_id() == era_id =>
332            {
333                Some(*bridge.clone())
334            }
335            _ => None,
336        })
337    }
338
339    fn credit(&self, public_key: &PublicKey) -> Option<ValidatorCredit> {
340        if let BidKind::Credit(credit) = self
341            .iter()
342            .find(|x| x.is_credit() && &x.validator_public_key() == public_key)?
343        {
344            Some(*credit.clone())
345        } else {
346            None
347        }
348    }
349
350    fn validator_total_stake(&self, public_key: &PublicKey) -> Option<U512> {
351        if let Some(validator_bid) = self.validator_bid(public_key) {
352            let delegator_stake = {
353                match self.delegators_by_validator_public_key(validator_bid.validator_public_key())
354                {
355                    None => U512::zero(),
356                    Some(delegators) => delegators.iter().map(|x| x.staked_amount()).sum(),
357                }
358            };
359            return Some(validator_bid.staked_amount() + delegator_stake);
360        }
361
362        if let BidKind::Unified(bid) = self
363            .iter()
364            .find(|x| x.is_validator() && &x.validator_public_key() == public_key)?
365        {
366            return Some(*bid.staked_amount());
367        }
368
369        None
370    }
371
372    fn delegators_by_validator_public_key(
373        &self,
374        public_key: &PublicKey,
375    ) -> Option<Vec<DelegatorBid>> {
376        let mut ret = vec![];
377        for delegator in self
378            .iter()
379            .filter(|x| x.is_delegator() && &x.validator_public_key() == public_key)
380        {
381            if let BidKind::Delegator(delegator) = delegator {
382                ret.push(*delegator.clone());
383            }
384        }
385
386        if ret.is_empty() {
387            None
388        } else {
389            Some(ret)
390        }
391    }
392
393    fn delegator_by_kind(
394        &self,
395        validator_public_key: &PublicKey,
396        delegator_kind: &DelegatorKind,
397    ) -> Option<DelegatorBid> {
398        if let BidKind::Delegator(delegator) = self.iter().find(|x| {
399            x.is_delegator()
400                && &x.validator_public_key() == validator_public_key
401                && x.delegator_kind() == Some(delegator_kind.clone())
402        })? {
403            Some(*delegator.clone())
404        } else {
405            None
406        }
407    }
408
409    fn reservations_by_validator_public_key(
410        &self,
411        validator_public_key: &PublicKey,
412    ) -> Option<Vec<Reservation>> {
413        let mut ret = vec![];
414        for reservation in self
415            .iter()
416            .filter(|x| x.is_reservation() && &x.validator_public_key() == validator_public_key)
417        {
418            if let BidKind::Reservation(reservation) = reservation {
419                ret.push(*reservation.clone());
420            }
421        }
422
423        if ret.is_empty() {
424            None
425        } else {
426            Some(ret)
427        }
428    }
429
430    fn reservation_by_kind(
431        &self,
432        validator_public_key: &PublicKey,
433        delegator_kind: &DelegatorKind,
434    ) -> Option<Reservation> {
435        if let BidKind::Reservation(reservation) = self.iter().find(|x| {
436            x.is_reservation()
437                && &x.validator_public_key() == validator_public_key
438                && x.delegator_kind() == Some(delegator_kind.clone())
439        })? {
440            Some(*reservation.clone())
441        } else {
442            None
443        }
444    }
445
446    fn unbond_by_kind(
447        &self,
448        validator_public_key: &PublicKey,
449        unbond_kind: &UnbondKind,
450    ) -> Option<Unbond> {
451        if let BidKind::Unbond(unbond) = self.iter().find(|x| {
452            x.is_unbond()
453                && &x.validator_public_key() == validator_public_key
454                && x.unbond_kind() == Some(unbond_kind.clone())
455        })? {
456            Some(*unbond.clone())
457        } else {
458            None
459        }
460    }
461
462    fn contains_validator_public_key(&self, public_key: &PublicKey) -> bool {
463        self.iter().any(|x| &x.validator_public_key() == public_key)
464    }
465
466    fn remove_by_validator_public_key(&mut self, public_key: &PublicKey) {
467        self.retain(|x| &x.validator_public_key() != public_key)
468    }
469
470    fn delegator_map(&self) -> BTreeMap<PublicKey, Vec<DelegatorKind>> {
471        let mut ret = BTreeMap::new();
472        let validators = self
473            .iter()
474            .filter(|x| x.is_validator())
475            .cloned()
476            .collect_vec();
477        for bid_kind in validators {
478            ret.insert(bid_kind.validator_public_key().clone(), vec![]);
479        }
480        let delegators = self
481            .iter()
482            .filter(|x| x.is_delegator())
483            .cloned()
484            .collect_vec();
485        for bid_kind in delegators {
486            if let BidKind::Delegator(delegator) = bid_kind {
487                match ret.entry(delegator.validator_public_key().clone()) {
488                    Entry::Vacant(ve) => {
489                        ve.insert(vec![delegator.delegator_kind().clone()]);
490                    }
491                    Entry::Occupied(mut oe) => {
492                        let delegators = oe.get_mut();
493                        delegators.push(delegator.delegator_kind().clone())
494                    }
495                }
496            }
497        }
498        let unified = self
499            .iter()
500            .filter(|x| x.is_unified())
501            .cloned()
502            .collect_vec();
503        for bid_kind in unified {
504            if let BidKind::Unified(unified) = bid_kind {
505                let delegators = unified
506                    .delegators()
507                    .iter()
508                    .map(|(_, y)| DelegatorKind::PublicKey(y.delegator_public_key().clone()))
509                    .collect();
510                ret.insert(unified.validator_public_key().clone(), delegators);
511            }
512        }
513        ret
514    }
515
516    fn upsert(&mut self, bid_kind: BidKind) {
517        let maybe_index = match bid_kind {
518            BidKind::Unified(_) | BidKind::Validator(_) => self
519                .iter()
520                .find_position(|x| {
521                    x.validator_public_key() == bid_kind.validator_public_key()
522                        && x.tag() == bid_kind.tag()
523                })
524                .map(|(idx, _)| idx),
525            BidKind::Delegator(_) => self
526                .iter()
527                .find_position(|x| {
528                    x.is_delegator()
529                        && x.validator_public_key() == bid_kind.validator_public_key()
530                        && x.delegator_kind() == bid_kind.delegator_kind()
531                })
532                .map(|(idx, _)| idx),
533            BidKind::Bridge(_) => self
534                .iter()
535                .find_position(|x| {
536                    x.is_bridge()
537                        && x.validator_public_key() == bid_kind.validator_public_key()
538                        && x.new_validator_public_key() == bid_kind.new_validator_public_key()
539                        && x.era_id() == bid_kind.era_id()
540                })
541                .map(|(idx, _)| idx),
542            BidKind::Credit(_) => self
543                .iter()
544                .find_position(|x| {
545                    x.validator_public_key() == bid_kind.validator_public_key()
546                        && x.tag() == bid_kind.tag()
547                        && x.era_id() == bid_kind.era_id()
548                })
549                .map(|(idx, _)| idx),
550            BidKind::Reservation(_) => self
551                .iter()
552                .find_position(|x| {
553                    x.is_reservation()
554                        && x.validator_public_key() == bid_kind.validator_public_key()
555                        && x.delegator_kind() == bid_kind.delegator_kind()
556                })
557                .map(|(idx, _)| idx),
558            BidKind::Unbond(_) => self
559                .iter()
560                .find_position(|x| {
561                    x.is_unbond()
562                        && x.validator_public_key() == bid_kind.validator_public_key()
563                        && x.unbond_kind() == bid_kind.unbond_kind()
564                })
565                .map(|(idx, _)| idx),
566        };
567
568        match maybe_index {
569            Some(index) => {
570                self.insert(index, bid_kind);
571            }
572            None => {
573                self.push(bid_kind);
574            }
575        }
576    }
577}
578
579#[cfg(test)]
580mod prop_test_delegator {
581    use proptest::prelude::*;
582
583    use crate::{bytesrepr, gens};
584
585    proptest! {
586        #[test]
587        fn test_value_bid(bid in gens::delegator_arb()) {
588            bytesrepr::test_serialization_roundtrip(&bid);
589        }
590    }
591}
592
593#[cfg(test)]
594mod prop_test_reservation {
595    use proptest::prelude::*;
596
597    use crate::{bytesrepr, gens};
598
599    proptest! {
600        #[test]
601        fn test_value_bid(bid in gens::reservation_arb()) {
602            bytesrepr::test_serialization_roundtrip(&bid);
603        }
604    }
605}