@@ -1159,25 +1159,36 @@ impl StorageManager for DiskStorageManager {
11591159 async fn load_headers ( & self , range : Range < u32 > ) -> StorageResult < Vec < BlockHeader > > {
11601160 let mut headers = Vec :: new ( ) ;
11611161
1162- let start_segment = Self :: get_segment_id ( range. start ) ;
1163- let end_segment = Self :: get_segment_id ( range. end . saturating_sub ( 1 ) ) ;
1162+ // Convert blockchain height range to storage index range using sync_base_height
1163+ let sync_base_height = * self . sync_base_height . read ( ) . await ;
1164+ let storage_start = if sync_base_height > 0 && range. start >= sync_base_height {
1165+ range. start - sync_base_height
1166+ } else {
1167+ range. start
1168+ } ;
1169+
1170+ let storage_end = if sync_base_height > 0 && range. end > sync_base_height {
1171+ range. end - sync_base_height
1172+ } else {
1173+ range. end
1174+ } ;
1175+
1176+ let start_segment = Self :: get_segment_id ( storage_start) ;
1177+ let end_segment = Self :: get_segment_id ( storage_end. saturating_sub ( 1 ) ) ;
11641178
11651179 for segment_id in start_segment..=end_segment {
11661180 self . ensure_segment_loaded ( segment_id) . await ?;
11671181
11681182 let segments = self . active_segments . read ( ) . await ;
11691183 if let Some ( segment) = segments. get ( & segment_id) {
1170- let _segment_start_height = segment_id * HEADERS_PER_SEGMENT ;
1171- let _segment_end_height = _segment_start_height + segment. headers . len ( ) as u32 ;
1172-
11731184 let start_idx = if segment_id == start_segment {
1174- Self :: get_segment_offset ( range . start )
1185+ Self :: get_segment_offset ( storage_start )
11751186 } else {
11761187 0
11771188 } ;
11781189
11791190 let end_idx = if segment_id == end_segment {
1180- Self :: get_segment_offset ( range . end . saturating_sub ( 1 ) ) + 1
1191+ Self :: get_segment_offset ( storage_end . saturating_sub ( 1 ) ) + 1
11811192 } else {
11821193 segment. headers . len ( )
11831194 } ;
@@ -1198,17 +1209,31 @@ impl StorageManager for DiskStorageManager {
11981209 }
11991210
12001211 async fn get_header ( & self , height : u32 ) -> StorageResult < Option < BlockHeader > > {
1201- // TODO: This method currently expects storage-relative heights (0-based from sync_base_height) .
1202- // Consider refactoring to accept blockchain heights and handle conversion internally for better UX.
1212+ // Accept blockchain (absolute) height and convert to storage index using sync_base_height.
1213+ let sync_base_height = * self . sync_base_height . read ( ) . await ;
12031214
1204- // First check if this height is within our known range
1205- let tip_height = self . cached_tip_height . read ( ) . await ;
1206- if let Some ( tip) = * tip_height {
1207- if height > tip {
1215+ // Convert absolute height to storage index (base-inclusive mapping)
1216+ let storage_index = if sync_base_height > 0 {
1217+ if height >= sync_base_height {
1218+ height - sync_base_height
1219+ } else {
1220+ // If caller passes a small value (likely a pre-conversion storage index), use it directly
1221+ height
1222+ }
1223+ } else {
1224+ height
1225+ } ;
1226+
1227+ // First check if this storage index is within our known range
1228+ let tip_index_opt = * self . cached_tip_height . read ( ) . await ;
1229+ if let Some ( tip_index) = tip_index_opt {
1230+ if storage_index > tip_index {
12081231 tracing:: trace!(
1209- "Requested header at height {} is beyond tip height {}" ,
1232+ "Requested header at storage index {} is beyond tip index {} (abs height {} base {})" ,
1233+ storage_index,
1234+ tip_index,
12101235 height,
1211- tip
1236+ sync_base_height
12121237 ) ;
12131238 return Ok ( None ) ;
12141239 }
@@ -1217,8 +1242,8 @@ impl StorageManager for DiskStorageManager {
12171242 return Ok ( None ) ;
12181243 }
12191244
1220- let segment_id = Self :: get_segment_id ( height ) ;
1221- let offset = Self :: get_segment_offset ( height ) ;
1245+ let segment_id = Self :: get_segment_id ( storage_index ) ;
1246+ let offset = Self :: get_segment_offset ( storage_index ) ;
12221247
12231248 self . ensure_segment_loaded ( segment_id) . await ?;
12241249
@@ -1235,18 +1260,30 @@ impl StorageManager for DiskStorageManager {
12351260
12361261 if header. is_none ( ) {
12371262 tracing:: debug!(
1238- "Header not found at height {} (segment: {}, offset: {})" ,
1239- height ,
1263+ "Header not found at storage index {} (segment: {}, offset: {}, abs height {}, base {})" ,
1264+ storage_index ,
12401265 segment_id,
1241- offset
1266+ offset,
1267+ height,
1268+ sync_base_height
12421269 ) ;
12431270 }
12441271
12451272 Ok ( header)
12461273 }
12471274
12481275 async fn get_tip_height ( & self ) -> StorageResult < Option < u32 > > {
1249- Ok ( * self . cached_tip_height . read ( ) . await )
1276+ let tip_index_opt = * self . cached_tip_height . read ( ) . await ;
1277+ if let Some ( tip_index) = tip_index_opt {
1278+ let base = * self . sync_base_height . read ( ) . await ;
1279+ if base > 0 {
1280+ Ok ( Some ( base + tip_index) )
1281+ } else {
1282+ Ok ( Some ( tip_index) )
1283+ }
1284+ } else {
1285+ Ok ( None )
1286+ }
12501287 }
12511288
12521289 async fn store_filter_headers ( & mut self , headers : & [ FilterHeader ] ) -> StorageResult < ( ) > {
@@ -1487,7 +1524,12 @@ impl StorageManager for DiskStorageManager {
14871524
14881525 // Load all headers
14891526 if let Some ( tip_height) = self . get_tip_height ( ) . await ? {
1490- state. headers = self . load_headers ( 0 ..tip_height + 1 ) . await ?;
1527+ let range_start = if state. synced_from_checkpoint && state. sync_base_height > 0 {
1528+ state. sync_base_height
1529+ } else {
1530+ 0
1531+ } ;
1532+ state. headers = self . load_headers ( range_start..tip_height + 1 ) . await ?;
14911533 }
14921534
14931535 // Load all filter headers
@@ -2032,16 +2074,22 @@ mod tests {
20322074 // Store headers using checkpoint sync method
20332075 storage. store_headers_from_height ( & headers, checkpoint_height) . await ?;
20342076
2035- // Verify headers are stored at correct storage indices
2036- // Header at blockchain height 1,100,000 should be at storage index 0
2037- let header_at_0 = storage. get_header ( 0 ) . await ?;
2038- assert ! ( header_at_0. is_some( ) , "Header at storage index 0 should exist" ) ;
2039- assert_eq ! ( header_at_0. unwrap( ) , headers[ 0 ] ) ;
2077+ // Set sync base height so storage interprets heights as blockchain heights
2078+ let mut base_state = ChainState :: new ( ) ;
2079+ base_state. sync_base_height = checkpoint_height;
2080+ base_state. synced_from_checkpoint = true ;
2081+ storage. store_chain_state ( & base_state) . await ?;
2082+
2083+ // Verify headers are stored at correct blockchain heights
2084+ // Header at blockchain height 1,100,000 should be retrievable by that height
2085+ let header_at_base = storage. get_header ( checkpoint_height) . await ?;
2086+ assert ! ( header_at_base. is_some( ) , "Header at base blockchain height should exist" ) ;
2087+ assert_eq ! ( header_at_base. unwrap( ) , headers[ 0 ] ) ;
20402088
2041- // Header at blockchain height 1,100,099 should be at storage index 99
2042- let header_at_99 = storage. get_header ( 99 ) . await ?;
2043- assert ! ( header_at_99 . is_some( ) , "Header at storage index 99 should exist" ) ;
2044- assert_eq ! ( header_at_99 . unwrap( ) , headers[ 99 ] ) ;
2089+ // Header at blockchain height 1,100,099 should be retrievable by that height
2090+ let header_at_ending = storage. get_header ( checkpoint_height + 99 ) . await ?;
2091+ assert ! ( header_at_ending . is_some( ) , "Header at ending blockchain height should exist" ) ;
2092+ assert_eq ! ( header_at_ending . unwrap( ) , headers[ 99 ] ) ;
20452093
20462094 // Test the reverse index (hash -> blockchain height)
20472095 let hash_0 = headers[ 0 ] . block_hash ( ) ;
@@ -2081,11 +2129,11 @@ mod tests {
20812129 "After index rebuild, hash should still map to blockchain height 1,100,000"
20822130 ) ;
20832131
2084- // Verify headers can still be retrieved by storage index
2085- let header_after_reload = storage2. get_header ( 0 ) . await ?;
2132+ // Verify header can still be retrieved by blockchain height after reload
2133+ let header_after_reload = storage2. get_header ( checkpoint_height ) . await ?;
20862134 assert ! (
20872135 header_after_reload. is_some( ) ,
2088- "Header at storage index 0 should exist after reload"
2136+ "Header at base blockchain height should exist after reload"
20892137 ) ;
20902138 assert_eq ! ( header_after_reload. unwrap( ) , headers[ 0 ] ) ;
20912139
0 commit comments