@@ -3928,14 +3928,13 @@ impl Blockstore {
39283928 . map ( |x| x. 0 )
39293929 }
39303930
3931- /// Returns the entry vector for the slot starting with `shred_start_index`, the number of
3932- /// shreds that comprise the entry vector, and whether the slot is full (consumed all shreds).
3933- pub fn get_slot_entries_with_shred_info (
3931+ /// Helper function that contains the common logic for getting slot data with shred info
3932+ fn get_slot_data_with_shred_info_common (
39343933 & self ,
39353934 slot : Slot ,
39363935 start_index : u64 ,
39373936 allow_dead_slots : bool ,
3938- ) -> Result < ( Vec < Entry > , u64 , bool ) > {
3937+ ) -> Result < ( CompletedRanges , SlotMeta , u64 ) > {
39393938 let ( completed_ranges, slot_meta) = self . get_completed_ranges ( slot, start_index) ?;
39403939
39413940 // Check if the slot is dead *after* fetching completed ranges to avoid a race
@@ -3945,7 +3944,7 @@ impl Blockstore {
39453944 if self . is_dead ( slot) && !allow_dead_slots {
39463945 return Err ( BlockstoreError :: DeadSlot ) ;
39473946 } else if completed_ranges. is_empty ( ) {
3948- return Ok ( ( vec ! [ ] , 0 , false ) ) ;
3947+ return Err ( BlockstoreError :: SlotUnavailable ) ;
39493948 }
39503949
39513950 let slot_meta = slot_meta. unwrap ( ) ;
@@ -3954,10 +3953,49 @@ impl Blockstore {
39543953 . map ( |& Range { end, .. } | u64:: from ( end) - start_index)
39553954 . unwrap_or ( 0 ) ;
39563955
3956+ Ok ( ( completed_ranges, slot_meta, num_shreds) )
3957+ }
3958+
3959+ /// Returns the entry vector for the slot starting with `shred_start_index`, the number of
3960+ /// shreds that comprise the entry vector, and whether the slot is full (consumed all shreds).
3961+ pub fn get_slot_entries_with_shred_info (
3962+ & self ,
3963+ slot : Slot ,
3964+ start_index : u64 ,
3965+ allow_dead_slots : bool ,
3966+ ) -> Result < ( Vec < Entry > , u64 , bool ) > {
3967+ let ( completed_ranges, slot_meta, num_shreds) =
3968+ match self . get_slot_data_with_shred_info_common ( slot, start_index, allow_dead_slots) {
3969+ Ok ( data) => data,
3970+ Err ( BlockstoreError :: SlotUnavailable ) => return Ok ( ( vec ! [ ] , 0 , false ) ) ,
3971+ Err ( e) => return Err ( e) ,
3972+ } ;
3973+
39573974 let entries = self . get_slot_entries_in_block ( slot, completed_ranges, Some ( & slot_meta) ) ?;
39583975 Ok ( ( entries, num_shreds, slot_meta. is_full ( ) ) )
39593976 }
39603977
3978+ /// Returns the components vector for the slot starting with `shred_start_index`, the number of
3979+ /// shreds that comprise the components vector, and whether the slot is full (consumed all
3980+ /// shreds).
3981+ pub fn get_slot_components_with_shred_info (
3982+ & self ,
3983+ slot : Slot ,
3984+ start_index : u64 ,
3985+ allow_dead_slots : bool ,
3986+ ) -> Result < ( Vec < BlockComponent > , u64 , bool ) > {
3987+ let ( completed_ranges, slot_meta, num_shreds) =
3988+ match self . get_slot_data_with_shred_info_common ( slot, start_index, allow_dead_slots) {
3989+ Ok ( data) => data,
3990+ Err ( BlockstoreError :: SlotUnavailable ) => return Ok ( ( vec ! [ ] , 0 , false ) ) ,
3991+ Err ( e) => return Err ( e) ,
3992+ } ;
3993+
3994+ let components =
3995+ self . get_slot_components_in_block ( slot, completed_ranges, Some ( & slot_meta) ) ?;
3996+ Ok ( ( components, num_shreds, slot_meta. is_full ( ) ) )
3997+ }
3998+
39613999 /// Gets accounts used in transactions in the slot range [starting_slot, ending_slot].
39624000 /// Additionally returns a bool indicating if the set may be incomplete.
39634001 /// Used by ledger-tool to create a minimized snapshot
@@ -4061,18 +4099,24 @@ impl Blockstore {
40614099 . collect ( )
40624100 }
40634101
4064- /// Fetch the entries corresponding to all of the shred indices in `completed_ranges`
4102+ /// Helper function to process shreds in `completed_ranges` and apply a transformation
4103+ /// to the resulting block components.
40654104 /// This function takes advantage of the fact that `completed_ranges` are both
40664105 /// contiguous and in sorted order. To clarify, suppose completed_ranges is as follows:
40674106 /// completed_ranges = [..., (s_i..e_i), (s_i+1..e_i+1), ...]
40684107 /// Then, the following statements are true:
40694108 /// s_i < e_i == s_i+1 < e_i+1
4070- fn get_slot_entries_in_block (
4109+ fn process_slot_data_in_block < T , I , F > (
40714110 & self ,
40724111 slot : Slot ,
40734112 completed_ranges : CompletedRanges ,
40744113 slot_meta : Option < & SlotMeta > ,
4075- ) -> Result < Vec < Entry > > {
4114+ transform : F ,
4115+ ) -> Result < Vec < T > >
4116+ where
4117+ I : IntoIterator < Item = T > ,
4118+ F : Fn ( Vec < BlockComponent > ) -> Result < I > ,
4119+ {
40764120 debug_assert ! ( completed_ranges
40774121 . iter( )
40784122 . tuple_windows( )
@@ -4118,26 +4162,60 @@ impl Blockstore {
41184162 . and_then ( |payload| {
41194163 // TODO(karthik): if Alpenglow flag is disabled, return an error on special
41204164 // EntryBatches.
4121- BlockComponent :: from_bytes_multiple ( & payload)
4122- . map ( |cs| {
4123- cs. into_iter ( )
4124- . filter_map ( |bc| bc. as_entry_batch_owned ( ) )
4125- . flatten ( )
4126- . collect_vec ( )
4127- } )
4128- . map_err ( |e| {
4165+ let components =
4166+ BlockComponent :: from_bytes_multiple ( & payload) . map_err ( |e| {
41294167 BlockstoreError :: InvalidShredData ( Box :: new (
41304168 bincode:: ErrorKind :: Custom ( format ! (
4131- "could not reconstruct entries : {e:?}"
4169+ "could not reconstruct block components : {e:?}"
41324170 ) ) ,
41334171 ) )
4134- } )
4172+ } ) ?;
4173+ transform ( components) . map_err ( |e| {
4174+ BlockstoreError :: InvalidShredData ( Box :: new ( bincode:: ErrorKind :: Custom (
4175+ format ! ( "could not transform block components: {e:?}" ) ,
4176+ ) ) )
4177+ } )
41354178 } )
41364179 } )
41374180 . flatten_ok ( )
41384181 . collect ( )
41394182 }
41404183
4184+ /// Fetch the components corresponding to all of the shred indices in `completed_ranges`
4185+ /// This function takes advantage of the fact that `completed_ranges` are both
4186+ /// contiguous and in sorted order. To clarify, suppose completed_ranges is as follows:
4187+ /// completed_ranges = [..., (s_i..e_i), (s_i+1..e_i+1), ...]
4188+ /// Then, the following statements are true:
4189+ /// s_i < e_i == s_i+1 < e_i+1
4190+ fn get_slot_components_in_block (
4191+ & self ,
4192+ slot : Slot ,
4193+ completed_ranges : CompletedRanges ,
4194+ slot_meta : Option < & SlotMeta > ,
4195+ ) -> Result < Vec < BlockComponent > > {
4196+ self . process_slot_data_in_block ( slot, completed_ranges, slot_meta, |cs| Ok ( cs. into_iter ( ) ) )
4197+ }
4198+
4199+ /// Fetch the entries corresponding to all of the shred indices in `completed_ranges`
4200+ /// This function takes advantage of the fact that `completed_ranges` are both
4201+ /// contiguous and in sorted order. To clarify, suppose completed_ranges is as follows:
4202+ /// completed_ranges = [..., (s_i..e_i), (s_i+1..e_i+1), ...]
4203+ /// Then, the following statements are true:
4204+ /// s_i < e_i == s_i+1 < e_i+1
4205+ fn get_slot_entries_in_block (
4206+ & self ,
4207+ slot : Slot ,
4208+ completed_ranges : CompletedRanges ,
4209+ slot_meta : Option < & SlotMeta > ,
4210+ ) -> Result < Vec < Entry > > {
4211+ self . process_slot_data_in_block ( slot, completed_ranges, slot_meta, |cs| {
4212+ Ok ( cs
4213+ . into_iter ( )
4214+ . filter_map ( |bc| bc. as_entry_batch_owned ( ) )
4215+ . flatten ( ) )
4216+ } )
4217+ }
4218+
41414219 pub fn get_entries_in_data_block (
41424220 & self ,
41434221 slot : Slot ,
0 commit comments