Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit d244d14

Browse files
committed
Fix callers of VoteAccounts::vote_state() holding the lock too long
1 parent 877feda commit d244d14

File tree

8 files changed

+48
-48
lines changed

8 files changed

+48
-48
lines changed

core/src/consensus.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ impl Tower {
271271
continue;
272272
}
273273
trace!("{} {} with stake {}", vote_account_pubkey, key, voted_stake);
274-
let mut vote_state = match account.vote_state().as_ref() {
274+
let vote_state = account.vote_state().clone();
275+
let mut vote_state = match vote_state {
275276
Err(_) => {
276277
datapoint_warn!(
277278
"tower_warn",
@@ -283,7 +284,7 @@ impl Tower {
283284
);
284285
continue;
285286
}
286-
Ok(vote_state) => vote_state.clone(),
287+
Ok(vote_state) => vote_state,
287288
};
288289
for vote in &vote_state.votes {
289290
lockout_intervals

core/src/replay_stage.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,16 +1919,16 @@ impl ReplayStage {
19191919
Some((_stake, vote_account)) => vote_account,
19201920
};
19211921
let vote_state = vote_account.vote_state();
1922-
let vote_state = match vote_state.as_ref() {
1923-
Err(_) => {
1924-
warn!(
1925-
"Vote account {} is unreadable. Unable to vote",
1926-
vote_account_pubkey,
1927-
);
1928-
return None;
1929-
}
1930-
Ok(vote_state) => vote_state,
1931-
};
1922+
if vote_state.is_err() {
1923+
drop(vote_state);
1924+
warn!(
1925+
"Vote account {} is unreadable. Unable to vote",
1926+
vote_account_pubkey,
1927+
);
1928+
return None;
1929+
}
1930+
// SAFETY: The `.unwrap()` is safe here because we just checked if vote_state is Err
1931+
let vote_state = vote_state.as_ref().unwrap();
19321932

19331933
if vote_state.node_pubkey != node_keypair.pubkey() {
19341934
info!(

core/src/validator.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,11 +1956,7 @@ fn get_stake_percent_in_gossip(bank: &Bank, cluster_info: &ClusterInfo, log: boo
19561956
if activated_stake == 0 {
19571957
continue;
19581958
}
1959-
let vote_state_node_pubkey = vote_account
1960-
.vote_state()
1961-
.as_ref()
1962-
.map(|vote_state| vote_state.node_pubkey)
1963-
.unwrap_or_default();
1959+
let vote_state_node_pubkey = vote_account.node_pubkey().unwrap_or_default();
19641960

19651961
if let Some(peer) = peers.get(&vote_state_node_pubkey) {
19661962
if peer.shred_version == my_shred_version {

ledger/src/blockstore_processor.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,16 +1462,19 @@ fn supermajority_root_from_vote_accounts(
14621462
return None;
14631463
}
14641464

1465-
match account.vote_state().as_ref() {
1466-
Err(_) => {
1467-
warn!(
1468-
"Unable to get vote_state from account {} in bank: {}",
1469-
key, bank_slot
1470-
);
1471-
None
1472-
}
1473-
Ok(vote_state) => Some((vote_state.root_slot?, *stake)),
1465+
let vote_state = account.vote_state();
1466+
if vote_state.is_err() {
1467+
drop(vote_state);
1468+
warn!(
1469+
"Unable to get vote_state from account {} in bank: {}",
1470+
key, bank_slot
1471+
);
1472+
return None;
14741473
}
1474+
// SAFETY: The `.unwrap()` is safe here because we just checked if vote_state is Err
1475+
let vote_state = vote_state.as_ref().unwrap();
1476+
1477+
Some((vote_state.root_slot?, *stake))
14751478
})
14761479
.collect();
14771480

runtime/src/bank.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ use {
156156
collections::{HashMap, HashSet},
157157
convert::{TryFrom, TryInto},
158158
fmt, mem,
159-
ops::{Deref, Div, RangeInclusive},
159+
ops::{Div, RangeInclusive},
160160
path::PathBuf,
161161
rc::Rc,
162162
sync::{
@@ -2977,8 +2977,9 @@ impl Bank {
29772977
invalid_vote_keys.insert(vote_pubkey, InvalidCacheEntryReason::WrongOwner);
29782978
return None;
29792979
}
2980-
let vote_state = match vote_account.vote_state().deref() {
2981-
Ok(vote_state) => vote_state.clone(),
2980+
let vote_state = vote_account.vote_state().clone();
2981+
let vote_state = match vote_state {
2982+
Ok(vote_state) => vote_state,
29822983
Err(_) => {
29832984
invalid_vote_keys.insert(vote_pubkey, InvalidCacheEntryReason::BadState);
29842985
return None;
@@ -5043,7 +5044,7 @@ impl Bank {
50435044
None
50445045
} else {
50455046
total_staked += *staked;
5046-
let node_pubkey = account.vote_state().as_ref().ok()?.node_pubkey;
5047+
let node_pubkey = account.node_pubkey()?;
50475048
Some((node_pubkey, *staked))
50485049
}
50495050
})

runtime/src/epoch_stakes.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,21 +72,20 @@ impl EpochStakes {
7272
let epoch_authorized_voters = epoch_vote_accounts
7373
.iter()
7474
.filter_map(|(key, (stake, account))| {
75-
let vote_state = account.vote_state();
76-
let vote_state = match vote_state.as_ref() {
77-
Err(_) => {
78-
datapoint_warn!(
79-
"parse_epoch_vote_accounts",
80-
(
81-
"warn",
82-
format!("Unable to get vote_state from account {}", key),
83-
String
84-
),
85-
);
86-
return None;
87-
}
88-
Ok(vote_state) => vote_state,
89-
};
75+
let vote_state_lock = account.vote_state();
76+
if vote_state_lock.is_err() {
77+
drop(vote_state_lock);
78+
datapoint_warn!(
79+
"parse_epoch_vote_accounts",
80+
(
81+
"warn",
82+
format!("Unable to get vote_state from account {}", key),
83+
String
84+
),
85+
);
86+
return None;
87+
}
88+
let vote_state = vote_state_lock.as_ref().unwrap();
9089

9190
if *stake > 0 {
9291
if let Some(authorized_voter) = vote_state

runtime/src/stakes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ impl Stakes<StakeAccount> {
379379
pub(crate) fn highest_staked_node(&self) -> Option<Pubkey> {
380380
let key = |(_pubkey, (stake, _vote_account)): &(_, &(u64, _))| *stake;
381381
let (_pubkey, (_stake, vote_account)) = self.vote_accounts.iter().max_by_key(key)?;
382-
Some(vote_account.vote_state().as_ref().ok()?.node_pubkey)
382+
vote_account.node_pubkey()
383383
}
384384
}
385385

runtime/src/vote_account.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const INVALID_VOTE_STATE: Result<VoteState, Error> = Err(Error::InstructionError
2626
#[serde(try_from = "Account")]
2727
pub struct VoteAccount(Arc<VoteAccountInner>);
2828

29-
#[derive(Debug, Error)]
29+
#[derive(Debug, Error, Clone)]
3030
pub enum Error {
3131
#[error(transparent)]
3232
InstructionError(#[from] InstructionError),
@@ -93,7 +93,7 @@ impl VoteAccount {
9393
}
9494

9595
/// VoteState.node_pubkey of this vote-account.
96-
fn node_pubkey(&self) -> Option<Pubkey> {
96+
pub fn node_pubkey(&self) -> Option<Pubkey> {
9797
Some(self.vote_state().as_ref().ok()?.node_pubkey)
9898
}
9999
}

0 commit comments

Comments
 (0)