Skip to content

Commit 1284cc9

Browse files
authored
refactor: Cleanup and simplify MemoryStorageManager (#224)
1 parent cc61379 commit 1284cc9

File tree

1 file changed

+35
-146
lines changed

1 file changed

+35
-146
lines changed

dash-spv/src/storage/memory.rs

Lines changed: 35 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)