@@ -17,6 +17,7 @@ pub struct MemoryStorageManager {
1717 filters : HashMap < u32 , Vec < u8 > > ,
1818 masternode_state : Option < MasternodeState > ,
1919 chain_state : Option < ChainState > ,
20+ sync_state : Option < crate :: storage:: PersistentSyncState > ,
2021 metadata : HashMap < String , Vec < u8 > > ,
2122 // Reverse indexes for O(1) lookups
2223 header_hash_index : HashMap < BlockHash , u32 > ,
@@ -34,12 +35,19 @@ impl MemoryStorageManager {
3435 filters : HashMap :: new ( ) ,
3536 masternode_state : None ,
3637 chain_state : None ,
38+ sync_state : None ,
3739 metadata : HashMap :: new ( ) ,
3840 header_hash_index : HashMap :: new ( ) ,
3941 mempool_transactions : HashMap :: new ( ) ,
4042 mempool_state : None ,
4143 } )
4244 }
45+ pub fn sync_base_height ( & self ) -> u32 {
46+ match self . chain_state . as_ref ( ) {
47+ Some ( state) => state. sync_base_height ,
48+ None => 0 ,
49+ }
50+ }
4351}
4452
4553#[ async_trait]
@@ -59,15 +67,7 @@ impl StorageManager for MemoryStorageManager {
5967 // Determine absolute height offset (for checkpoint-based sync) once per batch
6068 // If syncing from a checkpoint, storage index 0 corresponds to absolute height
6169 // sync_base_height (base-inclusive). Otherwise, absolute height equals storage index.
62- let ( sync_base_height, synced_from_checkpoint) = match self . load_sync_state ( ) . await {
63- Ok ( Some ( state) ) => ( state. sync_base_height , state. synced_from_checkpoint ) ,
64- _ => ( 0u32 , false ) ,
65- } ;
66- let abs_offset: u32 = if synced_from_checkpoint && sync_base_height > 0 {
67- sync_base_height
68- } else {
69- 0
70- } ;
70+ let sync_base_height = self . sync_base_height ( ) ;
7171
7272 for header in headers {
7373 let storage_index = self . headers . len ( ) as u32 ;
@@ -76,7 +76,7 @@ impl StorageManager for MemoryStorageManager {
7676 // Check if we already have this header
7777 if self . header_hash_index . contains_key ( & block_hash) {
7878 let existing_index = self . header_hash_index . get ( & block_hash) . copied ( ) ;
79- let existing_abs = existing_index. map ( |i| i. saturating_add ( abs_offset ) ) ;
79+ let existing_abs = existing_index. map ( |i| i. saturating_add ( sync_base_height ) ) ;
8080 tracing:: warn!(
8181 "MemoryStorage: header {} already exists at storage_index {:?} (abs height {:?}), skipping" ,
8282 block_hash,
@@ -92,7 +92,7 @@ impl StorageManager for MemoryStorageManager {
9292 // Update the reverse index
9393 self . header_hash_index . insert ( block_hash, storage_index) ;
9494
95- let abs_height = storage_index. saturating_add ( abs_offset ) ;
95+ let abs_height = storage_index. saturating_add ( sync_base_height ) ;
9696 tracing:: debug!(
9797 "MemoryStorage: stored header {} at storage_index {} (abs height {})" ,
9898 block_hash,
@@ -112,37 +112,11 @@ impl StorageManager for MemoryStorageManager {
112112
113113 async fn load_headers ( & self , range : Range < u32 > ) -> StorageResult < Vec < BlockHeader > > {
114114 // Interpret range as blockchain (absolute) heights and map to storage indices
115- let ( base, has_base) = match self . load_sync_state ( ) . await {
116- Ok ( Some ( state) ) if state. synced_from_checkpoint && state. sync_base_height > 0 => {
117- ( state. sync_base_height , true )
118- }
119- _ => ( 0u32 , false ) ,
120- } ;
115+ let sync_base_height = self . sync_base_height ( ) ;
116+ let start_idx = range. start . saturating_sub ( sync_base_height) as usize ;
121117
122- let start_idx = if has_base {
123- if range. start < base {
124- 0usize
125- } else {
126- ( range. start - base) as usize
127- }
128- } else {
129- range. start as usize
130- } ;
131-
132- let end_abs = range. end . min ( if has_base {
133- base + self . headers . len ( ) as u32
134- } else {
135- self . headers . len ( ) as u32
136- } ) ;
137- let end_idx = if has_base {
138- if end_abs <= base {
139- 0usize
140- } else {
141- ( end_abs - base) as usize
142- }
143- } else {
144- end_abs as usize
145- } ;
118+ let end_abs = range. end . min ( sync_base_height + self . headers . len ( ) as u32 ) ;
119+ let end_idx = end_abs. saturating_sub ( sync_base_height) as usize ;
146120
147121 if start_idx > self . headers . len ( ) {
148122 return Ok ( Vec :: new ( ) ) ;
@@ -152,32 +126,18 @@ impl StorageManager for MemoryStorageManager {
152126 }
153127
154128 async fn get_header ( & self , height : u32 ) -> StorageResult < Option < BlockHeader > > {
155- let sync_base_height = match self . load_sync_state ( ) . await {
156- Ok ( Some ( state) ) if state. synced_from_checkpoint && state. sync_base_height > 0 => {
157- state. sync_base_height
158- }
159- _ => 0u32 ,
160- } ;
161- if sync_base_height > 0 && height < sync_base_height {
162- return Ok ( None ) ;
163- }
164-
165129 // Convert absolute height to storage index (base-inclusive mapping)
166- let idx = height. saturating_sub ( sync_base_height) as usize ;
167- Ok ( self . headers . get ( idx) . copied ( ) )
130+ let Some ( idx) = height. checked_sub ( self . sync_base_height ( ) ) else {
131+ return Ok ( None ) ;
132+ } ;
133+ Ok ( self . headers . get ( idx as usize ) . copied ( ) )
168134 }
169135
170136 async fn get_tip_height ( & self ) -> StorageResult < Option < u32 > > {
171137 if self . headers . is_empty ( ) {
172138 return Ok ( None ) ;
173139 }
174- let base = match self . load_sync_state ( ) . await {
175- Ok ( Some ( state) ) if state. synced_from_checkpoint && state. sync_base_height > 0 => {
176- state. sync_base_height
177- }
178- _ => 0u32 ,
179- } ;
180- Ok ( Some ( base + self . headers . len ( ) as u32 - 1 ) )
140+ Ok ( Some ( self . sync_base_height ( ) + self . headers . len ( ) as u32 - 1 ) )
181141 }
182142
183143 async fn store_filter_headers ( & mut self , headers : & [ FilterHeader ] ) -> StorageResult < ( ) > {
@@ -189,38 +149,11 @@ impl StorageManager for MemoryStorageManager {
189149
190150 async fn load_filter_headers ( & self , range : Range < u32 > ) -> StorageResult < Vec < FilterHeader > > {
191151 // Interpret range as blockchain (absolute) heights and map to storage indices
192- let ( base, has_base) = match self . load_sync_state ( ) . await {
193- Ok ( Some ( state) ) if state. synced_from_checkpoint && state. sync_base_height > 0 => {
194- ( state. sync_base_height , true )
195- }
196- _ => ( 0u32 , false ) ,
197- } ;
152+ let sync_base_height = self . sync_base_height ( ) ;
153+ let start_idx = range. start . saturating_sub ( sync_base_height) as usize ;
198154
199- let start_idx = if has_base {
200- if range. start < base {
201- 0usize
202- } else {
203- ( range. start - base) as usize
204- }
205- } else {
206- range. start as usize
207- } ;
208-
209- let end_abs = range. end . min ( if has_base {
210- base + self . filter_headers . len ( ) as u32
211- } else {
212- self . filter_headers . len ( ) as u32
213- } ) ;
214-
215- let end_idx = if has_base {
216- if end_abs <= base {
217- 0usize
218- } else {
219- ( end_abs - base) as usize
220- }
221- } else {
222- end_abs as usize
223- } ;
155+ let end_abs = range. end . min ( sync_base_height + self . filter_headers . len ( ) as u32 ) ;
156+ let end_idx = end_abs. saturating_sub ( sync_base_height) as usize ;
224157
225158 if start_idx > self . filter_headers . len ( ) {
226159 return Ok ( Vec :: new ( ) ) ;
@@ -232,14 +165,7 @@ impl StorageManager for MemoryStorageManager {
232165
233166 async fn get_filter_header ( & self , height : u32 ) -> StorageResult < Option < FilterHeader > > {
234167 // Map blockchain (absolute) height to storage index relative to checkpoint base
235- let base = match self . load_sync_state ( ) . await {
236- Ok ( Some ( state) ) if state. synced_from_checkpoint && state. sync_base_height > 0 => {
237- state. sync_base_height
238- }
239- _ => 0u32 ,
240- } ;
241-
242- let idx = height. saturating_sub ( base) as usize ;
168+ let idx = height. saturating_sub ( self . sync_base_height ( ) ) as usize ;
243169 Ok ( self . filter_headers . get ( idx) . copied ( ) )
244170 }
245171
@@ -248,13 +174,7 @@ impl StorageManager for MemoryStorageManager {
248174 Ok ( None )
249175 } else {
250176 // Return blockchain (absolute) height for the tip, accounting for checkpoint base
251- let base = match self . load_sync_state ( ) . await {
252- Ok ( Some ( state) ) if state. synced_from_checkpoint && state. sync_base_height > 0 => {
253- state. sync_base_height
254- }
255- _ => 0u32 ,
256- } ;
257- Ok ( Some ( base + self . filter_headers . len ( ) as u32 - 1 ) )
177+ Ok ( Some ( self . sync_base_height ( ) + self . filter_headers . len ( ) as u32 - 1 ) )
258178 }
259179 }
260180
@@ -300,6 +220,7 @@ impl StorageManager for MemoryStorageManager {
300220 self . filters . clear ( ) ;
301221 self . masternode_state = None ;
302222 self . chain_state = None ;
223+ self . sync_state = None ;
303224 self . metadata . clear ( ) ;
304225 self . header_hash_index . clear ( ) ;
305226 self . mempool_transactions . clear ( ) ;
@@ -383,14 +304,7 @@ impl StorageManager for MemoryStorageManager {
383304 None => return Ok ( None ) ,
384305 } ;
385306
386- let base = match self . load_sync_state ( ) . await {
387- Ok ( Some ( state) ) if state. synced_from_checkpoint && state. sync_base_height > 0 => {
388- state. sync_base_height
389- }
390- _ => 0u32 ,
391- } ;
392-
393- Ok ( Some ( base + storage_index) )
307+ Ok ( Some ( self . sync_base_height ( ) + storage_index) )
394308 }
395309
396310 async fn get_headers_batch (
@@ -403,24 +317,14 @@ impl StorageManager for MemoryStorageManager {
403317 }
404318
405319 // Map absolute heights to storage indices
406- let base = match self . load_sync_state ( ) . await {
407- Ok ( Some ( state) ) if state. synced_from_checkpoint && state. sync_base_height > 0 => {
408- state. sync_base_height
409- }
410- _ => 0u32 ,
411- } ;
320+ let sync_base_height = self . sync_base_height ( ) ;
412321
413322 let mut results = Vec :: with_capacity ( ( end_height - start_height + 1 ) as usize ) ;
414323 for abs_h in start_height..=end_height {
415- let idx = if base > 0 {
416- if abs_h < base {
417- continue ;
418- }
419- ( abs_h - base) as usize
420- } else {
421- abs_h as usize
324+ let Some ( idx) = abs_h. checked_sub ( sync_base_height) else {
325+ continue ;
422326 } ;
423- if let Some ( header) = self . headers . get ( idx) {
327+ if let Some ( header) = self . headers . get ( idx as usize ) {
424328 results. push ( ( abs_h, * header) ) ;
425329 }
426330 }
@@ -434,31 +338,16 @@ impl StorageManager for MemoryStorageManager {
434338 & mut self ,
435339 state : & crate :: storage:: PersistentSyncState ,
436340 ) -> StorageResult < ( ) > {
437- // For in-memory storage, we could store the sync state but it won't persist across restarts
438- // This is mainly for testing and compatibility
439- self . metadata . insert (
440- "sync_state" . to_string ( ) ,
441- serde_json:: to_vec ( state) . map_err ( |e| {
442- StorageError :: WriteFailed ( format ! ( "Failed to serialize sync state: {}" , e) )
443- } ) ?,
444- ) ;
341+ self . sync_state = Some ( state. clone ( ) ) ;
445342 Ok ( ( ) )
446343 }
447344
448345 async fn load_sync_state ( & self ) -> StorageResult < Option < crate :: storage:: PersistentSyncState > > {
449- // Try to load from metadata (won't persist across restarts)
450- if let Some ( data) = self . metadata . get ( "sync_state" ) {
451- let state = serde_json:: from_slice ( data) . map_err ( |e| {
452- StorageError :: ReadFailed ( format ! ( "Failed to deserialize sync state: {}" , e) )
453- } ) ?;
454- Ok ( Some ( state) )
455- } else {
456- Ok ( None )
457- }
346+ Ok ( self . sync_state . clone ( ) )
458347 }
459348
460349 async fn clear_sync_state ( & mut self ) -> StorageResult < ( ) > {
461- self . metadata . remove ( " sync_state" ) ;
350+ self . sync_state = None ;
462351 // Also clear checkpoints
463352 self . metadata . retain ( |k, _| !k. starts_with ( "checkpoint_" ) ) ;
464353 Ok ( ( ) )
0 commit comments