Add EpochSlots frozen state transition (#19112)
This commit is contained in:
parent
176036aa58
commit
22674000bd
|
@ -1367,7 +1367,7 @@ mod test {
|
||||||
|
|
||||||
// Simulate Replay dumping this slot
|
// Simulate Replay dumping this slot
|
||||||
let mut duplicate_slots_to_repair = DuplicateSlotsToRepair::default();
|
let mut duplicate_slots_to_repair = DuplicateSlotsToRepair::default();
|
||||||
duplicate_slots_to_repair.insert((dead_slot, Hash::new_unique()));
|
duplicate_slots_to_repair.insert(dead_slot, Hash::new_unique());
|
||||||
ReplayStage::dump_then_repair_correct_slots(
|
ReplayStage::dump_then_repair_correct_slots(
|
||||||
&mut duplicate_slots_to_repair,
|
&mut duplicate_slots_to_repair,
|
||||||
&mut bank_forks.read().unwrap().ancestors(),
|
&mut bank_forks.read().unwrap().ancestors(),
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -317,7 +317,7 @@ impl ReplayStage {
|
||||||
vote_tracker: Arc<VoteTracker>,
|
vote_tracker: Arc<VoteTracker>,
|
||||||
cluster_slots: Arc<ClusterSlots>,
|
cluster_slots: Arc<ClusterSlots>,
|
||||||
retransmit_slots_sender: RetransmitSlotsSender,
|
retransmit_slots_sender: RetransmitSlotsSender,
|
||||||
_duplicate_slots_reset_receiver: DuplicateSlotsResetReceiver,
|
epoch_slots_frozen_receiver: DuplicateSlotsResetReceiver,
|
||||||
replay_vote_sender: ReplayVoteSender,
|
replay_vote_sender: ReplayVoteSender,
|
||||||
gossip_duplicate_confirmed_slots_receiver: GossipDuplicateConfirmedSlotsReceiver,
|
gossip_duplicate_confirmed_slots_receiver: GossipDuplicateConfirmedSlotsReceiver,
|
||||||
gossip_verified_vote_hash_receiver: GossipVerifiedVoteHashReceiver,
|
gossip_verified_vote_hash_receiver: GossipVerifiedVoteHashReceiver,
|
||||||
|
@ -374,7 +374,8 @@ impl ReplayStage {
|
||||||
let mut replay_timing = ReplayTiming::default();
|
let mut replay_timing = ReplayTiming::default();
|
||||||
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
||||||
let mut gossip_duplicate_confirmed_slots: GossipDuplicateConfirmedSlots = GossipDuplicateConfirmedSlots::default();
|
let mut gossip_duplicate_confirmed_slots: GossipDuplicateConfirmedSlots = GossipDuplicateConfirmedSlots::default();
|
||||||
let mut duplicate_slots_to_repair = HashSet::new();
|
let mut epoch_slots_frozen_slots: EpochSlotsFrozenSlots = EpochSlotsFrozenSlots::default();
|
||||||
|
let mut duplicate_slots_to_repair = DuplicateSlotsToRepair::default();
|
||||||
let mut unfrozen_gossip_verified_vote_hashes: UnfrozenGossipVerifiedVoteHashes = UnfrozenGossipVerifiedVoteHashes::default();
|
let mut unfrozen_gossip_verified_vote_hashes: UnfrozenGossipVerifiedVoteHashes = UnfrozenGossipVerifiedVoteHashes::default();
|
||||||
let mut latest_validator_votes_for_frozen_banks: LatestValidatorVotesForFrozenBanks = LatestValidatorVotesForFrozenBanks::default();
|
let mut latest_validator_votes_for_frozen_banks: LatestValidatorVotesForFrozenBanks = LatestValidatorVotesForFrozenBanks::default();
|
||||||
let mut voted_signatures = Vec::new();
|
let mut voted_signatures = Vec::new();
|
||||||
|
@ -421,6 +422,7 @@ impl ReplayStage {
|
||||||
&rpc_subscriptions,
|
&rpc_subscriptions,
|
||||||
&mut duplicate_slots_tracker,
|
&mut duplicate_slots_tracker,
|
||||||
&gossip_duplicate_confirmed_slots,
|
&gossip_duplicate_confirmed_slots,
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
&mut unfrozen_gossip_verified_vote_hashes,
|
&mut unfrozen_gossip_verified_vote_hashes,
|
||||||
&mut latest_validator_votes_for_frozen_banks,
|
&mut latest_validator_votes_for_frozen_banks,
|
||||||
&cluster_slots_update_sender,
|
&cluster_slots_update_sender,
|
||||||
|
@ -432,6 +434,24 @@ impl ReplayStage {
|
||||||
|
|
||||||
let forks_root = bank_forks.read().unwrap().root();
|
let forks_root = bank_forks.read().unwrap().root();
|
||||||
|
|
||||||
|
// Reset any dead slots that have been frozen by a sufficient portion of
|
||||||
|
// the network. Signalled by repair_service.
|
||||||
|
let mut purge_dead_slots_time = Measure::start("purge_dead_slots");
|
||||||
|
Self::process_epoch_slots_frozen_dead_slots(
|
||||||
|
&my_pubkey,
|
||||||
|
&blockstore,
|
||||||
|
&epoch_slots_frozen_receiver,
|
||||||
|
&mut duplicate_slots_tracker,
|
||||||
|
&gossip_duplicate_confirmed_slots,
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
|
&mut progress,
|
||||||
|
&mut heaviest_subtree_fork_choice,
|
||||||
|
&bank_forks,
|
||||||
|
&mut duplicate_slots_to_repair,
|
||||||
|
&ancestor_hashes_replay_update_sender
|
||||||
|
);
|
||||||
|
purge_dead_slots_time.stop();
|
||||||
|
|
||||||
// Check for any newly confirmed slots detected from gossip.
|
// Check for any newly confirmed slots detected from gossip.
|
||||||
let mut process_gossip_duplicate_confirmed_slots_time = Measure::start("process_gossip_duplicate_confirmed_slots");
|
let mut process_gossip_duplicate_confirmed_slots_time = Measure::start("process_gossip_duplicate_confirmed_slots");
|
||||||
Self::process_gossip_duplicate_confirmed_slots(
|
Self::process_gossip_duplicate_confirmed_slots(
|
||||||
|
@ -439,6 +459,7 @@ impl ReplayStage {
|
||||||
&blockstore,
|
&blockstore,
|
||||||
&mut duplicate_slots_tracker,
|
&mut duplicate_slots_tracker,
|
||||||
&mut gossip_duplicate_confirmed_slots,
|
&mut gossip_duplicate_confirmed_slots,
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
&mut progress,
|
&mut progress,
|
||||||
&mut heaviest_subtree_fork_choice,
|
&mut heaviest_subtree_fork_choice,
|
||||||
|
@ -470,6 +491,7 @@ impl ReplayStage {
|
||||||
&duplicate_slots_receiver,
|
&duplicate_slots_receiver,
|
||||||
&mut duplicate_slots_tracker,
|
&mut duplicate_slots_tracker,
|
||||||
&gossip_duplicate_confirmed_slots,
|
&gossip_duplicate_confirmed_slots,
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
&mut progress,
|
&mut progress,
|
||||||
&mut heaviest_subtree_fork_choice,
|
&mut heaviest_subtree_fork_choice,
|
||||||
|
@ -516,7 +538,7 @@ impl ReplayStage {
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::mark_slots_confirmed(&confirmed_forks, &blockstore, &bank_forks, &mut progress, &mut duplicate_slots_tracker, &mut heaviest_subtree_fork_choice, &mut duplicate_slots_to_repair, &ancestor_hashes_replay_update_sender);
|
Self::mark_slots_confirmed(&confirmed_forks, &blockstore, &bank_forks, &mut progress, &mut duplicate_slots_tracker, &mut heaviest_subtree_fork_choice, &mut epoch_slots_frozen_slots, &mut duplicate_slots_to_repair, &ancestor_hashes_replay_update_sender);
|
||||||
}
|
}
|
||||||
compute_slot_stats_time.stop();
|
compute_slot_stats_time.stop();
|
||||||
|
|
||||||
|
@ -618,6 +640,7 @@ impl ReplayStage {
|
||||||
&mut has_new_vote_been_rooted,
|
&mut has_new_vote_been_rooted,
|
||||||
&mut replay_timing,
|
&mut replay_timing,
|
||||||
&voting_sender,
|
&voting_sender,
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
voting_time.stop();
|
voting_time.stop();
|
||||||
|
@ -875,7 +898,7 @@ impl ReplayStage {
|
||||||
// TODO: handle if alternate version of descendant also got confirmed after ancestor was
|
// TODO: handle if alternate version of descendant also got confirmed after ancestor was
|
||||||
// confirmed, what happens then? Should probably keep track of purged list and skip things
|
// confirmed, what happens then? Should probably keep track of purged list and skip things
|
||||||
// in `duplicate_slots_to_repair` that have already been purged. Add test.
|
// in `duplicate_slots_to_repair` that have already been purged. Add test.
|
||||||
duplicate_slots_to_repair.retain(|(duplicate_slot, correct_hash)| {
|
duplicate_slots_to_repair.retain(|duplicate_slot, correct_hash| {
|
||||||
// Should not purge duplicate slots if there is currently a poh bank building
|
// Should not purge duplicate slots if there is currently a poh bank building
|
||||||
// on top of that slot, as BankingStage might still be referencing/touching that state
|
// on top of that slot, as BankingStage might still be referencing/touching that state
|
||||||
// concurrently.
|
// concurrently.
|
||||||
|
@ -934,6 +957,10 @@ impl ReplayStage {
|
||||||
bank_forks,
|
bank_forks,
|
||||||
blockstore,
|
blockstore,
|
||||||
);
|
);
|
||||||
|
warn!(
|
||||||
|
"Notifying repair service to repair duplicate slot: {}",
|
||||||
|
*duplicate_slot,
|
||||||
|
);
|
||||||
true
|
true
|
||||||
// TODO: Send signal to repair to repair the correct version of
|
// TODO: Send signal to repair to repair the correct version of
|
||||||
// `duplicate_slot` with hash == `correct_hash`
|
// `duplicate_slot` with hash == `correct_hash`
|
||||||
|
@ -952,6 +979,58 @@ impl ReplayStage {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn process_epoch_slots_frozen_dead_slots(
|
||||||
|
pubkey: &Pubkey,
|
||||||
|
blockstore: &Blockstore,
|
||||||
|
epoch_slots_frozen_receiver: &DuplicateSlotsResetReceiver,
|
||||||
|
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
||||||
|
gossip_duplicate_confirmed_slots: &GossipDuplicateConfirmedSlots,
|
||||||
|
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
||||||
|
progress: &mut ProgressMap,
|
||||||
|
fork_choice: &mut HeaviestSubtreeForkChoice,
|
||||||
|
bank_forks: &RwLock<BankForks>,
|
||||||
|
duplicate_slots_to_repair: &mut DuplicateSlotsToRepair,
|
||||||
|
ancestor_hashes_replay_update_sender: &AncestorHashesReplayUpdateSender,
|
||||||
|
) {
|
||||||
|
let root = bank_forks.read().unwrap().root();
|
||||||
|
for maybe_purgeable_duplicate_slots in epoch_slots_frozen_receiver.try_iter() {
|
||||||
|
warn!(
|
||||||
|
"{} ReplayStage notified of epoch slots duplicate frozen dead slots: {:?}",
|
||||||
|
pubkey, maybe_purgeable_duplicate_slots
|
||||||
|
);
|
||||||
|
for (epoch_slots_frozen_slot, epoch_slots_frozen_hash) in
|
||||||
|
maybe_purgeable_duplicate_slots.into_iter()
|
||||||
|
{
|
||||||
|
let epoch_slots_frozen_state = EpochSlotsFrozenState::new_from_state(
|
||||||
|
epoch_slots_frozen_slot,
|
||||||
|
epoch_slots_frozen_hash,
|
||||||
|
gossip_duplicate_confirmed_slots,
|
||||||
|
fork_choice,
|
||||||
|
|| progress.is_dead(epoch_slots_frozen_slot).unwrap_or(false),
|
||||||
|
|| {
|
||||||
|
bank_forks
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get(epoch_slots_frozen_slot)
|
||||||
|
.map(|b| b.hash())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
check_slot_agrees_with_cluster(
|
||||||
|
epoch_slots_frozen_slot,
|
||||||
|
root,
|
||||||
|
blockstore,
|
||||||
|
duplicate_slots_tracker,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
|
fork_choice,
|
||||||
|
duplicate_slots_to_repair,
|
||||||
|
ancestor_hashes_replay_update_sender,
|
||||||
|
SlotStateUpdate::EpochSlotsFrozen(epoch_slots_frozen_state),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn purge_unconfirmed_duplicate_slot(
|
fn purge_unconfirmed_duplicate_slot(
|
||||||
duplicate_slot: Slot,
|
duplicate_slot: Slot,
|
||||||
ancestors: &mut HashMap<Slot, HashSet<Slot>>,
|
ancestors: &mut HashMap<Slot, HashSet<Slot>>,
|
||||||
|
@ -1077,11 +1156,13 @@ impl ReplayStage {
|
||||||
// optimistic and in the future, duplicate slot confirmations on the exact
|
// optimistic and in the future, duplicate slot confirmations on the exact
|
||||||
// single slots and does not account for votes on their descendants. Used solely
|
// single slots and does not account for votes on their descendants. Used solely
|
||||||
// for duplicate slot recovery.
|
// for duplicate slot recovery.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn process_gossip_duplicate_confirmed_slots(
|
fn process_gossip_duplicate_confirmed_slots(
|
||||||
gossip_duplicate_confirmed_slots_receiver: &GossipDuplicateConfirmedSlotsReceiver,
|
gossip_duplicate_confirmed_slots_receiver: &GossipDuplicateConfirmedSlotsReceiver,
|
||||||
blockstore: &Blockstore,
|
blockstore: &Blockstore,
|
||||||
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
||||||
gossip_duplicate_confirmed_slots: &mut GossipDuplicateConfirmedSlots,
|
gossip_duplicate_confirmed_slots: &mut GossipDuplicateConfirmedSlots,
|
||||||
|
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
||||||
bank_forks: &RwLock<BankForks>,
|
bank_forks: &RwLock<BankForks>,
|
||||||
progress: &mut ProgressMap,
|
progress: &mut ProgressMap,
|
||||||
fork_choice: &mut HeaviestSubtreeForkChoice,
|
fork_choice: &mut HeaviestSubtreeForkChoice,
|
||||||
|
@ -1111,6 +1192,7 @@ impl ReplayStage {
|
||||||
root,
|
root,
|
||||||
blockstore,
|
blockstore,
|
||||||
duplicate_slots_tracker,
|
duplicate_slots_tracker,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
fork_choice,
|
fork_choice,
|
||||||
duplicate_slots_to_repair,
|
duplicate_slots_to_repair,
|
||||||
ancestor_hashes_replay_update_sender,
|
ancestor_hashes_replay_update_sender,
|
||||||
|
@ -1140,11 +1222,13 @@ impl ReplayStage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks for and handle forks with duplicate slots.
|
// Checks for and handle forks with duplicate slots.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn process_duplicate_slots(
|
fn process_duplicate_slots(
|
||||||
blockstore: &Blockstore,
|
blockstore: &Blockstore,
|
||||||
duplicate_slots_receiver: &DuplicateSlotReceiver,
|
duplicate_slots_receiver: &DuplicateSlotReceiver,
|
||||||
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
||||||
gossip_duplicate_confirmed_slots: &GossipDuplicateConfirmedSlots,
|
gossip_duplicate_confirmed_slots: &GossipDuplicateConfirmedSlots,
|
||||||
|
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
||||||
bank_forks: &RwLock<BankForks>,
|
bank_forks: &RwLock<BankForks>,
|
||||||
progress: &mut ProgressMap,
|
progress: &mut ProgressMap,
|
||||||
fork_choice: &mut HeaviestSubtreeForkChoice,
|
fork_choice: &mut HeaviestSubtreeForkChoice,
|
||||||
|
@ -1177,6 +1261,7 @@ impl ReplayStage {
|
||||||
root_slot,
|
root_slot,
|
||||||
blockstore,
|
blockstore,
|
||||||
duplicate_slots_tracker,
|
duplicate_slots_tracker,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
fork_choice,
|
fork_choice,
|
||||||
duplicate_slots_to_repair,
|
duplicate_slots_to_repair,
|
||||||
ancestor_hashes_replay_update_sender,
|
ancestor_hashes_replay_update_sender,
|
||||||
|
@ -1425,6 +1510,7 @@ impl ReplayStage {
|
||||||
rpc_subscriptions: &Arc<RpcSubscriptions>,
|
rpc_subscriptions: &Arc<RpcSubscriptions>,
|
||||||
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
||||||
gossip_duplicate_confirmed_slots: &GossipDuplicateConfirmedSlots,
|
gossip_duplicate_confirmed_slots: &GossipDuplicateConfirmedSlots,
|
||||||
|
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
||||||
progress: &mut ProgressMap,
|
progress: &mut ProgressMap,
|
||||||
heaviest_subtree_fork_choice: &mut HeaviestSubtreeForkChoice,
|
heaviest_subtree_fork_choice: &mut HeaviestSubtreeForkChoice,
|
||||||
duplicate_slots_to_repair: &mut DuplicateSlotsToRepair,
|
duplicate_slots_to_repair: &mut DuplicateSlotsToRepair,
|
||||||
|
@ -1468,12 +1554,14 @@ impl ReplayStage {
|
||||||
duplicate_slots_tracker,
|
duplicate_slots_tracker,
|
||||||
gossip_duplicate_confirmed_slots,
|
gossip_duplicate_confirmed_slots,
|
||||||
heaviest_subtree_fork_choice,
|
heaviest_subtree_fork_choice,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
);
|
);
|
||||||
check_slot_agrees_with_cluster(
|
check_slot_agrees_with_cluster(
|
||||||
slot,
|
slot,
|
||||||
root,
|
root,
|
||||||
blockstore,
|
blockstore,
|
||||||
duplicate_slots_tracker,
|
duplicate_slots_tracker,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
heaviest_subtree_fork_choice,
|
heaviest_subtree_fork_choice,
|
||||||
duplicate_slots_to_repair,
|
duplicate_slots_to_repair,
|
||||||
ancestor_hashes_replay_update_sender,
|
ancestor_hashes_replay_update_sender,
|
||||||
|
@ -1507,6 +1595,7 @@ impl ReplayStage {
|
||||||
has_new_vote_been_rooted: &mut bool,
|
has_new_vote_been_rooted: &mut bool,
|
||||||
replay_timing: &mut ReplayTiming,
|
replay_timing: &mut ReplayTiming,
|
||||||
voting_sender: &Sender<VoteOp>,
|
voting_sender: &Sender<VoteOp>,
|
||||||
|
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
||||||
) {
|
) {
|
||||||
if bank.is_empty() {
|
if bank.is_empty() {
|
||||||
inc_new_counter_info!("replay_stage-voted_empty_bank", 1);
|
inc_new_counter_info!("replay_stage-voted_empty_bank", 1);
|
||||||
|
@ -1556,6 +1645,7 @@ impl ReplayStage {
|
||||||
unfrozen_gossip_verified_vote_hashes,
|
unfrozen_gossip_verified_vote_hashes,
|
||||||
has_new_vote_been_rooted,
|
has_new_vote_been_rooted,
|
||||||
vote_signatures,
|
vote_signatures,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
);
|
);
|
||||||
rpc_subscriptions.notify_roots(rooted_slots);
|
rpc_subscriptions.notify_roots(rooted_slots);
|
||||||
if let Some(sender) = bank_notification_sender {
|
if let Some(sender) = bank_notification_sender {
|
||||||
|
@ -1874,6 +1964,7 @@ impl ReplayStage {
|
||||||
rpc_subscriptions: &Arc<RpcSubscriptions>,
|
rpc_subscriptions: &Arc<RpcSubscriptions>,
|
||||||
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
||||||
gossip_duplicate_confirmed_slots: &GossipDuplicateConfirmedSlots,
|
gossip_duplicate_confirmed_slots: &GossipDuplicateConfirmedSlots,
|
||||||
|
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
||||||
unfrozen_gossip_verified_vote_hashes: &mut UnfrozenGossipVerifiedVoteHashes,
|
unfrozen_gossip_verified_vote_hashes: &mut UnfrozenGossipVerifiedVoteHashes,
|
||||||
latest_validator_votes_for_frozen_banks: &mut LatestValidatorVotesForFrozenBanks,
|
latest_validator_votes_for_frozen_banks: &mut LatestValidatorVotesForFrozenBanks,
|
||||||
cluster_slots_update_sender: &ClusterSlotsUpdateSender,
|
cluster_slots_update_sender: &ClusterSlotsUpdateSender,
|
||||||
|
@ -1943,6 +2034,7 @@ impl ReplayStage {
|
||||||
rpc_subscriptions,
|
rpc_subscriptions,
|
||||||
duplicate_slots_tracker,
|
duplicate_slots_tracker,
|
||||||
gossip_duplicate_confirmed_slots,
|
gossip_duplicate_confirmed_slots,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
progress,
|
progress,
|
||||||
heaviest_subtree_fork_choice,
|
heaviest_subtree_fork_choice,
|
||||||
duplicate_slots_to_repair,
|
duplicate_slots_to_repair,
|
||||||
|
@ -1993,12 +2085,14 @@ impl ReplayStage {
|
||||||
duplicate_slots_tracker,
|
duplicate_slots_tracker,
|
||||||
gossip_duplicate_confirmed_slots,
|
gossip_duplicate_confirmed_slots,
|
||||||
heaviest_subtree_fork_choice,
|
heaviest_subtree_fork_choice,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
);
|
);
|
||||||
check_slot_agrees_with_cluster(
|
check_slot_agrees_with_cluster(
|
||||||
bank.slot(),
|
bank.slot(),
|
||||||
bank_forks.read().unwrap().root(),
|
bank_forks.read().unwrap().root(),
|
||||||
blockstore,
|
blockstore,
|
||||||
duplicate_slots_tracker,
|
duplicate_slots_tracker,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
heaviest_subtree_fork_choice,
|
heaviest_subtree_fork_choice,
|
||||||
duplicate_slots_to_repair,
|
duplicate_slots_to_repair,
|
||||||
ancestor_hashes_replay_update_sender,
|
ancestor_hashes_replay_update_sender,
|
||||||
|
@ -2519,6 +2613,7 @@ impl ReplayStage {
|
||||||
progress: &mut ProgressMap,
|
progress: &mut ProgressMap,
|
||||||
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
duplicate_slots_tracker: &mut DuplicateSlotsTracker,
|
||||||
fork_choice: &mut HeaviestSubtreeForkChoice,
|
fork_choice: &mut HeaviestSubtreeForkChoice,
|
||||||
|
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
||||||
duplicate_slots_to_repair: &mut DuplicateSlotsToRepair,
|
duplicate_slots_to_repair: &mut DuplicateSlotsToRepair,
|
||||||
ancestor_hashes_replay_update_sender: &AncestorHashesReplayUpdateSender,
|
ancestor_hashes_replay_update_sender: &AncestorHashesReplayUpdateSender,
|
||||||
) {
|
) {
|
||||||
|
@ -2544,6 +2639,7 @@ impl ReplayStage {
|
||||||
root_slot,
|
root_slot,
|
||||||
blockstore,
|
blockstore,
|
||||||
duplicate_slots_tracker,
|
duplicate_slots_tracker,
|
||||||
|
epoch_slots_frozen_slots,
|
||||||
fork_choice,
|
fork_choice,
|
||||||
duplicate_slots_to_repair,
|
duplicate_slots_to_repair,
|
||||||
ancestor_hashes_replay_update_sender,
|
ancestor_hashes_replay_update_sender,
|
||||||
|
@ -2600,6 +2696,7 @@ impl ReplayStage {
|
||||||
unfrozen_gossip_verified_vote_hashes: &mut UnfrozenGossipVerifiedVoteHashes,
|
unfrozen_gossip_verified_vote_hashes: &mut UnfrozenGossipVerifiedVoteHashes,
|
||||||
has_new_vote_been_rooted: &mut bool,
|
has_new_vote_been_rooted: &mut bool,
|
||||||
voted_signatures: &mut Vec<Signature>,
|
voted_signatures: &mut Vec<Signature>,
|
||||||
|
epoch_slots_frozen_slots: &mut EpochSlotsFrozenSlots,
|
||||||
) {
|
) {
|
||||||
bank_forks.write().unwrap().set_root(
|
bank_forks.write().unwrap().set_root(
|
||||||
new_root,
|
new_root,
|
||||||
|
@ -2630,6 +2727,9 @@ impl ReplayStage {
|
||||||
std::mem::swap(gossip_duplicate_confirmed_slots, &mut slots_ge_root);
|
std::mem::swap(gossip_duplicate_confirmed_slots, &mut slots_ge_root);
|
||||||
|
|
||||||
unfrozen_gossip_verified_vote_hashes.set_root(new_root);
|
unfrozen_gossip_verified_vote_hashes.set_root(new_root);
|
||||||
|
let mut slots_ge_root = epoch_slots_frozen_slots.split_off(&new_root);
|
||||||
|
// epoch_slots_frozen_slots now only contains entries >= `new_root`
|
||||||
|
std::mem::swap(epoch_slots_frozen_slots, &mut slots_ge_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_new_bank_forks(
|
fn generate_new_bank_forks(
|
||||||
|
@ -3066,6 +3166,10 @@ pub mod tests {
|
||||||
.map(|s| (s, HashMap::new()))
|
.map(|s| (s, HashMap::new()))
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
|
let mut epoch_slots_frozen_slots: EpochSlotsFrozenSlots = vec![root - 1, root, root + 1]
|
||||||
|
.into_iter()
|
||||||
|
.map(|slot| (slot, Hash::default()))
|
||||||
|
.collect();
|
||||||
ReplayStage::handle_new_root(
|
ReplayStage::handle_new_root(
|
||||||
root,
|
root,
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
|
@ -3078,6 +3182,7 @@ pub mod tests {
|
||||||
&mut unfrozen_gossip_verified_vote_hashes,
|
&mut unfrozen_gossip_verified_vote_hashes,
|
||||||
&mut true,
|
&mut true,
|
||||||
&mut Vec::new(),
|
&mut Vec::new(),
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
);
|
);
|
||||||
assert_eq!(bank_forks.read().unwrap().root(), root);
|
assert_eq!(bank_forks.read().unwrap().root(), root);
|
||||||
assert_eq!(progress.len(), 1);
|
assert_eq!(progress.len(), 1);
|
||||||
|
@ -3102,6 +3207,13 @@ pub mod tests {
|
||||||
.collect::<Vec<Slot>>(),
|
.collect::<Vec<Slot>>(),
|
||||||
vec![root, root + 1]
|
vec![root, root + 1]
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
epoch_slots_frozen_slots
|
||||||
|
.into_iter()
|
||||||
|
.map(|(slot, _hash)| slot)
|
||||||
|
.collect::<Vec<Slot>>(),
|
||||||
|
vec![root, root + 1]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -3149,6 +3261,7 @@ pub mod tests {
|
||||||
&mut UnfrozenGossipVerifiedVoteHashes::default(),
|
&mut UnfrozenGossipVerifiedVoteHashes::default(),
|
||||||
&mut true,
|
&mut true,
|
||||||
&mut Vec::new(),
|
&mut Vec::new(),
|
||||||
|
&mut EpochSlotsFrozenSlots::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(bank_forks.read().unwrap().root(), root);
|
assert_eq!(bank_forks.read().unwrap().root(), root);
|
||||||
assert!(bank_forks.read().unwrap().get(confirmed_root).is_some());
|
assert!(bank_forks.read().unwrap().get(confirmed_root).is_some());
|
||||||
|
@ -3434,7 +3547,8 @@ pub mod tests {
|
||||||
err,
|
err,
|
||||||
&rpc_subscriptions,
|
&rpc_subscriptions,
|
||||||
&mut DuplicateSlotsTracker::default(),
|
&mut DuplicateSlotsTracker::default(),
|
||||||
&GossipDuplicateConfirmedSlots::default(),
|
&GossipDuplicateConfirmedSlots::new(),
|
||||||
|
&mut EpochSlotsFrozenSlots::default(),
|
||||||
&mut progress,
|
&mut progress,
|
||||||
&mut heaviest_subtree_fork_choice,
|
&mut heaviest_subtree_fork_choice,
|
||||||
&mut DuplicateSlotsToRepair::default(),
|
&mut DuplicateSlotsToRepair::default(),
|
||||||
|
@ -4867,6 +4981,7 @@ pub mod tests {
|
||||||
blockstore.store_duplicate_slot(4, vec![], vec![]).unwrap();
|
blockstore.store_duplicate_slot(4, vec![], vec![]).unwrap();
|
||||||
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
||||||
let mut gossip_duplicate_confirmed_slots = GossipDuplicateConfirmedSlots::default();
|
let mut gossip_duplicate_confirmed_slots = GossipDuplicateConfirmedSlots::default();
|
||||||
|
let mut epoch_slots_frozen_slots = EpochSlotsFrozenSlots::default();
|
||||||
let bank4_hash = bank_forks.read().unwrap().bank_hash(4).unwrap();
|
let bank4_hash = bank_forks.read().unwrap().bank_hash(4).unwrap();
|
||||||
assert_ne!(bank4_hash, Hash::default());
|
assert_ne!(bank4_hash, Hash::default());
|
||||||
let duplicate_state = DuplicateState::new_from_state(
|
let duplicate_state = DuplicateState::new_from_state(
|
||||||
|
@ -4883,6 +4998,7 @@ pub mod tests {
|
||||||
bank_forks.read().unwrap().root(),
|
bank_forks.read().unwrap().root(),
|
||||||
&blockstore,
|
&blockstore,
|
||||||
&mut duplicate_slots_tracker,
|
&mut duplicate_slots_tracker,
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
&mut vote_simulator.heaviest_subtree_fork_choice,
|
&mut vote_simulator.heaviest_subtree_fork_choice,
|
||||||
&mut DuplicateSlotsToRepair::default(),
|
&mut DuplicateSlotsToRepair::default(),
|
||||||
&ancestor_hashes_replay_update_sender,
|
&ancestor_hashes_replay_update_sender,
|
||||||
|
@ -4915,6 +5031,7 @@ pub mod tests {
|
||||||
bank_forks.read().unwrap().root(),
|
bank_forks.read().unwrap().root(),
|
||||||
&blockstore,
|
&blockstore,
|
||||||
&mut duplicate_slots_tracker,
|
&mut duplicate_slots_tracker,
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
&mut vote_simulator.heaviest_subtree_fork_choice,
|
&mut vote_simulator.heaviest_subtree_fork_choice,
|
||||||
&mut DuplicateSlotsToRepair::default(),
|
&mut DuplicateSlotsToRepair::default(),
|
||||||
&ancestor_hashes_replay_update_sender,
|
&ancestor_hashes_replay_update_sender,
|
||||||
|
@ -4936,7 +5053,7 @@ pub mod tests {
|
||||||
|
|
||||||
// If slot 4 is marked as confirmed, then this confirms slot 2 and 4, and
|
// If slot 4 is marked as confirmed, then this confirms slot 2 and 4, and
|
||||||
// then slot 4 is now the heaviest bank again
|
// then slot 4 is now the heaviest bank again
|
||||||
let mut duplicate_slots_to_repair = HashSet::new();
|
let mut duplicate_slots_to_repair = DuplicateSlotsToRepair::default();
|
||||||
gossip_duplicate_confirmed_slots.insert(4, bank4_hash);
|
gossip_duplicate_confirmed_slots.insert(4, bank4_hash);
|
||||||
let duplicate_confirmed_state = DuplicateConfirmedState::new_from_state(
|
let duplicate_confirmed_state = DuplicateConfirmedState::new_from_state(
|
||||||
bank4_hash,
|
bank4_hash,
|
||||||
|
@ -4948,6 +5065,7 @@ pub mod tests {
|
||||||
bank_forks.read().unwrap().root(),
|
bank_forks.read().unwrap().root(),
|
||||||
&blockstore,
|
&blockstore,
|
||||||
&mut duplicate_slots_tracker,
|
&mut duplicate_slots_tracker,
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
&mut vote_simulator.heaviest_subtree_fork_choice,
|
&mut vote_simulator.heaviest_subtree_fork_choice,
|
||||||
&mut duplicate_slots_to_repair,
|
&mut duplicate_slots_to_repair,
|
||||||
&ancestor_hashes_replay_update_sender,
|
&ancestor_hashes_replay_update_sender,
|
||||||
|
@ -4996,8 +5114,9 @@ pub mod tests {
|
||||||
// Insert different versions of both 1 and 2. Both slots 1 and 2 should
|
// Insert different versions of both 1 and 2. Both slots 1 and 2 should
|
||||||
// then be purged
|
// then be purged
|
||||||
let mut duplicate_slots_to_repair = DuplicateSlotsToRepair::default();
|
let mut duplicate_slots_to_repair = DuplicateSlotsToRepair::default();
|
||||||
duplicate_slots_to_repair.insert((1, Hash::new_unique()));
|
duplicate_slots_to_repair.insert(1, Hash::new_unique());
|
||||||
duplicate_slots_to_repair.insert((2, Hash::new_unique()));
|
duplicate_slots_to_repair.insert(2, Hash::new_unique());
|
||||||
|
|
||||||
ReplayStage::dump_then_repair_correct_slots(
|
ReplayStage::dump_then_repair_correct_slots(
|
||||||
&mut duplicate_slots_to_repair,
|
&mut duplicate_slots_to_repair,
|
||||||
&mut ancestors,
|
&mut ancestors,
|
||||||
|
@ -5079,6 +5198,7 @@ pub mod tests {
|
||||||
gossip_duplicate_confirmed_slots.insert(2, duplicate_confirmed_bank2_hash);
|
gossip_duplicate_confirmed_slots.insert(2, duplicate_confirmed_bank2_hash);
|
||||||
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
let mut duplicate_slots_tracker = DuplicateSlotsTracker::default();
|
||||||
let mut duplicate_slots_to_repair = DuplicateSlotsToRepair::default();
|
let mut duplicate_slots_to_repair = DuplicateSlotsToRepair::default();
|
||||||
|
let mut epoch_slots_frozen_slots = EpochSlotsFrozenSlots::default();
|
||||||
|
|
||||||
// Mark fork choice branch as invalid so select forks below doesn't panic
|
// Mark fork choice branch as invalid so select forks below doesn't panic
|
||||||
// on a nonexistent `heaviest_bank_on_same_fork` after we dump the duplciate fork.
|
// on a nonexistent `heaviest_bank_on_same_fork` after we dump the duplciate fork.
|
||||||
|
@ -5094,12 +5214,16 @@ pub mod tests {
|
||||||
bank_forks.read().unwrap().root(),
|
bank_forks.read().unwrap().root(),
|
||||||
blockstore,
|
blockstore,
|
||||||
&mut duplicate_slots_tracker,
|
&mut duplicate_slots_tracker,
|
||||||
|
&mut epoch_slots_frozen_slots,
|
||||||
heaviest_subtree_fork_choice,
|
heaviest_subtree_fork_choice,
|
||||||
&mut duplicate_slots_to_repair,
|
&mut duplicate_slots_to_repair,
|
||||||
&ancestor_hashes_replay_update_sender,
|
&ancestor_hashes_replay_update_sender,
|
||||||
SlotStateUpdate::DuplicateConfirmed(duplicate_confirmed_state),
|
SlotStateUpdate::DuplicateConfirmed(duplicate_confirmed_state),
|
||||||
);
|
);
|
||||||
assert!(duplicate_slots_to_repair.contains(&(2, duplicate_confirmed_bank2_hash)));
|
assert_eq!(
|
||||||
|
*duplicate_slots_to_repair.get(&2).unwrap(),
|
||||||
|
duplicate_confirmed_bank2_hash
|
||||||
|
);
|
||||||
let mut ancestors = bank_forks.read().unwrap().ancestors();
|
let mut ancestors = bank_forks.read().unwrap().ancestors();
|
||||||
let mut descendants = bank_forks.read().unwrap().descendants().clone();
|
let mut descendants = bank_forks.read().unwrap().descendants().clone();
|
||||||
let old_descendants_of_2 = descendants.get(&2).unwrap().clone();
|
let old_descendants_of_2 = descendants.get(&2).unwrap().clone();
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
cluster_info_vote_listener::VoteTracker,
|
cluster_info_vote_listener::VoteTracker,
|
||||||
cluster_slot_state_verifier::{DuplicateSlotsTracker, GossipDuplicateConfirmedSlots},
|
cluster_slot_state_verifier::{
|
||||||
|
DuplicateSlotsTracker, EpochSlotsFrozenSlots, GossipDuplicateConfirmedSlots,
|
||||||
|
},
|
||||||
cluster_slots::ClusterSlots,
|
cluster_slots::ClusterSlots,
|
||||||
consensus::Tower,
|
consensus::Tower,
|
||||||
fork_choice::SelectVoteAndResetForkResult,
|
fork_choice::SelectVoteAndResetForkResult,
|
||||||
|
@ -212,6 +214,7 @@ impl VoteSimulator {
|
||||||
&mut UnfrozenGossipVerifiedVoteHashes::default(),
|
&mut UnfrozenGossipVerifiedVoteHashes::default(),
|
||||||
&mut true,
|
&mut true,
|
||||||
&mut Vec::new(),
|
&mut Vec::new(),
|
||||||
|
&mut EpochSlotsFrozenSlots::default(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2008,8 +2008,13 @@ fn test_snapshots_restart_validity() {
|
||||||
#[allow(unused_attributes)]
|
#[allow(unused_attributes)]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_fail_entry_verification_leader() {
|
fn test_fail_entry_verification_leader() {
|
||||||
let (cluster, _) =
|
let leader_stake = (DUPLICATE_THRESHOLD * 100.0) as u64 + 1;
|
||||||
test_faulty_node(BroadcastStageType::FailEntryVerification, vec![60, 50, 60]);
|
let validator_stake1 = (100 - leader_stake) / 2;
|
||||||
|
let validator_stake2 = 100 - leader_stake - validator_stake1;
|
||||||
|
let (cluster, _) = test_faulty_node(
|
||||||
|
BroadcastStageType::FailEntryVerification,
|
||||||
|
vec![leader_stake, validator_stake1, validator_stake2],
|
||||||
|
);
|
||||||
cluster.check_for_new_roots(
|
cluster.check_for_new_roots(
|
||||||
16,
|
16,
|
||||||
"test_fail_entry_verification_leader",
|
"test_fail_entry_verification_leader",
|
||||||
|
|
Loading…
Reference in New Issue