75
75
solana_time_utils:: timestamp,
76
76
solana_transaction:: Transaction ,
77
77
solana_vote:: vote_transaction:: VoteTransaction ,
78
+ solana_votor:: root_utils,
78
79
std:: {
79
80
collections:: { HashMap , HashSet } ,
80
81
num:: { NonZeroUsize , Saturating } ,
@@ -2400,16 +2401,23 @@ impl ReplayStage {
2400
2401
let new_root = tower. record_bank_vote ( bank) ;
2401
2402
2402
2403
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
+ ) ;
2403
2410
Self :: check_and_handle_new_root (
2404
- bank,
2411
+ & identity_keypair. pubkey ( ) ,
2412
+ bank. parent_slot ( ) ,
2405
2413
new_root,
2406
2414
bank_forks,
2407
2415
progress,
2408
2416
blockstore,
2409
2417
leader_schedule_cache,
2410
2418
snapshot_controller,
2411
2419
rpc_subscriptions,
2412
- block_commitment_cache ,
2420
+ highest_super_majority_root ,
2413
2421
bank_notification_sender,
2414
2422
has_new_vote_been_rooted,
2415
2423
tracked_vote_transactions,
@@ -3967,119 +3975,62 @@ impl ReplayStage {
3967
3975
}
3968
3976
3969
3977
#[ 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
3970
3981
fn check_and_handle_new_root (
3971
- vote_bank : & Bank ,
3982
+ my_pubkey : & Pubkey ,
3983
+ parent_slot : Slot ,
3972
3984
new_root : Slot ,
3973
3985
bank_forks : & RwLock < BankForks > ,
3974
3986
progress : & mut ProgressMap ,
3975
3987
blockstore : & Blockstore ,
3976
3988
leader_schedule_cache : & Arc < LeaderScheduleCache > ,
3977
3989
snapshot_controller : Option < & SnapshotController > ,
3978
3990
rpc_subscriptions : Option < & RpcSubscriptions > ,
3979
- block_commitment_cache : & Arc < RwLock < BlockCommitmentCache > > ,
3991
+ highest_super_majority_root : Option < Slot > ,
3980
3992
bank_notification_sender : & Option < BankNotificationSenderConfig > ,
3981
3993
has_new_vote_been_rooted : & mut bool ,
3982
3994
tracked_vote_transactions : & mut Vec < TrackedVoteTransaction > ,
3983
3995
drop_bank_sender : & Sender < Vec < BankWithScheduler > > ,
3984
3996
tbft_structs : & mut TowerBFTStructures ,
3985
3997
) -> 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,
4021
4000
new_root,
4022
- bank_forks,
4023
- progress,
4024
4001
snapshot_controller,
4025
4002
highest_super_majority_root,
4026
- has_new_vote_been_rooted,
4027
- tracked_vote_transactions,
4003
+ bank_notification_sender,
4028
4004
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
+ )
4054
4021
}
4055
4022
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 (
4058
4026
new_root : Slot ,
4059
- bank_forks : & RwLock < BankForks > ,
4027
+ bank_forks : & BankForks ,
4060
4028
progress : & mut ProgressMap ,
4061
- snapshot_controller : Option < & SnapshotController > ,
4062
- highest_super_majority_root : Option < Slot > ,
4063
4029
has_new_vote_been_rooted : & mut bool ,
4064
4030
tracked_vote_transactions : & mut Vec < TrackedVoteTransaction > ,
4065
- drop_bank_sender : & Sender < Vec < BankWithScheduler > > ,
4066
4031
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] ;
4083
4034
if !* has_new_vote_been_rooted {
4084
4035
for TrackedVoteTransaction {
4085
4036
message_hash,
@@ -4098,15 +4049,17 @@ impl ReplayStage {
4098
4049
std:: mem:: take ( tracked_vote_transactions) ;
4099
4050
}
4100
4051
}
4101
- progress. handle_new_root ( & r_bank_forks) ;
4052
+
4053
+ progress. handle_new_root ( bank_forks) ;
4102
4054
let TowerBFTStructures {
4103
4055
heaviest_subtree_fork_choice,
4104
4056
duplicate_slots_tracker,
4105
4057
duplicate_confirmed_slots,
4106
- epoch_slots_frozen_slots,
4107
4058
unfrozen_gossip_verified_vote_hashes,
4059
+ epoch_slots_frozen_slots,
4060
+ ..
4108
4061
} = 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 ( ) ) ) ;
4110
4063
* duplicate_slots_tracker = duplicate_slots_tracker. split_off ( & new_root) ;
4111
4064
// duplicate_slots_tracker now only contains entries >= `new_root`
4112
4065
@@ -4115,10 +4068,41 @@ impl ReplayStage {
4115
4068
4116
4069
unfrozen_gossip_verified_vote_hashes. set_root ( new_root) ;
4117
4070
* epoch_slots_frozen_slots = epoch_slots_frozen_slots. split_off ( & new_root) ;
4118
- Ok ( ( ) )
4119
4071
// epoch_slots_frozen_slots now only contains entries >= `new_root`
4120
4072
}
4121
4073
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
+
4122
4106
fn generate_new_bank_forks (
4123
4107
blockstore : & Blockstore ,
4124
4108
bank_forks : & RwLock < BankForks > ,
0 commit comments