(cherry picked from commit 3533e11786
)
Co-authored-by: carllin <wumu727@gmail.com>
This commit is contained in:
@ -24,6 +24,7 @@ use solana_runtime::{
|
|||||||
vote_sender_types::ReplayVoteSender,
|
vote_sender_types::ReplayVoteSender,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
|
account::Account,
|
||||||
clock::{Slot, MAX_PROCESSING_AGE},
|
clock::{Slot, MAX_PROCESSING_AGE},
|
||||||
genesis_config::GenesisConfig,
|
genesis_config::GenesisConfig,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
@ -35,7 +36,7 @@ use solana_sdk::{
|
|||||||
use solana_vote_program::vote_state::VoteState;
|
use solana_vote_program::vote_state::VoteState;
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{BTreeMap, HashMap},
|
collections::HashMap,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
result,
|
result,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
@ -877,7 +878,8 @@ fn load_frozen_forks(
|
|||||||
// for newer cluster confirmed roots
|
// for newer cluster confirmed roots
|
||||||
let new_root_bank = {
|
let new_root_bank = {
|
||||||
if *root == max_root {
|
if *root == max_root {
|
||||||
supermajority_root_from_bank(&bank).and_then(|supermajority_root| {
|
supermajority_root_from_vote_accounts(bank.slot(), bank.total_epoch_stake(), bank.vote_accounts()
|
||||||
|
.into_iter()).and_then(|supermajority_root| {
|
||||||
if supermajority_root > *root {
|
if supermajority_root > *root {
|
||||||
// If there's a cluster confirmed root greater than our last
|
// If there's a cluster confirmed root greater than our last
|
||||||
// replayed root, then beccause the cluster confirmed root should
|
// replayed root, then beccause the cluster confirmed root should
|
||||||
@ -944,23 +946,36 @@ fn load_frozen_forks(
|
|||||||
Ok(initial_forks.values().cloned().collect::<Vec<_>>())
|
Ok(initial_forks.values().cloned().collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supermajority_root(roots: &BTreeMap<Slot, u64>, total_epoch_stake: u64) -> Option<Slot> {
|
// `roots` is sorted largest to smallest by root slot
|
||||||
|
fn supermajority_root(roots: &[(Slot, u64)], total_epoch_stake: u64) -> Option<Slot> {
|
||||||
|
if roots.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// Find latest root
|
// Find latest root
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
for (root, stake) in roots.iter().rev() {
|
let mut prev_root = roots[0].0;
|
||||||
|
for (root, stake) in roots.iter() {
|
||||||
|
assert!(*root <= prev_root);
|
||||||
total += stake;
|
total += stake;
|
||||||
if total as f64 / total_epoch_stake as f64 > VOTE_THRESHOLD_SIZE {
|
if total as f64 / total_epoch_stake as f64 > VOTE_THRESHOLD_SIZE {
|
||||||
return Some(*root);
|
return Some(*root);
|
||||||
}
|
}
|
||||||
|
prev_root = *root;
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supermajority_root_from_bank(bank: &Bank) -> Option<Slot> {
|
fn supermajority_root_from_vote_accounts<I>(
|
||||||
let roots: BTreeMap<Slot, u64> = bank
|
bank_slot: Slot,
|
||||||
.vote_accounts()
|
total_epoch_stake: u64,
|
||||||
.into_iter()
|
vote_accounts_iter: I,
|
||||||
|
) -> Option<Slot>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = (Pubkey, (u64, Account))>,
|
||||||
|
{
|
||||||
|
let mut roots_stakes: Vec<(Slot, u64)> = vote_accounts_iter
|
||||||
.filter_map(|(key, (stake, account))| {
|
.filter_map(|(key, (stake, account))| {
|
||||||
if stake == 0 {
|
if stake == 0 {
|
||||||
return None;
|
return None;
|
||||||
@ -970,8 +985,7 @@ fn supermajority_root_from_bank(bank: &Bank) -> Option<Slot> {
|
|||||||
if vote_state.is_none() {
|
if vote_state.is_none() {
|
||||||
warn!(
|
warn!(
|
||||||
"Unable to get vote_state from account {} in bank: {}",
|
"Unable to get vote_state from account {} in bank: {}",
|
||||||
key,
|
key, bank_slot
|
||||||
bank.slot()
|
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -983,10 +997,11 @@ fn supermajority_root_from_bank(bank: &Bank) -> Option<Slot> {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let total_epoch_stake = bank.total_epoch_stake();
|
// Sort from greatest to smallest slot
|
||||||
|
roots_stakes.sort_unstable_by(|a, b| a.0.cmp(&b.0).reverse());
|
||||||
|
|
||||||
// Find latest root
|
// Find latest root
|
||||||
supermajority_root(&roots, total_epoch_stake)
|
supermajority_root(&roots_stakes, total_epoch_stake)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processes and replays the contents of a single slot, returns Error
|
// Processes and replays the contents of a single slot, returns Error
|
||||||
@ -1099,7 +1114,6 @@ pub mod tests {
|
|||||||
use solana_runtime::genesis_utils::{
|
use solana_runtime::genesis_utils::{
|
||||||
self, create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs,
|
self, create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs,
|
||||||
};
|
};
|
||||||
use solana_sdk::account::Account;
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
epoch_schedule::EpochSchedule,
|
epoch_schedule::EpochSchedule,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
@ -1109,7 +1123,11 @@ pub mod tests {
|
|||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
use solana_vote_program::{vote_state::MAX_LOCKOUT_HISTORY, vote_transaction};
|
use solana_vote_program::{
|
||||||
|
self,
|
||||||
|
vote_state::{VoteStateVersions, MAX_LOCKOUT_HISTORY},
|
||||||
|
vote_transaction,
|
||||||
|
};
|
||||||
use std::{collections::BTreeSet, sync::RwLock};
|
use std::{collections::BTreeSet, sync::RwLock};
|
||||||
use trees::tr;
|
use trees::tr;
|
||||||
|
|
||||||
@ -3123,6 +3141,57 @@ pub mod tests {
|
|||||||
run_test_process_blockstore_with_supermajority_root(Some(1))
|
run_test_process_blockstore_with_supermajority_root(Some(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_supermajority_root_from_vote_accounts() {
|
||||||
|
let convert_to_vote_accounts =
|
||||||
|
|roots_stakes: Vec<(Slot, u64)>| -> Vec<(Pubkey, (u64, Account))> {
|
||||||
|
roots_stakes
|
||||||
|
.into_iter()
|
||||||
|
.map(|(root, stake)| {
|
||||||
|
let mut vote_state = VoteState::default();
|
||||||
|
vote_state.root_slot = Some(root);
|
||||||
|
let mut vote_account =
|
||||||
|
Account::new(1, VoteState::size_of(), &solana_vote_program::id());
|
||||||
|
let versioned = VoteStateVersions::Current(Box::new(vote_state));
|
||||||
|
VoteState::serialize(&versioned, &mut vote_account.data).unwrap();
|
||||||
|
(Pubkey::new_rand(), (stake, vote_account))
|
||||||
|
})
|
||||||
|
.collect_vec()
|
||||||
|
};
|
||||||
|
|
||||||
|
let total_stake = 10;
|
||||||
|
let slot = 100;
|
||||||
|
|
||||||
|
// Supermajority root should be None
|
||||||
|
assert!(
|
||||||
|
supermajority_root_from_vote_accounts(slot, total_stake, std::iter::empty()).is_none()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Supermajority root should be None
|
||||||
|
let roots_stakes = vec![(8, 1), (3, 1), (4, 1), (8, 1)];
|
||||||
|
let accounts = convert_to_vote_accounts(roots_stakes);
|
||||||
|
assert!(
|
||||||
|
supermajority_root_from_vote_accounts(slot, total_stake, accounts.into_iter())
|
||||||
|
.is_none()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Supermajority root should be 4, has 7/10 of the stake
|
||||||
|
let roots_stakes = vec![(8, 1), (3, 1), (4, 1), (8, 5)];
|
||||||
|
let accounts = convert_to_vote_accounts(roots_stakes);
|
||||||
|
assert_eq!(
|
||||||
|
supermajority_root_from_vote_accounts(slot, total_stake, accounts.into_iter()).unwrap(),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
|
||||||
|
// Supermajority root should be 8, it has 7/10 of the stake
|
||||||
|
let roots_stakes = vec![(8, 1), (3, 1), (4, 1), (8, 6)];
|
||||||
|
let accounts = convert_to_vote_accounts(roots_stakes);
|
||||||
|
assert_eq!(
|
||||||
|
supermajority_root_from_vote_accounts(slot, total_stake, accounts.into_iter()).unwrap(),
|
||||||
|
8
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_process_blockstore_feature_activations_since_genesis() {
|
fn test_process_blockstore_feature_activations_since_genesis() {
|
||||||
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(123);
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(123);
|
||||||
|
Reference in New Issue
Block a user