Skip to content

Commit e86b3cd

Browse files
authored
v2.0: fix: borrow stakes delegation during snapshot serialization (backport of #2455) (#2500)
1 parent 858279a commit e86b3cd

File tree

7 files changed

+239
-102
lines changed

7 files changed

+239
-102
lines changed

runtime/src/bank.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2296,8 +2296,7 @@ impl Bank {
22962296
.fold(
22972297
HashSet::default,
22982298
|mut voter_pubkeys, (_stake_pubkey, stake_account)| {
2299-
let delegation = stake_account.delegation();
2300-
voter_pubkeys.insert(delegation.voter_pubkey);
2299+
voter_pubkeys.insert(stake_account.delegation().voter_pubkey);
23012300
voter_pubkeys
23022301
},
23032302
)
@@ -2361,7 +2360,7 @@ impl Bank {
23612360
};
23622361
if let Some(reward_calc_tracer) = reward_calc_tracer.as_ref() {
23632362
let delegation =
2364-
InflationPointCalculationEvent::Delegation(delegation, solana_vote_program);
2363+
InflationPointCalculationEvent::Delegation(*delegation, solana_vote_program);
23652364
let event = RewardCalculationEvent::Staking(stake_pubkey, &delegation);
23662365
reward_calc_tracer(&event);
23672366
}

runtime/src/bank/partitioned_epoch_rewards/calculation.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,9 @@ impl Bank {
378378
let stake_pubkey = **stake_pubkey;
379379
let stake_account = (*stake_account).to_owned();
380380

381-
let delegation = stake_account.delegation();
381+
let vote_pubkey = stake_account.delegation().voter_pubkey;
382382
let (mut stake_account, stake_state) =
383383
<(AccountSharedData, StakeStateV2)>::from(stake_account);
384-
let vote_pubkey = delegation.voter_pubkey;
385384
let vote_account = get_vote_account(&vote_pubkey)?;
386385
if vote_account.owner() != &solana_vote_program {
387386
return None;
@@ -501,8 +500,7 @@ impl Bank {
501500
stake_delegations
502501
.par_iter()
503502
.map(|(_stake_pubkey, stake_account)| {
504-
let delegation = stake_account.delegation();
505-
let vote_pubkey = delegation.voter_pubkey;
503+
let vote_pubkey = stake_account.delegation().voter_pubkey;
506504

507505
let Some(vote_account) = get_vote_account(&vote_pubkey) else {
508506
return 0;

runtime/src/bank/serde_snapshot.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ mod tests {
488488
#[cfg_attr(
489489
feature = "frozen-abi",
490490
derive(AbiExample),
491-
frozen_abi(digest = "6riNuebfnAUpS2e3GYb5G8udH5PoEtep48ULchLjRDCB")
491+
frozen_abi(digest = "AzsxaiGEcf3Bxwna5DPS3w5DP4JjyxPDfHnYTvUfyZ5f")
492492
)]
493493
#[derive(Serialize)]
494494
pub struct BankAbiTestWrapper {

runtime/src/stake_account.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ impl<T> StakeAccount<T> {
4848

4949
impl StakeAccount<Delegation> {
5050
#[inline]
51-
pub(crate) fn delegation(&self) -> Delegation {
51+
pub(crate) fn delegation(&self) -> &Delegation {
5252
// Safe to unwrap here because StakeAccount<Delegation> will always
5353
// only wrap a stake-state which is a delegation.
54-
self.stake_state.delegation().unwrap()
54+
self.stake_state.delegation_ref().unwrap()
5555
}
5656
}
5757

runtime/src/stakes.rs

Lines changed: 14 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ use {
2626
thiserror::Error,
2727
};
2828

29+
mod serde_stakes;
30+
pub(crate) use serde_stakes::serde_stakes_enum_compat;
31+
2932
#[derive(Debug, Error)]
3033
pub enum Error {
3134
#[error("Invalid delegation: {0}")]
@@ -267,7 +270,7 @@ impl Stakes<StakeAccount> {
267270
let stake_account = StakeAccount::try_from(stake_account)?;
268271
// Sanity check that the delegation is consistent with what is
269272
// stored in the account.
270-
if stake_account.delegation() == *delegation {
273+
if stake_account.delegation() == delegation {
271274
map.insert(*pubkey, stake_account);
272275
Ok(map)
273276
} else {
@@ -499,12 +502,15 @@ impl StakesEnum {
499502
}
500503
}
501504

505+
/// This conversion is very memory intensive so should only be used in
506+
/// development contexts.
507+
#[cfg(feature = "dev-context-only-utils")]
502508
impl From<Stakes<StakeAccount>> for Stakes<Delegation> {
503509
fn from(stakes: Stakes<StakeAccount>) -> Self {
504510
let stake_delegations = stakes
505511
.stake_delegations
506512
.into_iter()
507-
.map(|(pubkey, stake_account)| (pubkey, stake_account.delegation()))
513+
.map(|(pubkey, stake_account)| (pubkey, *stake_account.delegation()))
508514
.collect();
509515
Self {
510516
vote_accounts: stakes.vote_accounts,
@@ -516,6 +522,9 @@ impl From<Stakes<StakeAccount>> for Stakes<Delegation> {
516522
}
517523
}
518524

525+
/// This conversion is memory intensive so should only be used in development
526+
/// contexts.
527+
#[cfg(feature = "dev-context-only-utils")]
519528
impl From<Stakes<Stake>> for Stakes<Delegation> {
520529
fn from(stakes: Stakes<Stake>) -> Self {
521530
let stake_delegations = stakes
@@ -533,6 +542,9 @@ impl From<Stakes<Stake>> for Stakes<Delegation> {
533542
}
534543
}
535544

545+
/// This conversion is memory intensive so should only be used in development
546+
/// contexts.
547+
#[cfg(feature = "dev-context-only-utils")]
536548
impl From<StakesEnum> for Stakes<Delegation> {
537549
fn from(stakes: StakesEnum) -> Self {
538550
match stakes {
@@ -576,36 +588,6 @@ impl PartialEq<StakesEnum> for StakesEnum {
576588
}
577589
}
578590

579-
// In order to maintain backward compatibility, the StakesEnum in EpochStakes
580-
// and SerializableVersionedBank should be serialized as Stakes<Delegation>.
581-
pub(crate) mod serde_stakes_enum_compat {
582-
use {
583-
super::*,
584-
serde::{Deserialize, Deserializer, Serialize, Serializer},
585-
};
586-
587-
pub(crate) fn serialize<S>(stakes: &StakesEnum, serializer: S) -> Result<S::Ok, S::Error>
588-
where
589-
S: Serializer,
590-
{
591-
match stakes {
592-
StakesEnum::Delegations(stakes) => stakes.serialize(serializer),
593-
stakes => {
594-
let stakes = Stakes::<Delegation>::from(stakes.clone());
595-
stakes.serialize(serializer)
596-
}
597-
}
598-
}
599-
600-
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Arc<StakesEnum>, D::Error>
601-
where
602-
D: Deserializer<'de>,
603-
{
604-
let stakes = Stakes::<Delegation>::deserialize(deserializer)?;
605-
Ok(Arc::new(StakesEnum::Delegations(stakes)))
606-
}
607-
}
608-
609591
fn refresh_vote_accounts(
610592
thread_pool: &ThreadPool,
611593
epoch: Epoch,
@@ -651,7 +633,6 @@ fn refresh_vote_accounts(
651633
pub(crate) mod tests {
652634
use {
653635
super::*,
654-
rand::Rng,
655636
rayon::ThreadPoolBuilder,
656637
solana_sdk::{account::WritableAccount, pubkey::Pubkey, rent::Rent, stake},
657638
solana_stake_program::stake_state,
@@ -1078,63 +1059,4 @@ pub(crate) mod tests {
10781059
);
10791060
}
10801061
}
1081-
1082-
#[test]
1083-
fn test_serde_stakes_enum_compat() {
1084-
#[derive(Debug, PartialEq, Deserialize, Serialize)]
1085-
struct Dummy {
1086-
head: String,
1087-
#[serde(with = "serde_stakes_enum_compat")]
1088-
stakes: Arc<StakesEnum>,
1089-
tail: String,
1090-
}
1091-
let mut rng = rand::thread_rng();
1092-
let stakes_cache = StakesCache::new(Stakes {
1093-
unused: rng.gen(),
1094-
epoch: rng.gen(),
1095-
..Stakes::default()
1096-
});
1097-
for _ in 0..rng.gen_range(5usize..10) {
1098-
let vote_pubkey = solana_sdk::pubkey::new_rand();
1099-
let vote_account = vote_state::create_account(
1100-
&vote_pubkey,
1101-
&solana_sdk::pubkey::new_rand(), // node_pubkey
1102-
rng.gen_range(0..101), // commission
1103-
rng.gen_range(0..1_000_000), // lamports
1104-
);
1105-
stakes_cache.check_and_store(&vote_pubkey, &vote_account, None);
1106-
for _ in 0..rng.gen_range(10usize..20) {
1107-
let stake_pubkey = solana_sdk::pubkey::new_rand();
1108-
let rent = Rent::with_slots_per_epoch(rng.gen());
1109-
let stake_account = stake_state::create_account(
1110-
&stake_pubkey, // authorized
1111-
&vote_pubkey,
1112-
&vote_account,
1113-
&rent,
1114-
rng.gen_range(0..1_000_000), // lamports
1115-
);
1116-
stakes_cache.check_and_store(&stake_pubkey, &stake_account, None);
1117-
}
1118-
}
1119-
let stakes: Stakes<StakeAccount> = stakes_cache.stakes().clone();
1120-
assert!(stakes.vote_accounts.as_ref().len() >= 5);
1121-
assert!(stakes.stake_delegations.len() >= 50);
1122-
let dummy = Dummy {
1123-
head: String::from("dummy-head"),
1124-
stakes: Arc::new(StakesEnum::from(stakes.clone())),
1125-
tail: String::from("dummy-tail"),
1126-
};
1127-
assert!(dummy.stakes.vote_accounts().as_ref().len() >= 5);
1128-
let data = bincode::serialize(&dummy).unwrap();
1129-
let other: Dummy = bincode::deserialize(&data).unwrap();
1130-
assert_eq!(other, dummy);
1131-
let stakes = Stakes::<Delegation>::from(stakes);
1132-
assert!(stakes.vote_accounts.as_ref().len() >= 5);
1133-
assert!(stakes.stake_delegations.len() >= 50);
1134-
let other = match &*other.stakes {
1135-
StakesEnum::Accounts(_) | StakesEnum::Stakes(_) => panic!("wrong type!"),
1136-
StakesEnum::Delegations(delegations) => delegations,
1137-
};
1138-
assert_eq!(other, &stakes)
1139-
}
11401062
}

0 commit comments

Comments
 (0)