Skip to content

Commit b001c53

Browse files
committed
replay: refactor set-root to enable alpenglow to take over
1 parent f6e6ff2 commit b001c53

File tree

8 files changed

+385
-94
lines changed

8 files changed

+385
-94
lines changed

Cargo.lock

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ members = [
134134
"version",
135135
"vortexor",
136136
"vote",
137+
"votor",
137138
"watchtower",
138139
"wen-restart",
139140
"xdp",
@@ -554,6 +555,7 @@ solana-version = { path = "version", version = "=3.0.0" }
554555
solana-vote = { path = "vote", version = "=3.0.0" }
555556
solana-vote-interface = "2.2.6"
556557
solana-vote-program = { path = "programs/vote", version = "=3.0.0", default-features = false }
558+
solana-votor = { path = "votor", version = "=3.0.0" }
557559
solana-wen-restart = { path = "wen-restart", version = "=3.0.0" }
558560
solana-zk-elgamal-proof-program = { path = "programs/zk-elgamal-proof", version = "=3.0.0" }
559561
solana-zk-keygen = { path = "zk-keygen", version = "=3.0.0" }

core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ solana-validator-exit = { workspace = true }
164164
solana-version = { workspace = true }
165165
solana-vote = { workspace = true }
166166
solana-vote-program = { workspace = true }
167+
solana-votor = { workspace = true }
167168
solana-wen-restart = { workspace = true }
168169
static_assertions = { workspace = true }
169170
strum = { workspace = true, features = ["derive"] }

core/src/replay_stage.rs

Lines changed: 78 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ use {
7575
solana_time_utils::timestamp,
7676
solana_transaction::Transaction,
7777
solana_vote::vote_transaction::VoteTransaction,
78+
solana_votor::root_utils,
7879
std::{
7980
collections::{HashMap, HashSet},
8081
num::{NonZeroUsize, Saturating},
@@ -2400,16 +2401,23 @@ impl ReplayStage {
24002401
let new_root = tower.record_bank_vote(bank);
24012402

24022403
if let Some(new_root) = new_root {
2404+
let highest_super_majority_root = Some(
2405+
block_commitment_cache
2406+
.read()
2407+
.unwrap()
2408+
.highest_super_majority_root(),
2409+
);
24032410
Self::check_and_handle_new_root(
2404-
bank,
2411+
&identity_keypair.pubkey(),
2412+
bank.parent_slot(),
24052413
new_root,
24062414
bank_forks,
24072415
progress,
24082416
blockstore,
24092417
leader_schedule_cache,
24102418
snapshot_controller,
24112419
rpc_subscriptions,
2412-
block_commitment_cache,
2420+
highest_super_majority_root,
24132421
bank_notification_sender,
24142422
has_new_vote_been_rooted,
24152423
tracked_vote_transactions,
@@ -3967,119 +3975,62 @@ impl ReplayStage {
39673975
}
39683976

39693977
#[allow(clippy::too_many_arguments)]
3978+
/// A wrapper around `root_utils::check_and_handle_new_root` which:
3979+
/// - calls into `root_utils::set_bank_forks_root`
3980+
/// - Executes `set_progress_and_tower_bft_root` to cleanup tower bft structs and the progress map
39703981
fn check_and_handle_new_root(
3971-
vote_bank: &Bank,
3982+
my_pubkey: &Pubkey,
3983+
parent_slot: Slot,
39723984
new_root: Slot,
39733985
bank_forks: &RwLock<BankForks>,
39743986
progress: &mut ProgressMap,
39753987
blockstore: &Blockstore,
39763988
leader_schedule_cache: &Arc<LeaderScheduleCache>,
39773989
snapshot_controller: Option<&SnapshotController>,
39783990
rpc_subscriptions: Option<&RpcSubscriptions>,
3979-
block_commitment_cache: &Arc<RwLock<BlockCommitmentCache>>,
3991+
highest_super_majority_root: Option<Slot>,
39803992
bank_notification_sender: &Option<BankNotificationSenderConfig>,
39813993
has_new_vote_been_rooted: &mut bool,
39823994
tracked_vote_transactions: &mut Vec<TrackedVoteTransaction>,
39833995
drop_bank_sender: &Sender<Vec<BankWithScheduler>>,
39843996
tbft_structs: &mut TowerBFTStructures,
39853997
) -> Result<(), SetRootError> {
3986-
// get the root bank before squash
3987-
let root_bank = bank_forks
3988-
.read()
3989-
.unwrap()
3990-
.get(new_root)
3991-
.expect("Root bank doesn't exist");
3992-
let mut rooted_banks = root_bank.parents();
3993-
let oldest_parent = rooted_banks.last().map(|last| last.parent_slot());
3994-
rooted_banks.push(root_bank.clone());
3995-
let rooted_slots: Vec<_> = rooted_banks.iter().map(|bank| bank.slot()).collect();
3996-
// The following differs from rooted_slots by including the parent slot of the oldest parent bank.
3997-
let rooted_slots_with_parents = bank_notification_sender
3998-
.as_ref()
3999-
.is_some_and(|sender| sender.should_send_parents)
4000-
.then(|| {
4001-
let mut new_chain = rooted_slots.clone();
4002-
new_chain.push(oldest_parent.unwrap_or_else(|| vote_bank.parent_slot()));
4003-
new_chain
4004-
});
4005-
4006-
// Call leader schedule_cache.set_root() before blockstore.set_root() because
4007-
// bank_forks.root is consumed by repair_service to update gossip, so we don't want to
4008-
// get shreds for repair on gossip before we update leader schedule, otherwise they may
4009-
// get dropped.
4010-
leader_schedule_cache.set_root(rooted_banks.last().unwrap());
4011-
blockstore
4012-
.set_roots(rooted_slots.iter())
4013-
.expect("Ledger set roots failed");
4014-
let highest_super_majority_root = Some(
4015-
block_commitment_cache
4016-
.read()
4017-
.unwrap()
4018-
.highest_super_majority_root(),
4019-
);
4020-
Self::handle_new_root(
3998+
root_utils::check_and_handle_new_root(
3999+
parent_slot,
40214000
new_root,
4022-
bank_forks,
4023-
progress,
40244001
snapshot_controller,
40254002
highest_super_majority_root,
4026-
has_new_vote_been_rooted,
4027-
tracked_vote_transactions,
4003+
bank_notification_sender,
40284004
drop_bank_sender,
4029-
tbft_structs,
4030-
)?;
4031-
blockstore.slots_stats.mark_rooted(new_root);
4032-
if let Some(rpc_subscriptions) = rpc_subscriptions {
4033-
rpc_subscriptions.notify_roots(rooted_slots);
4034-
}
4035-
if let Some(sender) = bank_notification_sender {
4036-
let dependency_work = sender
4037-
.dependency_tracker
4038-
.as_ref()
4039-
.map(|s| s.get_current_declared_work());
4040-
sender
4041-
.sender
4042-
.send((BankNotification::NewRootBank(root_bank), dependency_work))
4043-
.unwrap_or_else(|err| warn!("bank_notification_sender failed: {err:?}"));
4044-
4045-
if let Some(new_chain) = rooted_slots_with_parents {
4046-
sender
4047-
.sender
4048-
.send((BankNotification::NewRootedChain(new_chain), dependency_work))
4049-
.unwrap_or_else(|err| warn!("bank_notification_sender failed: {err:?}"));
4050-
}
4051-
}
4052-
info!("new root {new_root}");
4053-
Ok(())
4005+
blockstore,
4006+
leader_schedule_cache,
4007+
bank_forks,
4008+
rpc_subscriptions,
4009+
my_pubkey,
4010+
move |bank_forks| {
4011+
Self::set_progress_and_tower_bft_root(
4012+
new_root,
4013+
bank_forks,
4014+
progress,
4015+
has_new_vote_been_rooted,
4016+
tracked_vote_transactions,
4017+
tbft_structs,
4018+
)
4019+
},
4020+
)
40544021
}
40554022

4056-
#[allow(clippy::too_many_arguments)]
4057-
pub fn handle_new_root(
4023+
// To avoid code duplication and keep compatibility with alpenglow, we add this
4024+
// extra callback in the rooting path. This happens immediately after setting the bank forks root
4025+
fn set_progress_and_tower_bft_root(
40584026
new_root: Slot,
4059-
bank_forks: &RwLock<BankForks>,
4027+
bank_forks: &BankForks,
40604028
progress: &mut ProgressMap,
4061-
snapshot_controller: Option<&SnapshotController>,
4062-
highest_super_majority_root: Option<Slot>,
40634029
has_new_vote_been_rooted: &mut bool,
40644030
tracked_vote_transactions: &mut Vec<TrackedVoteTransaction>,
4065-
drop_bank_sender: &Sender<Vec<BankWithScheduler>>,
40664031
tbft_structs: &mut TowerBFTStructures,
4067-
) -> Result<(), SetRootError> {
4068-
bank_forks.read().unwrap().prune_program_cache(new_root);
4069-
let removed_banks = bank_forks.write().unwrap().set_root(
4070-
new_root,
4071-
snapshot_controller,
4072-
highest_super_majority_root,
4073-
)?;
4074-
4075-
drop_bank_sender
4076-
.send(removed_banks)
4077-
.unwrap_or_else(|err| warn!("bank drop failed: {err:?}"));
4078-
4079-
// Dropping the bank_forks write lock and reacquiring as a read lock is
4080-
// safe because updates to bank_forks are only made by a single thread.
4081-
let r_bank_forks = bank_forks.read().unwrap();
4082-
let new_root_bank = &r_bank_forks[new_root];
4032+
) {
4033+
let new_root_bank = &bank_forks[new_root];
40834034
if !*has_new_vote_been_rooted {
40844035
for TrackedVoteTransaction {
40854036
message_hash,
@@ -4098,15 +4049,17 @@ impl ReplayStage {
40984049
std::mem::take(tracked_vote_transactions);
40994050
}
41004051
}
4101-
progress.handle_new_root(&r_bank_forks);
4052+
4053+
progress.handle_new_root(bank_forks);
41024054
let TowerBFTStructures {
41034055
heaviest_subtree_fork_choice,
41044056
duplicate_slots_tracker,
41054057
duplicate_confirmed_slots,
4106-
epoch_slots_frozen_slots,
41074058
unfrozen_gossip_verified_vote_hashes,
4059+
epoch_slots_frozen_slots,
4060+
..
41084061
} = tbft_structs;
4109-
heaviest_subtree_fork_choice.set_tree_root((new_root, r_bank_forks.root_bank().hash()));
4062+
heaviest_subtree_fork_choice.set_tree_root((new_root, bank_forks.root_bank().hash()));
41104063
*duplicate_slots_tracker = duplicate_slots_tracker.split_off(&new_root);
41114064
// duplicate_slots_tracker now only contains entries >= `new_root`
41124065

@@ -4115,10 +4068,41 @@ impl ReplayStage {
41154068

41164069
unfrozen_gossip_verified_vote_hashes.set_root(new_root);
41174070
*epoch_slots_frozen_slots = epoch_slots_frozen_slots.split_off(&new_root);
4118-
Ok(())
41194071
// epoch_slots_frozen_slots now only contains entries >= `new_root`
41204072
}
41214073

4074+
#[allow(clippy::too_many_arguments)]
4075+
pub fn handle_new_root(
4076+
new_root: Slot,
4077+
bank_forks: &RwLock<BankForks>,
4078+
progress: &mut ProgressMap,
4079+
snapshot_controller: Option<&SnapshotController>,
4080+
highest_super_majority_root: Option<Slot>,
4081+
has_new_vote_been_rooted: &mut bool,
4082+
tracked_vote_transactions: &mut Vec<TrackedVoteTransaction>,
4083+
drop_bank_sender: &Sender<Vec<BankWithScheduler>>,
4084+
tbft_structs: &mut TowerBFTStructures,
4085+
) -> Result<(), SetRootError> {
4086+
root_utils::set_bank_forks_root(
4087+
new_root,
4088+
bank_forks,
4089+
snapshot_controller,
4090+
highest_super_majority_root,
4091+
drop_bank_sender,
4092+
move |bank_forks| {
4093+
Self::set_progress_and_tower_bft_root(
4094+
new_root,
4095+
bank_forks,
4096+
progress,
4097+
has_new_vote_been_rooted,
4098+
tracked_vote_transactions,
4099+
tbft_structs,
4100+
)
4101+
},
4102+
)?;
4103+
Ok(())
4104+
}
4105+
41224106
fn generate_new_bank_forks(
41234107
blockstore: &Blockstore,
41244108
bank_forks: &RwLock<BankForks>,

programs/sbf/Cargo.lock

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)