cbe_program/
stake_history.rs1pub use crate::clock::Epoch;
10use std::ops::Deref;
11
12pub const MAX_ENTRIES: usize = 512; #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default, Clone, AbiExample)]
15pub struct StakeHistoryEntry {
16 pub effective: u64, pub activating: u64, pub deactivating: u64, }
20
21impl StakeHistoryEntry {
22 pub fn with_effective(effective: u64) -> Self {
23 Self {
24 effective,
25 ..Self::default()
26 }
27 }
28
29 pub fn with_effective_and_activating(effective: u64, activating: u64) -> Self {
30 Self {
31 effective,
32 activating,
33 ..Self::default()
34 }
35 }
36
37 pub fn with_deactivating(deactivating: u64) -> Self {
38 Self {
39 effective: deactivating,
40 deactivating,
41 ..Self::default()
42 }
43 }
44}
45
46impl std::ops::Add for StakeHistoryEntry {
47 type Output = StakeHistoryEntry;
48 fn add(self, rhs: StakeHistoryEntry) -> Self::Output {
49 Self {
50 effective: self.effective.saturating_add(rhs.effective),
51 activating: self.activating.saturating_add(rhs.activating),
52 deactivating: self.deactivating.saturating_add(rhs.deactivating),
53 }
54 }
55}
56
57#[repr(C)]
58#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default, Clone, AbiExample)]
59pub struct StakeHistory(Vec<(Epoch, StakeHistoryEntry)>);
60
61impl StakeHistory {
62 pub fn get(&self, epoch: Epoch) -> Option<&StakeHistoryEntry> {
63 self.binary_search_by(|probe| epoch.cmp(&probe.0))
64 .ok()
65 .map(|index| &self[index].1)
66 }
67
68 pub fn add(&mut self, epoch: Epoch, entry: StakeHistoryEntry) {
69 match self.binary_search_by(|probe| epoch.cmp(&probe.0)) {
70 Ok(index) => (self.0)[index] = (epoch, entry),
71 Err(index) => (self.0).insert(index, (epoch, entry)),
72 }
73 (self.0).truncate(MAX_ENTRIES);
74 }
75}
76
77impl Deref for StakeHistory {
78 type Target = Vec<(Epoch, StakeHistoryEntry)>;
79 fn deref(&self) -> &Self::Target {
80 &self.0
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn test_stake_history() {
90 let mut stake_history = StakeHistory::default();
91
92 for i in 0..MAX_ENTRIES as u64 + 1 {
93 stake_history.add(
94 i,
95 StakeHistoryEntry {
96 activating: i,
97 ..StakeHistoryEntry::default()
98 },
99 );
100 }
101 assert_eq!(stake_history.len(), MAX_ENTRIES);
102 assert_eq!(stake_history.iter().map(|entry| entry.0).min().unwrap(), 1);
103 assert_eq!(stake_history.get(0), None);
104 assert_eq!(
105 stake_history.get(1),
106 Some(&StakeHistoryEntry {
107 activating: 1,
108 ..StakeHistoryEntry::default()
109 })
110 );
111 }
112}