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