1use {
2 itertools::Itertools,
3 once_cell::sync::OnceCell,
4 serde::ser::{Serialize, Serializer},
5 solana_sdk::{
6 account::{AccountSharedData, ReadableAccount},
7 instruction::InstructionError,
8 pubkey::Pubkey,
9 },
10 solana_vote_program::vote_state::VoteState,
11 std::{
12 cmp::Ordering,
13 collections::{hash_map::Entry, HashMap},
14 iter::FromIterator,
15 sync::Arc,
16 },
17 thiserror::Error,
18};
19
20#[derive(Clone, Debug, PartialEq, AbiExample, Deserialize)]
21#[serde(try_from = "AccountSharedData")]
22pub struct VoteAccount(Arc<VoteAccountInner>);
23
24#[derive(Debug, Error)]
25pub enum Error {
26 #[error(transparent)]
27 InstructionError(#[from] InstructionError),
28 #[error("Invalid vote account owner: {0}")]
29 InvalidOwner(Pubkey),
30}
31
32#[derive(Debug, AbiExample)]
33struct VoteAccountInner {
34 account: AccountSharedData,
35 vote_state: OnceCell<Result<VoteState, Error>>,
36}
37
38pub type VoteAccountsHashMap = HashMap<Pubkey, (u64, VoteAccount)>;
39
40#[derive(Clone, Debug, AbiExample, Deserialize)]
41#[serde(from = "Arc<VoteAccountsHashMap>")]
42pub struct VoteAccounts {
43 vote_accounts: Arc<VoteAccountsHashMap>,
44 staked_nodes: OnceCell<
46 Arc<
47 HashMap<
48 Pubkey, u64, >,
51 >,
52 >,
53}
54
55impl VoteAccount {
56 pub(crate) fn account(&self) -> &AccountSharedData {
57 &self.0.account
58 }
59
60 pub(crate) fn lamports(&self) -> u64 {
61 self.0.account.lamports()
62 }
63
64 pub(crate) fn owner(&self) -> &Pubkey {
65 self.0.account.owner()
66 }
67
68 pub fn vote_state(&self) -> &Result<VoteState, Error> {
69 self.0
72 .vote_state
73 .get_or_init(|| VoteState::deserialize(self.0.account.data()).map_err(Error::from))
74 }
75
76 pub(crate) fn is_deserialized(&self) -> bool {
77 self.0.vote_state.get().is_some()
78 }
79
80 pub fn node_pubkey(&self) -> Option<Pubkey> {
82 Some(self.vote_state().as_ref().ok()?.node_pubkey)
83 }
84}
85
86impl VoteAccounts {
87 pub(crate) fn len(&self) -> usize {
88 self.vote_accounts.len()
89 }
90
91 pub fn staked_nodes(&self) -> Arc<HashMap<Pubkey, u64>> {
92 self.staked_nodes
93 .get_or_init(|| {
94 Arc::new(
95 self.vote_accounts
96 .values()
97 .filter(|(stake, _)| *stake != 0u64)
98 .filter_map(|(stake, vote_account)| {
99 Some((vote_account.node_pubkey()?, stake))
100 })
101 .into_grouping_map()
102 .aggregate(|acc, _node_pubkey, stake| {
103 Some(acc.unwrap_or_default() + stake)
104 }),
105 )
106 })
107 .clone()
108 }
109
110 pub(crate) fn get(&self, pubkey: &Pubkey) -> Option<&VoteAccount> {
111 let (_stake, vote_account) = self.vote_accounts.get(pubkey)?;
112 Some(vote_account)
113 }
114
115 pub fn get_delegated_stake(&self, pubkey: &Pubkey) -> u64 {
116 self.vote_accounts
117 .get(pubkey)
118 .map(|(stake, _vote_account)| *stake)
119 .unwrap_or_default()
120 }
121
122 pub(crate) fn iter(&self) -> impl Iterator<Item = (&Pubkey, &VoteAccount)> {
123 self.vote_accounts
124 .iter()
125 .map(|(vote_pubkey, (_stake, vote_account))| (vote_pubkey, vote_account))
126 }
127
128 pub(crate) fn delegated_stakes(&self) -> impl Iterator<Item = (&Pubkey, u64)> {
129 self.vote_accounts
130 .iter()
131 .map(|(vote_pubkey, (stake, _vote_account))| (vote_pubkey, *stake))
132 }
133
134 pub(crate) fn find_max_by_delegated_stake(&self) -> Option<&VoteAccount> {
135 let key = |(_pubkey, (stake, _vote_account)): &(_, &(u64, _))| *stake;
136 let (_pubkey, (_stake, vote_account)) = self.vote_accounts.iter().max_by_key(key)?;
137 Some(vote_account)
138 }
139
140 pub(crate) fn insert(&mut self, pubkey: Pubkey, (stake, vote_account): (u64, VoteAccount)) {
141 self.add_node_stake(stake, &vote_account);
142 let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
143 if let Some((stake, vote_account)) = vote_accounts.insert(pubkey, (stake, vote_account)) {
144 self.sub_node_stake(stake, &vote_account);
145 }
146 }
147
148 pub(crate) fn remove(&mut self, pubkey: &Pubkey) -> Option<(u64, VoteAccount)> {
149 let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
150 let entry = vote_accounts.remove(pubkey);
151 if let Some((stake, ref vote_account)) = entry {
152 self.sub_node_stake(stake, vote_account);
153 }
154 entry
155 }
156
157 pub(crate) fn add_stake(&mut self, pubkey: &Pubkey, delta: u64) {
158 let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
159 if let Some((stake, vote_account)) = vote_accounts.get_mut(pubkey) {
160 *stake += delta;
161 let vote_account = vote_account.clone();
162 self.add_node_stake(delta, &vote_account);
163 }
164 }
165
166 pub(crate) fn sub_stake(&mut self, pubkey: &Pubkey, delta: u64) {
167 let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
168 if let Some((stake, vote_account)) = vote_accounts.get_mut(pubkey) {
169 *stake = stake
170 .checked_sub(delta)
171 .expect("subtraction value exceeds account's stake");
172 let vote_account = vote_account.clone();
173 self.sub_node_stake(delta, &vote_account);
174 }
175 }
176
177 fn add_node_stake(&mut self, stake: u64, vote_account: &VoteAccount) {
178 if stake == 0u64 {
179 return;
180 }
181 let staked_nodes = match self.staked_nodes.get_mut() {
182 None => return,
183 Some(staked_nodes) => staked_nodes,
184 };
185 if let Some(node_pubkey) = vote_account.node_pubkey() {
186 Arc::make_mut(staked_nodes)
187 .entry(node_pubkey)
188 .and_modify(|s| *s += stake)
189 .or_insert(stake);
190 }
191 }
192
193 fn sub_node_stake(&mut self, stake: u64, vote_account: &VoteAccount) {
194 if stake == 0u64 {
195 return;
196 }
197 let staked_nodes = match self.staked_nodes.get_mut() {
198 None => return,
199 Some(staked_nodes) => staked_nodes,
200 };
201 if let Some(node_pubkey) = vote_account.node_pubkey() {
202 match Arc::make_mut(staked_nodes).entry(node_pubkey) {
203 Entry::Vacant(_) => panic!("this should not happen!"),
204 Entry::Occupied(mut entry) => match entry.get().cmp(&stake) {
205 Ordering::Less => panic!("subtraction value exceeds node's stake"),
206 Ordering::Equal => {
207 entry.remove_entry();
208 }
209 Ordering::Greater => *entry.get_mut() -= stake,
210 },
211 }
212 }
213 }
214}
215
216impl Serialize for VoteAccount {
217 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
218 where
219 S: Serializer,
220 {
221 self.0.account.serialize(serializer)
222 }
223}
224
225impl From<VoteAccount> for AccountSharedData {
226 fn from(account: VoteAccount) -> Self {
227 account.0.account.clone()
228 }
229}
230
231impl TryFrom<AccountSharedData> for VoteAccount {
232 type Error = Error;
233 fn try_from(account: AccountSharedData) -> Result<Self, Self::Error> {
234 let vote_account = VoteAccountInner::try_from(account)?;
235 Ok(Self(Arc::new(vote_account)))
236 }
237}
238
239impl TryFrom<AccountSharedData> for VoteAccountInner {
240 type Error = Error;
241 fn try_from(account: AccountSharedData) -> Result<Self, Self::Error> {
242 if !solana_vote_program::check_id(account.owner()) {
243 return Err(Error::InvalidOwner(*account.owner()));
244 }
245 Ok(Self {
246 account,
247 vote_state: OnceCell::new(),
248 })
249 }
250}
251
252impl PartialEq<VoteAccountInner> for VoteAccountInner {
253 fn eq(&self, other: &Self) -> bool {
254 let Self {
255 account,
256 vote_state: _,
257 } = self;
258 account == &other.account
259 }
260}
261
262impl Default for VoteAccounts {
263 fn default() -> Self {
264 Self {
265 vote_accounts: Arc::default(),
266 staked_nodes: OnceCell::new(),
267 }
268 }
269}
270
271impl PartialEq<VoteAccounts> for VoteAccounts {
272 fn eq(&self, other: &Self) -> bool {
273 let Self {
274 vote_accounts,
275 staked_nodes: _,
276 } = self;
277 vote_accounts == &other.vote_accounts
278 }
279}
280
281impl From<Arc<VoteAccountsHashMap>> for VoteAccounts {
282 fn from(vote_accounts: Arc<VoteAccountsHashMap>) -> Self {
283 Self {
284 vote_accounts,
285 staked_nodes: OnceCell::new(),
286 }
287 }
288}
289
290impl AsRef<VoteAccountsHashMap> for VoteAccounts {
291 fn as_ref(&self) -> &VoteAccountsHashMap {
292 &self.vote_accounts
293 }
294}
295
296impl From<&VoteAccounts> for Arc<VoteAccountsHashMap> {
297 fn from(vote_accounts: &VoteAccounts) -> Self {
298 Arc::clone(&vote_accounts.vote_accounts)
299 }
300}
301
302impl FromIterator<(Pubkey, (u64, VoteAccount))> for VoteAccounts {
303 fn from_iter<I>(iter: I) -> Self
304 where
305 I: IntoIterator<Item = (Pubkey, (u64, VoteAccount))>,
306 {
307 Self::from(Arc::new(HashMap::from_iter(iter)))
308 }
309}
310
311impl Serialize for VoteAccounts {
312 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
313 where
314 S: Serializer,
315 {
316 self.vote_accounts.serialize(serializer)
317 }
318}
319
320#[cfg(test)]
321mod tests {
322 use {
323 super::*,
324 bincode::Options,
325 rand::Rng,
326 solana_sdk::{pubkey::Pubkey, sysvar::clock::Clock},
327 solana_vote_program::vote_state::{VoteInit, VoteStateVersions},
328 std::iter::repeat_with,
329 };
330
331 fn new_rand_vote_account<R: Rng>(
332 rng: &mut R,
333 node_pubkey: Option<Pubkey>,
334 ) -> (AccountSharedData, VoteState) {
335 let vote_init = VoteInit {
336 node_pubkey: node_pubkey.unwrap_or_else(Pubkey::new_unique),
337 authorized_voter: Pubkey::new_unique(),
338 authorized_withdrawer: Pubkey::new_unique(),
339 commission: rng.gen(),
340 };
341 let clock = Clock {
342 slot: rng.gen(),
343 epoch_start_timestamp: rng.gen(),
344 epoch: rng.gen(),
345 leader_schedule_epoch: rng.gen(),
346 unix_timestamp: rng.gen(),
347 };
348 let vote_state = VoteState::new(&vote_init, &clock);
349 let account = AccountSharedData::new_data(
350 rng.gen(), &VoteStateVersions::new_current(vote_state.clone()),
352 &solana_vote_program::id(), )
354 .unwrap();
355 (account, vote_state)
356 }
357
358 fn new_rand_vote_accounts<R: Rng>(
359 rng: &mut R,
360 num_nodes: usize,
361 ) -> impl Iterator<Item = (Pubkey, (u64, VoteAccount))> + '_ {
362 let nodes: Vec<_> = repeat_with(Pubkey::new_unique).take(num_nodes).collect();
363 repeat_with(move || {
364 let node = nodes[rng.gen_range(0, nodes.len())];
365 let (account, _) = new_rand_vote_account(rng, Some(node));
366 let stake = rng.gen_range(0, 997);
367 let vote_account = VoteAccount::try_from(account).unwrap();
368 (Pubkey::new_unique(), (stake, vote_account))
369 })
370 }
371
372 fn staked_nodes<'a, I>(vote_accounts: I) -> HashMap<Pubkey, u64>
373 where
374 I: IntoIterator<Item = &'a (Pubkey, (u64, VoteAccount))>,
375 {
376 let mut staked_nodes = HashMap::new();
377 for (_, (stake, vote_account)) in vote_accounts
378 .into_iter()
379 .filter(|(_, (stake, _))| *stake != 0)
380 {
381 if let Some(node_pubkey) = vote_account.node_pubkey() {
382 staked_nodes
383 .entry(node_pubkey)
384 .and_modify(|s| *s += *stake)
385 .or_insert(*stake);
386 }
387 }
388 staked_nodes
389 }
390
391 #[test]
392 fn test_vote_account() {
393 let mut rng = rand::thread_rng();
394 let (account, vote_state) = new_rand_vote_account(&mut rng, None);
395 let lamports = account.lamports();
396 let vote_account = VoteAccount::try_from(account).unwrap();
397 assert_eq!(lamports, vote_account.lamports());
398 assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
399 assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
401 }
402
403 #[test]
404 fn test_vote_account_serialize() {
405 let mut rng = rand::thread_rng();
406 let (account, vote_state) = new_rand_vote_account(&mut rng, None);
407 let vote_account = VoteAccount::try_from(account.clone()).unwrap();
408 assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
409 assert_eq!(
411 bincode::serialize(&account).unwrap(),
412 bincode::serialize(&vote_account).unwrap()
413 );
414 }
415
416 #[test]
417 fn test_vote_account_deserialize() {
418 let mut rng = rand::thread_rng();
419 let (account, vote_state) = new_rand_vote_account(&mut rng, None);
420 let data = bincode::serialize(&account).unwrap();
421 let vote_account = VoteAccount::try_from(account).unwrap();
422 assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
423 let other_vote_account: VoteAccount = bincode::deserialize(&data).unwrap();
424 assert_eq!(vote_account, other_vote_account);
425 assert_eq!(
426 vote_state,
427 *other_vote_account.vote_state().as_ref().unwrap()
428 );
429 }
430
431 #[test]
432 fn test_vote_account_round_trip() {
433 let mut rng = rand::thread_rng();
434 let (account, vote_state) = new_rand_vote_account(&mut rng, None);
435 let vote_account = VoteAccount::try_from(account).unwrap();
436 assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
437 let data = bincode::serialize(&vote_account).unwrap();
438 let other_vote_account: VoteAccount = bincode::deserialize(&data).unwrap();
439 assert_eq!(vote_account, other_vote_account);
441 assert_eq!(
442 vote_state,
443 *other_vote_account.vote_state().as_ref().unwrap()
444 );
445 }
446
447 #[test]
448 fn test_vote_accounts_serialize() {
449 let mut rng = rand::thread_rng();
450 let vote_accounts_hash_map: VoteAccountsHashMap =
451 new_rand_vote_accounts(&mut rng, 64).take(1024).collect();
452 let vote_accounts = VoteAccounts::from(Arc::new(vote_accounts_hash_map.clone()));
453 assert!(vote_accounts.staked_nodes().len() > 32);
454 assert_eq!(
455 bincode::serialize(&vote_accounts).unwrap(),
456 bincode::serialize(&vote_accounts_hash_map).unwrap(),
457 );
458 assert_eq!(
459 bincode::options().serialize(&vote_accounts).unwrap(),
460 bincode::options()
461 .serialize(&vote_accounts_hash_map)
462 .unwrap(),
463 )
464 }
465
466 #[test]
467 fn test_vote_accounts_deserialize() {
468 let mut rng = rand::thread_rng();
469 let vote_accounts_hash_map: VoteAccountsHashMap =
470 new_rand_vote_accounts(&mut rng, 64).take(1024).collect();
471 let data = bincode::serialize(&vote_accounts_hash_map).unwrap();
472 let vote_accounts: VoteAccounts = bincode::deserialize(&data).unwrap();
473 assert!(vote_accounts.staked_nodes().len() > 32);
474 assert_eq!(*vote_accounts.vote_accounts, vote_accounts_hash_map);
475 let data = bincode::options()
476 .serialize(&vote_accounts_hash_map)
477 .unwrap();
478 let vote_accounts: VoteAccounts = bincode::options().deserialize(&data).unwrap();
479 assert_eq!(*vote_accounts.vote_accounts, vote_accounts_hash_map);
480 }
481
482 #[test]
483 fn test_staked_nodes() {
484 let mut rng = rand::thread_rng();
485 let mut accounts: Vec<_> = new_rand_vote_accounts(&mut rng, 64).take(1024).collect();
486 let mut vote_accounts = VoteAccounts::default();
487 for (k, (pubkey, (stake, vote_account))) in accounts.iter().enumerate() {
489 vote_accounts.insert(*pubkey, (*stake, vote_account.clone()));
490 if (k + 1) % 128 == 0 {
491 assert_eq!(
492 staked_nodes(&accounts[..k + 1]),
493 *vote_accounts.staked_nodes()
494 );
495 }
496 }
497 for k in 0..256 {
499 let index = rng.gen_range(0, accounts.len());
500 let (pubkey, (_, _)) = accounts.swap_remove(index);
501 vote_accounts.remove(&pubkey);
502 if (k + 1) % 32 == 0 {
503 assert_eq!(staked_nodes(&accounts), *vote_accounts.staked_nodes());
504 }
505 }
506 for k in 0..2048 {
508 let index = rng.gen_range(0, accounts.len());
509 let (pubkey, (stake, _)) = &mut accounts[index];
510 let new_stake = rng.gen_range(0, 997);
511 if new_stake < *stake {
512 vote_accounts.sub_stake(pubkey, *stake - new_stake);
513 } else {
514 vote_accounts.add_stake(pubkey, new_stake - *stake);
515 }
516 *stake = new_stake;
517 if (k + 1) % 128 == 0 {
518 assert_eq!(staked_nodes(&accounts), *vote_accounts.staked_nodes());
519 }
520 }
521 while !accounts.is_empty() {
523 let index = rng.gen_range(0, accounts.len());
524 let (pubkey, (_, _)) = accounts.swap_remove(index);
525 vote_accounts.remove(&pubkey);
526 if accounts.len() % 32 == 0 {
527 assert_eq!(staked_nodes(&accounts), *vote_accounts.staked_nodes());
528 }
529 }
530 assert!(vote_accounts.staked_nodes.get().unwrap().is_empty());
531 }
532
533 #[test]
535 fn test_staked_nodes_cow() {
536 let mut rng = rand::thread_rng();
537 let mut accounts = new_rand_vote_accounts(&mut rng, 64);
538 let mut vote_accounts = VoteAccounts::default();
540 for (pubkey, (stake, vote_account)) in (&mut accounts).take(1024) {
541 vote_accounts.insert(pubkey, (stake, vote_account));
542 }
543 let staked_nodes = vote_accounts.staked_nodes();
544 let (pubkey, (more_stake, vote_account)) =
545 accounts.find(|(_, (stake, _))| *stake != 0).unwrap();
546 let node_pubkey = vote_account.node_pubkey().unwrap();
547 vote_accounts.insert(pubkey, (more_stake, vote_account));
548 assert_ne!(staked_nodes, vote_accounts.staked_nodes());
549 assert_eq!(
550 vote_accounts.staked_nodes()[&node_pubkey],
551 more_stake + staked_nodes.get(&node_pubkey).copied().unwrap_or_default()
552 );
553 for (pubkey, stake) in vote_accounts.staked_nodes().iter() {
554 if *pubkey != node_pubkey {
555 assert_eq!(*stake, staked_nodes[pubkey]);
556 } else {
557 assert_eq!(
558 *stake,
559 more_stake + staked_nodes.get(pubkey).copied().unwrap_or_default()
560 );
561 }
562 }
563 }
564
565 #[test]
567 fn test_vote_accounts_cow() {
568 let mut rng = rand::thread_rng();
569 let mut accounts = new_rand_vote_accounts(&mut rng, 64);
570 let mut vote_accounts = VoteAccounts::default();
572 for (pubkey, (stake, vote_account)) in (&mut accounts).take(1024) {
573 vote_accounts.insert(pubkey, (stake, vote_account));
574 }
575 let vote_accounts_hashmap = Arc::<VoteAccountsHashMap>::from(&vote_accounts);
576 assert_eq!(vote_accounts_hashmap, vote_accounts.vote_accounts);
577 assert!(Arc::ptr_eq(
578 &vote_accounts_hashmap,
579 &vote_accounts.vote_accounts
580 ));
581 let (pubkey, (more_stake, vote_account)) =
582 accounts.find(|(_, (stake, _))| *stake != 0).unwrap();
583 vote_accounts.insert(pubkey, (more_stake, vote_account.clone()));
584 assert!(!Arc::ptr_eq(
585 &vote_accounts_hashmap,
586 &vote_accounts.vote_accounts
587 ));
588 assert_ne!(vote_accounts_hashmap, vote_accounts.vote_accounts);
589 let other = (more_stake, vote_account);
590 for (pk, value) in vote_accounts.vote_accounts.iter() {
591 if *pk != pubkey {
592 assert_eq!(value, &vote_accounts_hashmap[pk]);
593 } else {
594 assert_eq!(value, &other);
595 }
596 }
597 }
598}