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

Commit 195f20a

Browse files
committed
Make test not fragile with improved arrangement
1 parent 2f25985 commit 195f20a

File tree

5 files changed

+71
-72
lines changed

5 files changed

+71
-72
lines changed

core/src/validator.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,6 @@ pub struct ValidatorConfig {
158158
pub validator_exit: Arc<RwLock<Exit>>,
159159
pub no_wait_for_vote_to_start_leader: bool,
160160
pub accounts_shrink_ratio: AccountShrinkThreshold,
161-
pub no_hard_fork_blockstore_root_reconcilation_for_local_cluster_test: bool,
162161
}
163162

164163
impl Default for ValidatorConfig {
@@ -218,7 +217,6 @@ impl Default for ValidatorConfig {
218217
no_wait_for_vote_to_start_leader: true,
219218
accounts_shrink_ratio: AccountShrinkThreshold::default(),
220219
accounts_db_config: None,
221-
no_hard_fork_blockstore_root_reconcilation_for_local_cluster_test: false,
222220
}
223221
}
224222
}
@@ -1292,20 +1290,18 @@ fn new_banks_from_ledger(
12921290
if let Some(hard_fork_restart_slot) =
12931291
maybe_cluster_restart_with_hard_fork(config, bank_forks.root_bank().slot())
12941292
{
1295-
if !config.no_hard_fork_blockstore_root_reconcilation_for_local_cluster_test {
1296-
reconcile_blockstore_roots_with_external_source(
1297-
ExternalRootSource::HardFork(hard_fork_restart_slot),
1298-
&blockstore,
1299-
&mut last_blockstore_root,
1300-
)
1301-
.unwrap_or_else(|err| {
1302-
error!(
1303-
"Failed to reconcile blockstore according to hard fork: {:?}",
1304-
err
1305-
);
1306-
abort()
1307-
});
1308-
}
1293+
reconcile_blockstore_roots_with_external_source(
1294+
ExternalRootSource::HardFork(hard_fork_restart_slot),
1295+
&blockstore,
1296+
&mut last_blockstore_root,
1297+
)
1298+
.unwrap_or_else(|err| {
1299+
error!(
1300+
"Failed to reconcile blockstore according to hard fork: {:?}",
1301+
err
1302+
);
1303+
abort()
1304+
});
13091305
}
13101306
let tower = post_process_restored_tower(
13111307
restored_tower,

ledger/src/blockstore.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,13 @@ impl Blockstore {
17401740
self.meta_cf.put_bytes(slot, bytes)
17411741
}
17421742

1743+
/// Manually update the meta for a slot.
1744+
/// Can interfere with automatic meta update and potentially break chaining.
1745+
/// Dangerous. Use with care.
1746+
pub fn put_meta(&self, slot: Slot, meta: &SlotMeta) -> Result<()> {
1747+
self.put_meta_bytes(slot, &bincode::serialize(meta)?)
1748+
}
1749+
17431750
// Given a start and end entry index, find all the missing
17441751
// indexes in the ledger in the range [start_index, end_index)
17451752
// for the slot with the specified slot

ledger/src/blockstore_meta.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,11 @@ impl SlotMeta {
187187
}
188188

189189
pub fn is_parent_set(&self) -> bool {
190-
self.parent_slot != std::u64::MAX
190+
self.parent_slot != Slot::MAX
191+
}
192+
193+
pub fn unset_parent(&mut self) {
194+
self.parent_slot = Slot::MAX;
191195
}
192196

193197
pub fn clear_unconfirmed_slot(&mut self) {

local-cluster/src/validator_configs.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ pub fn safe_clone_config(config: &ValidatorConfig) -> ValidatorConfig {
5959
no_wait_for_vote_to_start_leader: config.no_wait_for_vote_to_start_leader,
6060
accounts_shrink_ratio: config.accounts_shrink_ratio,
6161
accounts_db_config: config.accounts_db_config.clone(),
62-
no_hard_fork_blockstore_root_reconcilation_for_local_cluster_test: config
63-
.no_hard_fork_blockstore_root_reconcilation_for_local_cluster_test,
6462
}
6563
}
6664

local-cluster/tests/local_cluster.rs

Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3159,9 +3159,9 @@ fn open_blockstore(ledger_path: &Path) -> Blockstore {
31593159
})
31603160
}
31613161

3162-
fn purge_slots(blockstore: &Blockstore, start_slot: Slot, slot_count: Slot) {
3163-
blockstore.purge_from_next_slots(start_slot, start_slot + slot_count);
3164-
blockstore.purge_slots(start_slot, start_slot + slot_count, PurgeType::Exact);
3162+
fn purge_slots_with_count(blockstore: &Blockstore, start_slot: Slot, slot_count: Slot) {
3163+
blockstore.purge_from_next_slots(start_slot, start_slot + slot_count - 1);
3164+
blockstore.purge_slots(start_slot, start_slot + slot_count - 1, PurgeType::Exact);
31653165
}
31663166

31673167
fn copy_blocks(end_slot: Slot, source: &Blockstore, dest: &Blockstore) {
@@ -3358,7 +3358,7 @@ fn do_test_optimistic_confirmation_violation_with_or_without_tower(with_tower: b
33583358
remove_tower(&val_c_ledger_path, &validator_b_pubkey);
33593359

33603360
let blockstore = open_blockstore(&val_c_ledger_path);
3361-
purge_slots(&blockstore, base_slot + 1, truncated_slots);
3361+
purge_slots_with_count(&blockstore, base_slot + 1, truncated_slots);
33623362
}
33633363
info!("Create validator A's ledger");
33643364
{
@@ -3372,7 +3372,7 @@ fn do_test_optimistic_confirmation_violation_with_or_without_tower(with_tower: b
33723372
copy_blocks(b_last_vote, &b_blockstore, &a_blockstore);
33733373

33743374
// Purge uneccessary slots
3375-
purge_slots(&a_blockstore, next_slot_on_a + 1, truncated_slots);
3375+
purge_slots_with_count(&a_blockstore, next_slot_on_a + 1, truncated_slots);
33763376
}
33773377

33783378
// Step 3:
@@ -3404,7 +3404,7 @@ fn do_test_optimistic_confirmation_violation_with_or_without_tower(with_tower: b
34043404
let validator_a_info = cluster.exit_node(&validator_a_pubkey);
34053405
{
34063406
let blockstore = open_blockstore(&val_a_ledger_path);
3407-
purge_slots(&blockstore, next_slot_on_a + 1, truncated_slots);
3407+
purge_slots_with_count(&blockstore, next_slot_on_a + 1, truncated_slots);
34083408
if !with_tower {
34093409
info!("Removing tower!");
34103410
remove_tower(&val_a_ledger_path, &validator_a_pubkey);
@@ -3415,7 +3415,7 @@ fn do_test_optimistic_confirmation_violation_with_or_without_tower(with_tower: b
34153415
// validator C yet.
34163416
// Then it will be stuck on 27 unable to switch because C doesn't
34173417
// have enough stake to generate a switching proof
3418-
purge_slots(&blockstore, next_slot_on_a, truncated_slots);
3418+
purge_slots_with_count(&blockstore, next_slot_on_a, truncated_slots);
34193419
} else {
34203420
info!("Not removing tower!");
34213421
}
@@ -3563,7 +3563,7 @@ fn do_test_future_tower(cluster_mode: ClusterMode) {
35633563
purged_slot_before_restart,
35643564
);
35653565
let blockstore = open_blockstore(&val_a_ledger_path);
3566-
purge_slots(&blockstore, purged_slot_before_restart, 100);
3566+
purge_slots_with_count(&blockstore, purged_slot_before_restart, 100);
35673567
}
35683568

35693569
cluster.restart_node(
@@ -3794,25 +3794,25 @@ fn create_simple_snapshot_config(ledger_path: &Path) -> SnapshotConfig {
37943794
}
37953795
}
37963796

3797-
fn create_snapshot_to_hard_fork(ledger_path: &Path, snapshot_slot: Slot, hardforks: Vec<Slot>) {
3797+
fn create_snapshot_to_hard_fork(
3798+
blockstore: &Blockstore,
3799+
snapshot_slot: Slot,
3800+
hard_forks: Vec<Slot>,
3801+
) {
37983802
let process_options = ProcessOptions {
37993803
dev_halt_at_slot: Some(snapshot_slot),
3800-
new_hard_forks: Some(hardforks),
3804+
new_hard_forks: Some(hard_forks),
38013805
poh_verify: false,
38023806
..ProcessOptions::default()
38033807
};
3808+
let ledger_path = blockstore.ledger_path();
38043809
let genesis_config = open_genesis_config(ledger_path, u64::max_value());
3805-
let blockstore =
3806-
Blockstore::open_with_access_type(ledger_path, AccessType::PrimaryOnly, None, true)
3807-
.unwrap_or_else(|e| {
3808-
panic!("Failed to open ledger at {:?}, err: {}", ledger_path, e);
3809-
});
38103810
let snapshot_config = Some(create_simple_snapshot_config(ledger_path));
38113811
let (accounts_package_sender, _) = channel();
38123812
let (bank_forks, ..) = bank_forks_utils::load(
38133813
&genesis_config,
3814-
&blockstore,
3815-
vec![blockstore.ledger_path().join("accounts")],
3814+
blockstore,
3815+
vec![ledger_path.join("accounts")],
38163816
None,
38173817
snapshot_config.as_ref(),
38183818
process_options,
@@ -3840,7 +3840,9 @@ fn create_snapshot_to_hard_fork(ledger_path: &Path, snapshot_slot: Slot, hardfor
38403840
);
38413841
}
38423842

3843-
fn do_test_hard_fork_with_or_without_gap_in_roots(with_gap: bool) {
3843+
#[test]
3844+
#[serial]
3845+
fn test_hard_fork_with_gap_in_roots() {
38443846
solana_logger::setup_with_default(RUST_LOG_FILTER);
38453847

38463848
// First set up the cluster with 2 nodes
@@ -3865,7 +3867,6 @@ fn do_test_hard_fork_with_or_without_gap_in_roots(with_gap: bool) {
38653867

38663868
let validator_config = ValidatorConfig {
38673869
snapshot_config: Some(LocalCluster::create_dummy_load_only_snapshot_config()),
3868-
no_hard_fork_blockstore_root_reconcilation_for_local_cluster_test: with_gap,
38693870
..ValidatorConfig::default()
38703871
};
38713872
let mut config = ClusterConfig {
@@ -3915,7 +3916,23 @@ fn do_test_hard_fork_with_or_without_gap_in_roots(with_gap: bool) {
39153916

39163917
// create hard-forked snapshot only for validator a, emulating the manual cluster restart
39173918
// procedure with `solana-ledger-tool create-snapshot`
3918-
create_snapshot_to_hard_fork(&val_a_ledger_path, hard_fork_slot, vec![hard_fork_slot]);
3919+
let genesis_slot = 0;
3920+
{
3921+
let blockstore_a = Blockstore::open(&val_a_ledger_path).unwrap();
3922+
create_snapshot_to_hard_fork(&blockstore_a, hard_fork_slot, vec![hard_fork_slot]);
3923+
3924+
// Intentionally make solana-validator unbootable by replaying blocks from the genesis to
3925+
// ensure the hard-forked snapshot is used always. Otherwise, we couldn't create a gap
3926+
// in the ledger roots column family reliably.
3927+
// There was a bug which caused the hard-forked snapshot at an unrooted slot to forget
3928+
// to root some slots (thus, creating a gap in roots, which shouldn't happen).
3929+
purge_slots_with_count(&blockstore_a, genesis_slot, 1);
3930+
3931+
let next_slot = genesis_slot + 1;
3932+
let mut meta = blockstore_a.meta(next_slot).unwrap().unwrap();
3933+
meta.unset_parent();
3934+
blockstore_a.put_meta(next_slot, &meta).unwrap();
3935+
}
39193936

39203937
// strictly speaking, new_hard_forks isn't needed for validator a.
39213938
// but when snapshot loading isn't working, you might see:
@@ -3958,48 +3975,25 @@ fn do_test_hard_fork_with_or_without_gap_in_roots(with_gap: bool) {
39583975
let blockstore_a = Blockstore::open(&val_a_ledger_path).unwrap();
39593976
let blockstore_b = Blockstore::open(&val_b_ledger_path).unwrap();
39603977

3961-
// collect all slots
3962-
let slots_a = AncestorIterator::new(common_last_vote, &blockstore_a).collect::<Vec<_>>();
3963-
let roots_a = blockstore_a
3978+
// collect all slot/root parents
3979+
let mut slots_a = AncestorIterator::new(common_last_vote, &blockstore_a).collect::<Vec<_>>();
3980+
let mut roots_a = blockstore_a
39643981
.reversed_rooted_slot_iterator(common_root)
39653982
.unwrap()
39663983
.collect::<Vec<_>>();
3984+
// artifically restore the forcibly purged genesis only for the validator A just for the sake of
3985+
// following the final assertion.
3986+
slots_a.push(genesis_slot);
3987+
roots_a.push(genesis_slot);
3988+
39673989
let slots_b = AncestorIterator::new(common_last_vote, &blockstore_b).collect::<Vec<_>>();
39683990
let roots_b = blockstore_b
39693991
.reversed_rooted_slot_iterator(common_root)
39703992
.unwrap()
39713993
.collect::<Vec<_>>();
39723994

3973-
// compare all slots
3974-
if !with_gap {
3975-
assert_eq!((slots_a, roots_a), (slots_b, roots_b));
3976-
} else {
3977-
// rough way to detect a gap with mostly similar slots...
3978-
assert_eq!(
3979-
(slots_a.first().unwrap(), roots_a.first().unwrap()),
3980-
(slots_b.first().unwrap(), roots_b.first().unwrap())
3981-
);
3982-
assert_eq!(
3983-
(slots_a.last().unwrap(), roots_a.last().unwrap()),
3984-
(slots_b.last().unwrap(), roots_b.last().unwrap())
3985-
);
3986-
assert_ne!((slots_a, roots_a), (slots_b, roots_b));
3987-
}
3988-
}
3989-
3990-
// the following two tests are rather fragile, depending on successful loading of the hard-forked snapshot.
3991-
// so, make sure they aren't broken by testing (expected) failures as well with those conditioned
3992-
// two actual test code invocations.
3993-
#[test]
3994-
#[serial]
3995-
fn test_hard_fork_without_gap_in_roots() {
3996-
do_test_hard_fork_with_or_without_gap_in_roots(false);
3997-
}
3998-
3999-
#[test]
4000-
#[serial]
4001-
fn test_hard_fork_with_gap_in_roots() {
4002-
do_test_hard_fork_with_or_without_gap_in_roots(true);
3995+
// compare them all!
3996+
assert_eq!((slots_a, roots_a), (slots_b, roots_b));
40033997
}
40043998

40053999
fn run_test_load_program_accounts_partition(scan_commitment: CommitmentConfig) {

0 commit comments

Comments
 (0)