Fix bad assertion (#17401)
This commit is contained in:
@ -715,6 +715,8 @@ impl Tower {
|
|||||||
// then use this bank as a representative for the fork.
|
// then use this bank as a representative for the fork.
|
||||||
|| descendants.iter().any(|d| progress.get_fork_stats(*d).map(|stats| stats.computed).unwrap_or(false))
|
|| descendants.iter().any(|d| progress.get_fork_stats(*d).map(|stats| stats.computed).unwrap_or(false))
|
||||||
|| *candidate_slot == last_voted_slot
|
|| *candidate_slot == last_voted_slot
|
||||||
|
// Ignore if the `candidate_slot` is a descendant of the `last_voted_slot`, since we do not
|
||||||
|
// want to count votes on the same fork.
|
||||||
|| Self::is_candidate_slot_descendant_of_last_vote(*candidate_slot, last_voted_slot, ancestors).expect("exists in descendants map, so must exist in ancestors map")
|
|| Self::is_candidate_slot_descendant_of_last_vote(*candidate_slot, last_voted_slot, ancestors).expect("exists in descendants map, so must exist in ancestors map")
|
||||||
|| *candidate_slot <= root
|
|| *candidate_slot <= root
|
||||||
{
|
{
|
||||||
@ -776,9 +778,30 @@ impl Tower {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if *candidate_latest_frozen_vote > last_voted_slot
|
if *candidate_latest_frozen_vote > last_voted_slot
|
||||||
&& !Self::is_candidate_slot_descendant_of_last_vote(
|
&&
|
||||||
|
// Because `candidate_latest_frozen_vote` is the last vote made by some validator
|
||||||
|
// in the cluster for a frozen bank `B` observed through gossip, we may have cleared
|
||||||
|
// that frozen bank `B` because we `set_root(root)` for a `root` on a different fork,
|
||||||
|
// like so:
|
||||||
|
//
|
||||||
|
// |----------X ------candidate_latest_frozen_vote (frozen)
|
||||||
|
// old root
|
||||||
|
// |----------new root ----last_voted_slot
|
||||||
|
//
|
||||||
|
// In most cases, because `last_voted_slot` must be a descendant of `root`, then
|
||||||
|
// if `candidate_latest_frozen_vote` is not found in the ancestors/descendants map (recall these
|
||||||
|
// directly reflect the state of BankForks), this implies that `B` was pruned from BankForks
|
||||||
|
// because it was on a different fork than `last_voted_slot`, and thus this vote for `candidate_latest_frozen_vote`
|
||||||
|
// should be safe to count towards the switching proof:
|
||||||
|
//
|
||||||
|
// However, there is also the possibility that `last_voted_slot` is a stray, in which
|
||||||
|
// case we cannot make this conclusion as we do not know the ancestors/descendants
|
||||||
|
// of strays. Hence we err on the side of caution here and ignore this vote. This
|
||||||
|
// is ok because validators voting on different unrooted forks should eventually vote
|
||||||
|
// on some descendant of the root, at which time they can be included in switching proofs.
|
||||||
|
!Self::is_candidate_slot_descendant_of_last_vote(
|
||||||
*candidate_latest_frozen_vote, last_voted_slot, ancestors)
|
*candidate_latest_frozen_vote, last_voted_slot, ancestors)
|
||||||
.expect("candidate_latest_frozen_vote is a frozen bank, so must exist in ancestors map") {
|
.unwrap_or(true) {
|
||||||
let stake = epoch_vote_accounts
|
let stake = epoch_vote_accounts
|
||||||
.get(vote_account_pubkey)
|
.get(vote_account_pubkey)
|
||||||
.map(|(stake, _)| *stake)
|
.map(|(stake, _)| *stake)
|
||||||
@ -1820,7 +1843,8 @@ pub mod test {
|
|||||||
/ (tr(44)
|
/ (tr(44)
|
||||||
// Minor fork 2
|
// Minor fork 2
|
||||||
/ (tr(45) / (tr(46) / (tr(47) / (tr(48) / (tr(49) / (tr(50)))))))
|
/ (tr(45) / (tr(46) / (tr(47) / (tr(48) / (tr(49) / (tr(50)))))))
|
||||||
/ (tr(110))))));
|
/ (tr(110)))
|
||||||
|
/ tr(112))));
|
||||||
|
|
||||||
// Fill the BankForks according to the above fork structure
|
// Fill the BankForks according to the above fork structure
|
||||||
vote_simulator.fill_bank_forks(forks, &HashMap::new());
|
vote_simulator.fill_bank_forks(forks, &HashMap::new());
|
||||||
@ -2124,18 +2148,19 @@ pub mod test {
|
|||||||
.latest_validator_votes_for_frozen_banks
|
.latest_validator_votes_for_frozen_banks
|
||||||
.check_add_vote(
|
.check_add_vote(
|
||||||
other_vote_account,
|
other_vote_account,
|
||||||
110,
|
112,
|
||||||
Some(
|
Some(
|
||||||
vote_simulator
|
vote_simulator
|
||||||
.bank_forks
|
.bank_forks
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get(110)
|
.get(112)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.hash(),
|
.hash(),
|
||||||
),
|
),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tower.check_switch_threshold(
|
tower.check_switch_threshold(
|
||||||
110,
|
110,
|
||||||
@ -2148,6 +2173,30 @@ pub mod test {
|
|||||||
),
|
),
|
||||||
SwitchForkDecision::SwitchProof(Hash::default())
|
SwitchForkDecision::SwitchProof(Hash::default())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If we now set a root that causes slot 112 to be purged from BankForks, then
|
||||||
|
// the switch proof will now fail since that validator's vote can no longer be
|
||||||
|
// included in the switching proof
|
||||||
|
vote_simulator.set_root(44);
|
||||||
|
let ancestors = vote_simulator.bank_forks.read().unwrap().ancestors();
|
||||||
|
let descendants = vote_simulator
|
||||||
|
.bank_forks
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.descendants()
|
||||||
|
.clone();
|
||||||
|
assert_eq!(
|
||||||
|
tower.check_switch_threshold(
|
||||||
|
110,
|
||||||
|
&ancestors,
|
||||||
|
&descendants,
|
||||||
|
&vote_simulator.progress,
|
||||||
|
total_stake,
|
||||||
|
bank0.epoch_vote_accounts(0).unwrap(),
|
||||||
|
&vote_simulator.latest_validator_votes_for_frozen_banks
|
||||||
|
),
|
||||||
|
SwitchForkDecision::FailedSwitchThreshold(0, 20000)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Reference in New Issue
Block a user