Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit aed865a

Browse files
committed
Reflow the adjust tower fn code path and new tests
1 parent 94e8d66 commit aed865a

File tree

2 files changed

+65
-26
lines changed

2 files changed

+65
-26
lines changed

core/src/consensus.rs

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -569,22 +569,18 @@ impl Tower {
569569
return SwitchForkDecision::SameFork;
570570
}
571571

572-
// Generally, should never consider switching to an ancestor of your last vote
573572
if last_vote_ancestors.contains(&switch_slot) {
574-
let restored_stray_exception = self.is_stray_last_vote() && switch_slot < last_voted_slot;
575-
if !restored_stray_exception {
573+
if !self.is_stray_last_vote() {
576574
panic!(
577575
"Should never consider switching to slot ({}), which is ancestors({:?}) of last vote: {}",
578576
switch_slot,
579577
last_vote_ancestors,
580578
last_voted_slot
581579
);
582580
} else {
583-
// If last vote is stray, it's possible to reach here, because we don't have complete view of voting history.
584-
// In that case, pretend we're always failing to switch, regarless switch_slot is actually on same frok or not.
585-
// this is for safety; otherwise we accidentally might doubl#e-vte on ancestors.
586-
// siwtch_slot must be `< last_voted_slot` because switch_slot must be one of last_vote_ancestors in this if clause.
587-
return SwitchForkDecision::FailedSwitchThreshold(0, 1);
581+
// If last vote is stray, it's possible to reach here, because bank fork might not have the slot which (???)
582+
// lockout check should prevent double vote and slashing.
583+
return SwitchForkDecision::SameFork;
588584
}
589585
}
590586

@@ -857,14 +853,9 @@ impl Tower {
857853
);
858854
assert_eq!(slot_history.check(replayed_root), Check::Found);
859855

860-
// reconcile_blockstore_roots_with_tower() should already have aligned these.
861-
assert!(
862-
tower_root <= replayed_root,
863-
format!(
864-
"tower root: {:?} >= replayed root slot: {}",
865-
tower_root, replayed_root
866-
)
867-
);
856+
if tower_root > replayed_root {
857+
return Err(TowerError::TooOldBlockstore(tower_root, replayed_root));
858+
}
868859
assert!(
869860
self.last_vote == Vote::default() && self.lockouts.votes.is_empty()
870861
|| self.last_vote != Vote::default() && !self.lockouts.votes.is_empty(),
@@ -1126,6 +1117,12 @@ pub enum TowerError {
11261117
)]
11271118
TooOldTower(Slot, Slot),
11281119

1120+
#[error(
1121+
"The blockstore is too old: \
1122+
root in tower ({0}) > root in blockstore ({1})"
1123+
)]
1124+
TooOldBlockstore(Slot, Slot),
1125+
11291126
#[error("The tower is fatally inconsistent with blockstore: {0}")]
11301127
FatallyInconsistent(&'static str),
11311128
}
@@ -1184,14 +1181,24 @@ pub fn reconcile_blockstore_roots_with_tower(
11841181
),
11851182
})
11861183
.collect();
1187-
// adjust this assertion as well; this can be triggered by being empty if tower is moved to new ledger
1188-
// which has older max slot.
1189-
assert!(
1190-
!new_roots.is_empty(),
1191-
"at least 1 parent slot must be found"
1192-
);
1193-
1194-
blockstore.set_roots(&new_roots)?;
1184+
if !new_roots.is_empty() {
1185+
info!(
1186+
"marking slots as root based on tower root: {:?} ({}..{}) ",
1187+
new_roots, tower_root, last_blockstore_root
1188+
);
1189+
blockstore.set_roots(&new_roots)?;
1190+
} else {
1191+
// This indicates we're in bad state; but still don't panic here.
1192+
// That's because we might have a chance of recovering properly with
1193+
// newer snapshot. Ultimately TooOldBlockstore should handle
1194+
// this bad condition.
1195+
warn!(
1196+
"Couldn't find any ancestor slots from tower root ({}) \
1197+
towards ({}) in blockstore; blockstore pruned or only \
1198+
tower moved?",
1199+
tower_root, last_blockstore_root,
1200+
);
1201+
}
11951202
}
11961203
Ok(())
11971204
}
@@ -2713,8 +2720,7 @@ pub mod test {
27132720
}
27142721

27152722
#[test]
2716-
#[should_panic(expected = "at least 1 parent slot must be found")]
2717-
fn test_reconcile_blockstore_roots_with_tower_panic_no_parent() {
2723+
fn test_reconcile_blockstore_roots_with_tower_nop_no_parent() {
27182724
solana_logger::setup();
27192725
let blockstore_path = get_tmp_ledger_path!();
27202726
{
@@ -2730,7 +2736,9 @@ pub mod test {
27302736

27312737
let mut tower = Tower::new_with_key(&Pubkey::default());
27322738
tower.lockouts.root_slot = Some(4);
2739+
assert_eq!(blockstore.last_root(), 0);
27332740
reconcile_blockstore_roots_with_tower(&tower, &blockstore).unwrap();
2741+
assert_eq!(blockstore.last_root(), 0);
27342742
}
27352743
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
27362744
}
@@ -3052,6 +3060,23 @@ pub mod test {
30523060
.unwrap();
30533061
}
30543062

3063+
#[test]
3064+
fn test_adjust_lockouts_after_replay_vote_on_root() {
3065+
let mut tower = Tower::new_for_tests(10, 0.9);
3066+
tower.lockouts.root_slot = Some(42);
3067+
tower.lockouts.votes.push_back(Lockout::new(42));
3068+
tower.lockouts.votes.push_back(Lockout::new(43));
3069+
tower.lockouts.votes.push_back(Lockout::new(44));
3070+
let vote = Vote::new(vec![44], Hash::default());
3071+
tower.last_vote = vote;
3072+
3073+
let mut slot_history = SlotHistory::default();
3074+
slot_history.add(42);
3075+
3076+
let tower = tower.adjust_lockouts_after_replay(42, &slot_history);
3077+
assert_eq!(tower.unwrap().voted_slots(), [43, 44]);
3078+
}
3079+
30553080
#[test]
30563081
fn test_adjust_lockouts_after_replay_vote_on_genesis() {
30573082
let mut tower = Tower::new_for_tests(10, 0.9);

core/src/validator.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,20 @@ fn post_process_restored_tower(
746746
"And there is an existing vote_account containing actual votes. \
747747
Aborting due to possible conflicting duplicate votes",
748748
);
749+
if let crate::consensus::TowerError::TooOldBlockstore(tower_root, _) = err {
750+
error!(
751+
"This error indicates there had been an unexpeted manipulation to \
752+
the ledger causing severe inconsistency between blockstore and tower.",
753+
);
754+
error!(
755+
"Please restore rocksdb/tower if you modified/copied/moved those files or \
756+
use snapshot (newer than {}) fetched from the cluster by running without \
757+
--no-snapshot-fertch or populate missing data in blockstore by running \
758+
with --no-voting and without --identity and --vote-account until rooting {}.",
759+
tower_root,
760+
tower_root,
761+
);
762+
}
749763
process::exit(1);
750764
}
751765
if err.is_file_missing() && !voting_has_been_active {

0 commit comments

Comments
 (0)