Skip to content

Commit 2e85243

Browse files
committed
removed chain storage an related code
1 parent 72ac033 commit 2e85243

File tree

7 files changed

+3
-1454
lines changed

7 files changed

+3
-1454
lines changed

dash-spv/src/chain/fork_detector.rs

Lines changed: 2 additions & 247 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,14 @@
33
//! This module detects when incoming headers create a fork in the blockchain
44
//! rather than extending the current chain tip.
55
6-
use super::{ChainWork, Fork};
7-
use crate::storage::ChainStorage;
8-
use crate::types::ChainState;
9-
use dashcore::{BlockHash, Header as BlockHeader};
6+
use super::Fork;
7+
use dashcore::BlockHash;
108
use std::collections::HashMap;
119

1210
/// Detects and manages blockchain forks
1311
pub struct ForkDetector {
1412
/// Currently known forks indexed by their tip hash
1513
forks: HashMap<BlockHash, Fork>,
16-
/// Maximum number of forks to track
17-
max_forks: usize,
1814
}
1915

2016
impl ForkDetector {
@@ -24,164 +20,9 @@ impl ForkDetector {
2420
}
2521
Ok(Self {
2622
forks: HashMap::new(),
27-
max_forks,
2823
})
2924
}
3025

31-
/// Check if a header creates or extends a fork
32-
pub fn check_header<CS: ChainStorage>(
33-
&mut self,
34-
header: &BlockHeader,
35-
chain_state: &ChainState,
36-
storage: &CS,
37-
) -> ForkDetectionResult {
38-
let header_hash = header.block_hash();
39-
let prev_hash = header.prev_blockhash;
40-
41-
// Check if this extends the main chain
42-
if let Some(tip_header) = chain_state.get_tip_header() {
43-
tracing::trace!(
44-
"Checking main chain extension - prev_hash: {}, tip_hash: {}",
45-
prev_hash,
46-
tip_header.block_hash()
47-
);
48-
if prev_hash == tip_header.block_hash() {
49-
return ForkDetectionResult::ExtendsMainChain;
50-
}
51-
} else {
52-
// Special case: chain state is empty (shouldn't happen with genesis initialized)
53-
// But handle it just in case
54-
if chain_state.headers.is_empty() {
55-
// Check if this is connecting to genesis in storage
56-
if let Ok(Some(height)) = storage.get_header_height(&prev_hash) {
57-
if height == 0 {
58-
// This is the first header after genesis
59-
return ForkDetectionResult::ExtendsMainChain;
60-
}
61-
}
62-
}
63-
}
64-
65-
// Special case: Check if header connects to genesis which might be at height 0
66-
// This handles the case where chain_state has genesis but we're syncing the first real block
67-
if chain_state.tip_height() == 0 {
68-
if let Some(genesis_header) = chain_state.header_at_height(0) {
69-
tracing::debug!(
70-
"Checking if header connects to genesis - prev_hash: {}, genesis_hash: {}",
71-
prev_hash,
72-
genesis_header.block_hash()
73-
);
74-
if prev_hash == genesis_header.block_hash() {
75-
tracing::info!(
76-
"Header extends genesis block - treating as main chain extension"
77-
);
78-
return ForkDetectionResult::ExtendsMainChain;
79-
}
80-
}
81-
}
82-
83-
// Check if this extends a known fork
84-
// Need to find a fork whose tip matches our prev_hash
85-
let matching_fork = self
86-
.forks
87-
.iter()
88-
.find(|(_, fork)| fork.tip_hash == prev_hash)
89-
.map(|(_, fork)| fork.clone());
90-
91-
if let Some(mut fork) = matching_fork {
92-
// Remove the old entry (indexed by old tip)
93-
self.forks.remove(&fork.tip_hash);
94-
95-
// Update the fork
96-
fork.headers.push(*header);
97-
fork.tip_hash = header_hash;
98-
fork.tip_height += 1;
99-
fork.chain_work = fork.chain_work.add_header(header);
100-
101-
// Re-insert with new tip hash
102-
let result_fork = fork.clone();
103-
self.forks.insert(header_hash, fork);
104-
105-
return ForkDetectionResult::ExtendsFork(result_fork);
106-
}
107-
108-
// Check if this connects to the main chain (creates new fork)
109-
if let Ok(Some(height)) = storage.get_header_height(&prev_hash) {
110-
// Check if this would create a fork from before our checkpoint
111-
if chain_state.synced_from_checkpoint() && height < chain_state.sync_base_height {
112-
tracing::warn!(
113-
"Rejecting header that would create fork from height {} (before checkpoint base {}). \
114-
This likely indicates headers from genesis were received during checkpoint sync.",
115-
height, chain_state.sync_base_height
116-
);
117-
return ForkDetectionResult::Orphan;
118-
}
119-
120-
// Found connection point - this creates a new fork
121-
let fork_height = height;
122-
let fork = Fork {
123-
fork_point: prev_hash,
124-
fork_height,
125-
tip_hash: header_hash,
126-
tip_height: fork_height + 1,
127-
headers: vec![*header],
128-
chain_work: ChainWork::from_height_and_header(fork_height, header),
129-
};
130-
131-
self.add_fork(fork.clone());
132-
return ForkDetectionResult::CreatesNewFork(fork);
133-
}
134-
135-
// Additional check: see if header connects to any header in chain_state
136-
// This helps when storage might be out of sync with chain_state
137-
for (height, state_header) in chain_state.headers.iter().enumerate() {
138-
if prev_hash == state_header.block_hash() {
139-
// Calculate the actual blockchain height for this index
140-
let actual_height = chain_state.sync_base_height + (height as u32);
141-
142-
// This connects to a header in chain state but not in storage
143-
// Treat it as extending main chain if it's the tip
144-
if height == chain_state.headers.len() - 1 {
145-
return ForkDetectionResult::ExtendsMainChain;
146-
} else {
147-
// Creates a fork from an earlier point
148-
let fork = Fork {
149-
fork_point: prev_hash,
150-
fork_height: actual_height,
151-
tip_hash: header_hash,
152-
tip_height: actual_height + 1,
153-
headers: vec![*header],
154-
chain_work: ChainWork::from_height_and_header(actual_height, header),
155-
};
156-
157-
self.add_fork(fork.clone());
158-
return ForkDetectionResult::CreatesNewFork(fork);
159-
}
160-
}
161-
}
162-
163-
// This header doesn't connect to anything we know
164-
ForkDetectionResult::Orphan
165-
}
166-
167-
/// Add a new fork to track
168-
fn add_fork(&mut self, fork: Fork) {
169-
self.forks.insert(fork.tip_hash, fork);
170-
171-
// Limit the number of forks we track
172-
if self.forks.len() > self.max_forks {
173-
// Remove the fork with least work
174-
if let Some(weakest) = self.find_weakest_fork() {
175-
self.forks.remove(&weakest);
176-
}
177-
}
178-
}
179-
180-
/// Find the fork with the least cumulative work
181-
fn find_weakest_fork(&self) -> Option<BlockHash> {
182-
self.forks.iter().min_by_key(|(_, fork)| &fork.chain_work).map(|(hash, _)| *hash)
183-
}
184-
18526
/// Get all known forks
18627
pub fn get_forks(&self) -> Vec<&Fork> {
18728
self.forks.values().collect()
@@ -229,92 +70,6 @@ pub enum ForkDetectionResult {
22970
#[cfg(test)]
23071
mod tests {
23172
use super::*;
232-
use crate::storage::MemoryStorage;
233-
use dashcore::blockdata::constants::genesis_block;
234-
use dashcore::Network;
235-
use dashcore_hashes::Hash;
236-
237-
fn create_test_header(prev_hash: BlockHash, nonce: u32) -> BlockHeader {
238-
let mut header = genesis_block(Network::Dash).header;
239-
header.prev_blockhash = prev_hash;
240-
header.nonce = nonce;
241-
header
242-
}
243-
244-
#[test]
245-
fn test_fork_detection() {
246-
let mut detector = ForkDetector::new(10).expect("Failed to create fork detector");
247-
let storage = MemoryStorage::new();
248-
let mut chain_state = ChainState::new();
249-
250-
// Add genesis
251-
let genesis = genesis_block(Network::Dash).header;
252-
storage.store_header(&genesis, 0).expect("Failed to store genesis header");
253-
chain_state.add_header(genesis);
254-
255-
// Header that extends main chain
256-
let header1 = create_test_header(genesis.block_hash(), 1);
257-
let result = detector.check_header(&header1, &chain_state, &storage);
258-
assert!(matches!(result, ForkDetectionResult::ExtendsMainChain));
259-
260-
// Add header1 to chain
261-
storage.store_header(&header1, 1).expect("Failed to store header1");
262-
chain_state.add_header(header1);
263-
264-
// Header that creates a fork from genesis
265-
let fork_header = create_test_header(genesis.block_hash(), 2);
266-
let result = detector.check_header(&fork_header, &chain_state, &storage);
267-
268-
match result {
269-
ForkDetectionResult::CreatesNewFork(fork) => {
270-
assert_eq!(fork.fork_point, genesis.block_hash());
271-
assert_eq!(fork.fork_height, 0);
272-
assert_eq!(fork.tip_height, 1);
273-
assert_eq!(fork.headers.len(), 1);
274-
}
275-
result => panic!("Expected CreatesNewFork, got {:?}", result),
276-
}
277-
278-
// Header that extends the fork
279-
let fork_header2 = create_test_header(fork_header.block_hash(), 3);
280-
let result = detector.check_header(&fork_header2, &chain_state, &storage);
281-
282-
assert!(matches!(result, ForkDetectionResult::ExtendsFork(_)));
283-
assert_eq!(detector.get_forks().len(), 1);
284-
285-
// Orphan header
286-
let orphan = create_test_header(
287-
BlockHash::from_raw_hash(dashcore_hashes::hash_x11::Hash::all_zeros()),
288-
4,
289-
);
290-
let result = detector.check_header(&orphan, &chain_state, &storage);
291-
assert!(matches!(result, ForkDetectionResult::Orphan));
292-
}
293-
294-
#[test]
295-
fn test_fork_limits() {
296-
let mut detector = ForkDetector::new(2).expect("Failed to create fork detector");
297-
let storage = MemoryStorage::new();
298-
let mut chain_state = ChainState::new();
299-
300-
// Add genesis
301-
let genesis = genesis_block(Network::Dash).header;
302-
storage.store_header(&genesis, 0).expect("Failed to store genesis header");
303-
chain_state.add_header(genesis);
304-
305-
// Add a header to extend the main chain past genesis
306-
let header1 = create_test_header(genesis.block_hash(), 1);
307-
storage.store_header(&header1, 1).expect("Failed to store header1");
308-
chain_state.add_header(header1);
309-
310-
// Create 3 forks from genesis, should only keep 2
311-
for i in 0..3 {
312-
let fork_header = create_test_header(genesis.block_hash(), i + 100);
313-
detector.check_header(&fork_header, &chain_state, &storage);
314-
}
315-
316-
assert_eq!(detector.get_forks().len(), 2);
317-
}
31873

31974
#[test]
32075
fn test_fork_detector_zero_max_forks() {

0 commit comments

Comments
 (0)