@@ -3159,9 +3159,9 @@ fn open_blockstore(ledger_path: &Path) -> Blockstore {
3159
3159
} )
3160
3160
}
3161
3161
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 ) ;
3165
3165
}
3166
3166
3167
3167
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
3358
3358
remove_tower ( & val_c_ledger_path, & validator_b_pubkey) ;
3359
3359
3360
3360
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) ;
3362
3362
}
3363
3363
info ! ( "Create validator A's ledger" ) ;
3364
3364
{
@@ -3372,7 +3372,7 @@ fn do_test_optimistic_confirmation_violation_with_or_without_tower(with_tower: b
3372
3372
copy_blocks ( b_last_vote, & b_blockstore, & a_blockstore) ;
3373
3373
3374
3374
// 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) ;
3376
3376
}
3377
3377
3378
3378
// Step 3:
@@ -3404,7 +3404,7 @@ fn do_test_optimistic_confirmation_violation_with_or_without_tower(with_tower: b
3404
3404
let validator_a_info = cluster. exit_node ( & validator_a_pubkey) ;
3405
3405
{
3406
3406
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) ;
3408
3408
if !with_tower {
3409
3409
info ! ( "Removing tower!" ) ;
3410
3410
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
3415
3415
// validator C yet.
3416
3416
// Then it will be stuck on 27 unable to switch because C doesn't
3417
3417
// 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) ;
3419
3419
} else {
3420
3420
info ! ( "Not removing tower!" ) ;
3421
3421
}
@@ -3563,7 +3563,7 @@ fn do_test_future_tower(cluster_mode: ClusterMode) {
3563
3563
purged_slot_before_restart,
3564
3564
) ;
3565
3565
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 ) ;
3567
3567
}
3568
3568
3569
3569
cluster. restart_node (
@@ -3794,25 +3794,25 @@ fn create_simple_snapshot_config(ledger_path: &Path) -> SnapshotConfig {
3794
3794
}
3795
3795
}
3796
3796
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
+ ) {
3798
3802
let process_options = ProcessOptions {
3799
3803
dev_halt_at_slot : Some ( snapshot_slot) ,
3800
- new_hard_forks : Some ( hardforks ) ,
3804
+ new_hard_forks : Some ( hard_forks ) ,
3801
3805
poh_verify : false ,
3802
3806
..ProcessOptions :: default ( )
3803
3807
} ;
3808
+ let ledger_path = blockstore. ledger_path ( ) ;
3804
3809
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
- } ) ;
3810
3810
let snapshot_config = Some ( create_simple_snapshot_config ( ledger_path) ) ;
3811
3811
let ( accounts_package_sender, _) = channel ( ) ;
3812
3812
let ( bank_forks, ..) = bank_forks_utils:: load (
3813
3813
& genesis_config,
3814
- & blockstore,
3815
- vec ! [ blockstore . ledger_path( ) . join( "accounts" ) ] ,
3814
+ blockstore,
3815
+ vec ! [ ledger_path. join( "accounts" ) ] ,
3816
3816
None ,
3817
3817
snapshot_config. as_ref ( ) ,
3818
3818
process_options,
@@ -3840,7 +3840,9 @@ fn create_snapshot_to_hard_fork(ledger_path: &Path, snapshot_slot: Slot, hardfor
3840
3840
) ;
3841
3841
}
3842
3842
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 ( ) {
3844
3846
solana_logger:: setup_with_default ( RUST_LOG_FILTER ) ;
3845
3847
3846
3848
// 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) {
3865
3867
3866
3868
let validator_config = ValidatorConfig {
3867
3869
snapshot_config : Some ( LocalCluster :: create_dummy_load_only_snapshot_config ( ) ) ,
3868
- no_hard_fork_blockstore_root_reconcilation_for_local_cluster_test : with_gap,
3869
3870
..ValidatorConfig :: default ( )
3870
3871
} ;
3871
3872
let mut config = ClusterConfig {
@@ -3915,7 +3916,23 @@ fn do_test_hard_fork_with_or_without_gap_in_roots(with_gap: bool) {
3915
3916
3916
3917
// create hard-forked snapshot only for validator a, emulating the manual cluster restart
3917
3918
// 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
+ }
3919
3936
3920
3937
// strictly speaking, new_hard_forks isn't needed for validator a.
3921
3938
// 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) {
3958
3975
let blockstore_a = Blockstore :: open ( & val_a_ledger_path) . unwrap ( ) ;
3959
3976
let blockstore_b = Blockstore :: open ( & val_b_ledger_path) . unwrap ( ) ;
3960
3977
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
3964
3981
. reversed_rooted_slot_iterator ( common_root)
3965
3982
. unwrap ( )
3966
3983
. 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
+
3967
3989
let slots_b = AncestorIterator :: new ( common_last_vote, & blockstore_b) . collect :: < Vec < _ > > ( ) ;
3968
3990
let roots_b = blockstore_b
3969
3991
. reversed_rooted_slot_iterator ( common_root)
3970
3992
. unwrap ( )
3971
3993
. collect :: < Vec < _ > > ( ) ;
3972
3994
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) ) ;
4003
3997
}
4004
3998
4005
3999
fn run_test_load_program_accounts_partition ( scan_commitment : CommitmentConfig ) {
0 commit comments