solana_runtime/
stake_history.rs

1//! This module implements clone-on-write semantics for the SDK's `StakeHistory` to reduce
2//! unnecessary cloning of the underlying vector.
3use std::{
4    ops::{Deref, DerefMut},
5    sync::Arc,
6};
7
8/// The SDK's stake history with clone-on-write semantics
9#[derive(Default, Clone, PartialEq, Eq, Debug, Deserialize, Serialize, AbiExample)]
10pub struct StakeHistory(Arc<StakeHistoryInner>);
11
12impl Deref for StakeHistory {
13    type Target = StakeHistoryInner;
14    fn deref(&self) -> &Self::Target {
15        &self.0
16    }
17}
18
19impl DerefMut for StakeHistory {
20    fn deref_mut(&mut self) -> &mut Self::Target {
21        Arc::make_mut(&mut self.0)
22    }
23}
24
25/// The inner type, which is the SDK's stake history
26type StakeHistoryInner = solana_sdk::stake_history::StakeHistory;
27
28#[cfg(test)]
29mod tests {
30    use {super::*, solana_sdk::stake_history::StakeHistoryEntry};
31
32    fn rand_stake_history_entry() -> StakeHistoryEntry {
33        StakeHistoryEntry {
34            effective: rand::random(),
35            activating: rand::random(),
36            deactivating: rand::random(),
37        }
38    }
39
40    /// Ensure that StakeHistory is indeed clone-on-write
41    #[test]
42    fn test_stake_history_is_cow() {
43        let mut stake_history = StakeHistory::default();
44        (100..109).for_each(|epoch| {
45            let entry = rand_stake_history_entry();
46            stake_history.add(epoch, entry);
47        });
48
49        // Test: Clone the stake history and **do not modify**.  Assert the underlying instances
50        // are the same.
51        {
52            let stake_history2 = stake_history.clone();
53            assert_eq!(stake_history, stake_history2);
54            assert!(
55                Arc::ptr_eq(&stake_history.0, &stake_history2.0),
56                "Inner Arc must point to the same underlying instance"
57            );
58            assert!(
59                std::ptr::eq(stake_history.deref(), stake_history2.deref()),
60                "Deref must point to the same underlying instance"
61            );
62        }
63
64        // Test: Clone the stake history and then modify.  Assert the underlying instances are
65        // unique.
66        {
67            let mut stake_history2 = stake_history.clone();
68            assert_eq!(stake_history, stake_history2);
69            (200..209).for_each(|epoch| {
70                let entry = rand_stake_history_entry();
71                stake_history2.add(epoch, entry);
72            });
73            assert_ne!(stake_history, stake_history2);
74            assert!(
75                !Arc::ptr_eq(&stake_history.0, &stake_history2.0),
76                "Inner Arc must point to a different underlying instance"
77            );
78            assert!(
79                !std::ptr::eq(stake_history.deref(), stake_history2.deref()),
80                "Deref must point to a different underlying instance"
81            );
82        }
83    }
84
85    /// Ensure that StakeHistory serializes and deserializes between the inner and outer types
86    #[test]
87    fn test_stake_history_serde() {
88        let mut stake_history_outer = StakeHistory::default();
89        let mut stake_history_inner = StakeHistoryInner::default();
90        (2134..).take(11).for_each(|epoch| {
91            let entry = rand_stake_history_entry();
92            stake_history_outer.add(epoch, entry.clone());
93            stake_history_inner.add(epoch, entry);
94        });
95
96        // Test: Assert that serializing the outer and inner types produces the same data
97        assert_eq!(
98            bincode::serialize(&stake_history_outer).unwrap(),
99            bincode::serialize(&stake_history_inner).unwrap(),
100        );
101
102        // Test: Assert that serializing the outer type then deserializing to the inner type
103        // produces the same values
104        {
105            let data = bincode::serialize(&stake_history_outer).unwrap();
106            let deserialized_inner: StakeHistoryInner = bincode::deserialize(&data).unwrap();
107            assert_eq!(&deserialized_inner, stake_history_outer.deref());
108        }
109
110        // Test: Assert that serializing the inner type then deserializing to the outer type
111        // produces the same values
112        {
113            let data = bincode::serialize(&stake_history_inner).unwrap();
114            let deserialized_outer: StakeHistory = bincode::deserialize(&data).unwrap();
115            assert_eq!(deserialized_outer.deref(), &stake_history_inner);
116        }
117    }
118}