1use {
2 super::{StakeAccount, Stakes, StakesEnum},
3 crate::stake_history::StakeHistory,
4 im::HashMap as ImHashMap,
5 serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer},
6 solana_clock::Epoch,
7 solana_pubkey::Pubkey,
8 solana_stake_interface::state::Delegation,
9 solana_stake_program::stake_state::Stake,
10 solana_vote::vote_account::VoteAccounts,
11 std::sync::Arc,
12};
13
14#[cfg_attr(feature = "frozen-abi", derive(AbiExample, AbiEnumVisitor))]
18#[derive(Debug, Clone)]
19pub enum SerdeStakesToStakeFormat {
20 Stake(Stakes<Stake>),
21 Account(Stakes<StakeAccount>),
22}
23
24#[cfg(feature = "dev-context-only-utils")]
25impl PartialEq<Self> for SerdeStakesToStakeFormat {
26 fn eq(&self, other: &Self) -> bool {
27 match (self, other) {
28 (Self::Stake(stakes), Self::Stake(other)) => stakes == other,
29 (Self::Account(stakes), Self::Account(other)) => stakes == other,
30 (Self::Stake(stakes), Self::Account(other)) => {
31 stakes == &Stakes::<Stake>::from(other.clone())
32 }
33 (Self::Account(stakes), Self::Stake(other)) => {
34 other == &Stakes::<Stake>::from(stakes.clone())
35 }
36 }
37 }
38}
39
40impl From<SerdeStakesToStakeFormat> for StakesEnum {
41 fn from(stakes: SerdeStakesToStakeFormat) -> Self {
42 match stakes {
43 SerdeStakesToStakeFormat::Stake(stakes) => Self::Stakes(stakes),
44 SerdeStakesToStakeFormat::Account(stakes) => Self::Accounts(stakes),
45 }
46 }
47}
48
49impl Serialize for SerdeStakesToStakeFormat {
50 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
51 where
52 S: Serializer,
53 {
54 match self {
55 Self::Stake(stakes) => stakes.serialize(serializer),
56 Self::Account(stakes) => serialize_stake_accounts_to_stake_format(stakes, serializer),
57 }
58 }
59}
60
61impl<'de> Deserialize<'de> for SerdeStakesToStakeFormat {
62 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
63 where
64 D: Deserializer<'de>,
65 {
66 let stakes = Stakes::<Stake>::deserialize(deserializer)?;
67 Ok(Self::Stake(stakes))
68 }
69}
70
71pub(crate) mod serde_stakes_to_delegation_format {
74 use {
75 super::*,
76 serde::{Deserialize, Deserializer, Serialize, Serializer},
77 };
78
79 pub(crate) fn serialize<S>(stakes: &StakesEnum, serializer: S) -> Result<S::Ok, S::Error>
80 where
81 S: Serializer,
82 {
83 match stakes {
84 StakesEnum::Delegations(stakes) => stakes.serialize(serializer),
85 StakesEnum::Stakes(stakes) => serialize_stakes_to_delegation_format(stakes, serializer),
86 StakesEnum::Accounts(stakes) => {
87 serialize_stake_accounts_to_delegation_format(stakes, serializer)
88 }
89 }
90 }
91
92 pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Arc<StakesEnum>, D::Error>
93 where
94 D: Deserializer<'de>,
95 {
96 let stakes = Stakes::<Delegation>::deserialize(deserializer)?;
97 Ok(Arc::new(StakesEnum::Delegations(stakes)))
98 }
99}
100
101fn serialize_stakes_to_delegation_format<S: Serializer>(
102 stakes: &Stakes<Stake>,
103 serializer: S,
104) -> Result<S::Ok, S::Error> {
105 SerdeStakesToDelegationFormat::from(stakes.clone()).serialize(serializer)
106}
107
108fn serialize_stake_accounts_to_delegation_format<S: Serializer>(
109 stakes: &Stakes<StakeAccount>,
110 serializer: S,
111) -> Result<S::Ok, S::Error> {
112 SerdeStakeAccountsToDelegationFormat::from(stakes.clone()).serialize(serializer)
113}
114
115fn serialize_stake_accounts_to_stake_format<S: Serializer>(
116 stakes: &Stakes<StakeAccount>,
117 serializer: S,
118) -> Result<S::Ok, S::Error> {
119 SerdeStakeAccountsToStakeFormat::from(stakes.clone()).serialize(serializer)
120}
121
122impl From<Stakes<Stake>> for SerdeStakesToDelegationFormat {
123 fn from(stakes: Stakes<Stake>) -> Self {
124 let Stakes {
125 vote_accounts,
126 stake_delegations,
127 unused,
128 epoch,
129 stake_history,
130 } = stakes;
131
132 Self {
133 vote_accounts,
134 stake_delegations: SerdeStakeMapToDelegationFormat(stake_delegations),
135 unused,
136 epoch,
137 stake_history,
138 }
139 }
140}
141
142impl From<Stakes<StakeAccount>> for SerdeStakeAccountsToDelegationFormat {
143 fn from(stakes: Stakes<StakeAccount>) -> Self {
144 let Stakes {
145 vote_accounts,
146 stake_delegations,
147 unused,
148 epoch,
149 stake_history,
150 } = stakes;
151
152 Self {
153 vote_accounts,
154 stake_delegations: SerdeStakeAccountMapToDelegationFormat(stake_delegations),
155 unused,
156 epoch,
157 stake_history,
158 }
159 }
160}
161
162impl From<Stakes<StakeAccount>> for SerdeStakeAccountsToStakeFormat {
163 fn from(stakes: Stakes<StakeAccount>) -> Self {
164 let Stakes {
165 vote_accounts,
166 stake_delegations,
167 unused,
168 epoch,
169 stake_history,
170 } = stakes;
171
172 Self {
173 vote_accounts,
174 stake_delegations: SerdeStakeAccountMapToStakeFormat(stake_delegations),
175 unused,
176 epoch,
177 stake_history,
178 }
179 }
180}
181
182#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
183#[derive(Serialize)]
184struct SerdeStakesToDelegationFormat {
185 vote_accounts: VoteAccounts,
186 stake_delegations: SerdeStakeMapToDelegationFormat,
187 unused: u64,
188 epoch: Epoch,
189 stake_history: StakeHistory,
190}
191
192#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
193#[derive(Serialize)]
194struct SerdeStakeAccountsToDelegationFormat {
195 vote_accounts: VoteAccounts,
196 stake_delegations: SerdeStakeAccountMapToDelegationFormat,
197 unused: u64,
198 epoch: Epoch,
199 stake_history: StakeHistory,
200}
201
202#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
203#[derive(Serialize)]
204struct SerdeStakeAccountsToStakeFormat {
205 vote_accounts: VoteAccounts,
206 stake_delegations: SerdeStakeAccountMapToStakeFormat,
207 unused: u64,
208 epoch: Epoch,
209 stake_history: StakeHistory,
210}
211
212#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
213struct SerdeStakeMapToDelegationFormat(ImHashMap<Pubkey, Stake>);
214impl Serialize for SerdeStakeMapToDelegationFormat {
215 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
216 where
217 S: Serializer,
218 {
219 let mut s = serializer.serialize_map(Some(self.0.len()))?;
220 for (pubkey, stake) in self.0.iter() {
221 s.serialize_entry(pubkey, &stake.delegation)?;
222 }
223 s.end()
224 }
225}
226
227#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
228struct SerdeStakeAccountMapToDelegationFormat(ImHashMap<Pubkey, StakeAccount>);
229impl Serialize for SerdeStakeAccountMapToDelegationFormat {
230 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
231 where
232 S: Serializer,
233 {
234 let mut s = serializer.serialize_map(Some(self.0.len()))?;
235 for (pubkey, stake_account) in self.0.iter() {
236 s.serialize_entry(pubkey, stake_account.delegation())?;
237 }
238 s.end()
239 }
240}
241
242#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
243struct SerdeStakeAccountMapToStakeFormat(ImHashMap<Pubkey, StakeAccount>);
244impl Serialize for SerdeStakeAccountMapToStakeFormat {
245 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
246 where
247 S: Serializer,
248 {
249 let mut s = serializer.serialize_map(Some(self.0.len()))?;
250 for (pubkey, stake_account) in self.0.iter() {
251 s.serialize_entry(pubkey, stake_account.stake())?;
252 }
253 s.end()
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use {
260 super::*, crate::stakes::StakesCache, rand::Rng, solana_rent::Rent,
261 solana_stake_program::stake_state, solana_vote_program::vote_state,
262 };
263
264 #[test]
265 fn test_serde_stakes_to_stake_format() {
266 let mut stake_delegations = ImHashMap::new();
267 stake_delegations.insert(
268 Pubkey::new_unique(),
269 StakeAccount::try_from(stake_state::create_account(
270 &Pubkey::new_unique(),
271 &Pubkey::new_unique(),
272 &vote_state::create_account(
273 &Pubkey::new_unique(),
274 &Pubkey::new_unique(),
275 0,
276 1_000_000_000,
277 ),
278 &Rent::default(),
279 1_000_000_000,
280 ))
281 .unwrap(),
282 );
283
284 let stake_account_stakes = Stakes {
285 vote_accounts: VoteAccounts::default(),
286 stake_delegations,
287 unused: 0,
288 epoch: 0,
289 stake_history: StakeHistory::default(),
290 };
291
292 let wrapped_stakes = SerdeStakesToStakeFormat::Account(stake_account_stakes.clone());
293 let serialized_stakes = bincode::serialize(&wrapped_stakes).unwrap();
294 let stake_stakes = bincode::deserialize::<Stakes<Stake>>(&serialized_stakes).unwrap();
295 assert_eq!(
296 StakesEnum::Stakes(stake_stakes),
297 StakesEnum::Accounts(stake_account_stakes)
298 );
299 }
300
301 #[test]
302 fn test_serde_stakes_to_delegation_format() {
303 #[derive(Debug, PartialEq, Deserialize, Serialize)]
304 struct Dummy {
305 head: String,
306 #[serde(with = "serde_stakes_to_delegation_format")]
307 stakes: Arc<StakesEnum>,
308 tail: String,
309 }
310 let mut rng = rand::thread_rng();
311 let stakes_cache = StakesCache::new(Stakes {
312 unused: rng.gen(),
313 epoch: rng.gen(),
314 ..Stakes::default()
315 });
316 for _ in 0..rng.gen_range(5usize..10) {
317 let vote_pubkey = solana_pubkey::new_rand();
318 let vote_account = vote_state::create_account(
319 &vote_pubkey,
320 &solana_pubkey::new_rand(), rng.gen_range(0..101), rng.gen_range(0..1_000_000), );
324 stakes_cache.check_and_store(&vote_pubkey, &vote_account, None);
325 for _ in 0..rng.gen_range(10usize..20) {
326 let stake_pubkey = solana_pubkey::new_rand();
327 let rent = Rent::with_slots_per_epoch(rng.gen());
328 let stake_account = stake_state::create_account(
329 &stake_pubkey, &vote_pubkey,
331 &vote_account,
332 &rent,
333 rng.gen_range(0..1_000_000), );
335 stakes_cache.check_and_store(&stake_pubkey, &stake_account, None);
336 }
337 }
338 let stakes: Stakes<StakeAccount> = stakes_cache.stakes().clone();
339 assert!(stakes.vote_accounts.as_ref().len() >= 5);
340 assert!(stakes.stake_delegations.len() >= 50);
341 let dummy = Dummy {
342 head: String::from("dummy-head"),
343 stakes: Arc::new(StakesEnum::from(stakes.clone())),
344 tail: String::from("dummy-tail"),
345 };
346 assert!(dummy.stakes.vote_accounts().as_ref().len() >= 5);
347 let data = bincode::serialize(&dummy).unwrap();
348 let other: Dummy = bincode::deserialize(&data).unwrap();
349 assert_eq!(other, dummy);
350 let stakes = Stakes::<Delegation>::from(stakes);
351 assert!(stakes.vote_accounts.as_ref().len() >= 5);
352 assert!(stakes.stake_delegations.len() >= 50);
353 let other = match &*other.stakes {
354 StakesEnum::Accounts(_) | StakesEnum::Stakes(_) => panic!("wrong type!"),
355 StakesEnum::Delegations(delegations) => delegations,
356 };
357 assert_eq!(other, &stakes)
358 }
359}