Skip to content

Commit 1debfa3

Browse files
committed
sync from genesis working kind of
1 parent 4e6d9de commit 1debfa3

13 files changed

Lines changed: 124 additions & 113 deletions

File tree

dash-spv/src/chain/chainlock_manager.rs

Lines changed: 38 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
use dashcore::{BlockHash, ChainLock};
77
use dashcore::sml::masternode_list_engine::MasternodeListEngine;
88
use indexmap::IndexMap;
9-
use std::sync::{Arc, RwLock};
9+
use std::sync::Arc;
10+
use tokio::sync::RwLock;
1011
use tracing::{debug, error, info, warn};
1112

1213
use crate::error::{StorageError, StorageResult, ValidationError, ValidationResult};
@@ -57,22 +58,15 @@ impl ChainLockManager {
5758
}
5859

5960
/// Set the masternode engine for validation
60-
pub fn set_masternode_engine(&self, engine: Arc<MasternodeListEngine>) {
61-
match self.masternode_engine.write() {
62-
Ok(mut guard) => {
63-
*guard = Some(engine);
64-
info!("Masternode engine set for ChainLock validation");
65-
}
66-
Err(e) => {
67-
error!("Failed to set masternode engine: {}", e);
68-
}
69-
}
61+
pub async fn set_masternode_engine(&self, engine: Arc<MasternodeListEngine>) {
62+
let mut guard = self.masternode_engine.write().await;
63+
*guard = Some(engine);
64+
info!("Masternode engine set for ChainLock validation");
7065
}
7166

7267
/// Queue a ChainLock for validation when masternode data is available
73-
pub fn queue_pending_chainlock(&self, chain_lock: ChainLock) -> StorageResult<()> {
74-
let mut pending = self.pending_chainlocks.write()
75-
.map_err(|_| StorageError::LockPoisoned("pending_chainlocks".to_string()))?;
68+
pub async fn queue_pending_chainlock(&self, chain_lock: ChainLock) -> StorageResult<()> {
69+
let mut pending = self.pending_chainlocks.write().await;
7670

7771
// If at capacity, drop the oldest ChainLock
7872
if pending.len() >= MAX_PENDING_CHAINLOCKS {
@@ -95,8 +89,7 @@ impl ChainLockManager {
9589
storage: &mut dyn StorageManager,
9690
) -> ValidationResult<()> {
9791
let pending = {
98-
let mut pending_guard = self.pending_chainlocks.write()
99-
.map_err(|_| ValidationError::InvalidChainLock("Lock poisoned".to_string()))?;
92+
let mut pending_guard = self.pending_chainlocks.write().await;
10093
std::mem::take(&mut *pending_guard)
10194
};
10295

@@ -138,8 +131,8 @@ impl ChainLockManager {
138131
);
139132

140133
// Check if we already have this chain lock
141-
if self.has_chain_lock_at_height(chain_lock.block_height) {
142-
let existing = self.get_chain_lock_by_height(chain_lock.block_height);
134+
if self.has_chain_lock_at_height(chain_lock.block_height).await {
135+
let existing = self.get_chain_lock_by_height(chain_lock.block_height).await;
143136
if let Some(existing_entry) = existing {
144137
if existing_entry.chain_lock.block_hash != chain_lock.block_hash {
145138
error!(
@@ -173,8 +166,7 @@ impl ChainLockManager {
173166
}
174167

175168
// Full validation with masternode engine if available
176-
let engine_guard = self.masternode_engine.read()
177-
.map_err(|_| ValidationError::InvalidChainLock("Lock poisoned".to_string()))?;
169+
let engine_guard = self.masternode_engine.read().await;
178170

179171
let mut validated = false;
180172

@@ -195,7 +187,7 @@ impl ChainLockManager {
195187
warn!("⚠️ Masternode engine exists but lacks required masternode lists for height {} (needs list at height {} for ChainLock validation), queueing ChainLock for later validation",
196188
chain_lock.block_height, required_height);
197189
drop(engine_guard); // Release the read lock before acquiring write lock
198-
self.queue_pending_chainlock(chain_lock.clone())
190+
self.queue_pending_chainlock(chain_lock.clone()).await
199191
.map_err(|e| ValidationError::InvalidChainLock(
200192
format!("Failed to queue pending ChainLock: {}", e)
201193
))?;
@@ -210,7 +202,7 @@ impl ChainLockManager {
210202
// Queue for later validation when engine becomes available
211203
warn!("⚠️ Masternode engine not available, queueing ChainLock for later validation");
212204
drop(engine_guard); // Release the read lock before acquiring write lock
213-
self.queue_pending_chainlock(chain_lock.clone())
205+
self.queue_pending_chainlock(chain_lock.clone()).await
214206
.map_err(|e| ValidationError::InvalidChainLock(
215207
format!("Failed to queue pending ChainLock: {}", e)
216208
))?;
@@ -266,10 +258,8 @@ impl ChainLockManager {
266258

267259
// Store in memory caches
268260
{
269-
let mut by_height = self.chain_locks_by_height.write()
270-
.map_err(|_| StorageError::LockPoisoned("chain_locks_by_height".to_string()))?;
271-
let mut by_hash = self.chain_locks_by_hash.write()
272-
.map_err(|_| StorageError::LockPoisoned("chain_locks_by_hash".to_string()))?;
261+
let mut by_height = self.chain_locks_by_height.write().await;
262+
let mut by_hash = self.chain_locks_by_hash.write().await;
273263

274264
by_height.insert(chain_lock.block_height, entry.clone());
275265
by_hash.insert(chain_lock.block_hash, entry.clone());
@@ -304,58 +294,51 @@ impl ChainLockManager {
304294
}
305295

306296
/// Check if we have a chain lock at the given height
307-
pub fn has_chain_lock_at_height(&self, height: u32) -> bool {
308-
self.chain_locks_by_height.read()
309-
.map(|locks| locks.contains_key(&height))
310-
.unwrap_or(false)
297+
pub async fn has_chain_lock_at_height(&self, height: u32) -> bool {
298+
let locks = self.chain_locks_by_height.read().await;
299+
locks.contains_key(&height)
311300
}
312301

313302
/// Get chain lock by height
314-
pub fn get_chain_lock_by_height(&self, height: u32) -> Option<ChainLockEntry> {
315-
self.chain_locks_by_height.read()
316-
.ok()
317-
.and_then(|locks| locks.get(&height).cloned())
303+
pub async fn get_chain_lock_by_height(&self, height: u32) -> Option<ChainLockEntry> {
304+
let locks = self.chain_locks_by_height.read().await;
305+
locks.get(&height).cloned()
318306
}
319307

320308
/// Get chain lock by block hash
321-
pub fn get_chain_lock_by_hash(&self, hash: &BlockHash) -> Option<ChainLockEntry> {
322-
self.chain_locks_by_hash.read()
323-
.ok()
324-
.and_then(|locks| locks.get(hash).cloned())
309+
pub async fn get_chain_lock_by_hash(&self, hash: &BlockHash) -> Option<ChainLockEntry> {
310+
let locks = self.chain_locks_by_hash.read().await;
311+
locks.get(hash).cloned()
325312
}
326313

327314
/// Check if a block is chain-locked
328-
pub fn is_block_chain_locked(&self, block_hash: &BlockHash, height: u32) -> bool {
315+
pub async fn is_block_chain_locked(&self, block_hash: &BlockHash, height: u32) -> bool {
329316
// First check by hash (most specific)
330-
if let Some(entry) = self.get_chain_lock_by_hash(block_hash) {
317+
if let Some(entry) = self.get_chain_lock_by_hash(block_hash).await {
331318
return entry.validated && entry.chain_lock.block_hash == *block_hash;
332319
}
333320

334321
// Then check by height
335-
if let Some(entry) = self.get_chain_lock_by_height(height) {
322+
if let Some(entry) = self.get_chain_lock_by_height(height).await {
336323
return entry.validated && entry.chain_lock.block_hash == *block_hash;
337324
}
338325

339326
false
340327
}
341328

342329
/// Get the highest chain-locked block height
343-
pub fn get_highest_chain_locked_height(&self) -> Option<u32> {
344-
self.chain_locks_by_height.read()
345-
.ok()
346-
.and_then(|locks| locks.keys().max().cloned())
330+
pub async fn get_highest_chain_locked_height(&self) -> Option<u32> {
331+
let locks = self.chain_locks_by_height.read().await;
332+
locks.keys().max().cloned()
347333
}
348334

349335
/// Check if a reorganization would violate chain locks
350-
pub fn would_violate_chain_lock(&self, reorg_from_height: u32, reorg_to_height: u32) -> bool {
336+
pub async fn would_violate_chain_lock(&self, reorg_from_height: u32, reorg_to_height: u32) -> bool {
351337
if !self.enforce_chain_locks {
352338
return false;
353339
}
354340

355-
let locks = match self.chain_locks_by_height.read() {
356-
Ok(locks) => locks,
357-
Err(_) => return false, // If we can't read locks, assume no violation
358-
};
341+
let locks = self.chain_locks_by_height.read().await;
359342

360343
// Check if any chain-locked block would be reorganized
361344
for height in reorg_from_height..=reorg_to_height {
@@ -395,10 +378,8 @@ impl ChainLockManager {
395378
validated: true,
396379
};
397380

398-
let mut by_height = self.chain_locks_by_height.write()
399-
.map_err(|_| StorageError::LockPoisoned("chain_locks_by_height".to_string()))?;
400-
let mut by_hash = self.chain_locks_by_hash.write()
401-
.map_err(|_| StorageError::LockPoisoned("chain_locks_by_hash".to_string()))?;
381+
let mut by_height = self.chain_locks_by_height.write().await;
382+
let mut by_hash = self.chain_locks_by_hash.write().await;
402383

403384
by_height.insert(chain_lock.block_height, entry.clone());
404385
by_hash.insert(chain_lock.block_hash, entry);
@@ -417,29 +398,9 @@ impl ChainLockManager {
417398

418399

419400
/// Get chain lock statistics
420-
pub fn get_stats(&self) -> ChainLockStats {
421-
let by_height = match self.chain_locks_by_height.read() {
422-
Ok(guard) => guard,
423-
Err(_) => return ChainLockStats {
424-
total_chain_locks: 0,
425-
cached_by_height: 0,
426-
cached_by_hash: 0,
427-
highest_locked_height: None,
428-
lowest_locked_height: None,
429-
enforce_chain_locks: self.enforce_chain_locks,
430-
},
431-
};
432-
let by_hash = match self.chain_locks_by_hash.read() {
433-
Ok(guard) => guard,
434-
Err(_) => return ChainLockStats {
435-
total_chain_locks: 0,
436-
cached_by_height: 0,
437-
cached_by_hash: 0,
438-
highest_locked_height: None,
439-
lowest_locked_height: None,
440-
enforce_chain_locks: self.enforce_chain_locks,
441-
},
442-
};
401+
pub async fn get_stats(&self) -> ChainLockStats {
402+
let by_height = self.chain_locks_by_height.read().await;
403+
let by_hash = self.chain_locks_by_hash.read().await;
443404

444405
ChainLockStats {
445406
total_chain_locks: by_height.len(),

dash-spv/src/chain/chainlock_test.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ mod tests {
2929
assert!(result.is_ok(), "ChainLock processing should succeed");
3030

3131
// Verify it was stored
32-
assert!(chainlock_manager.has_chain_lock_at_height(1000));
32+
assert!(chainlock_manager.has_chain_lock_at_height(1000).await);
3333

3434
// Verify we can retrieve it
35-
let entry = chainlock_manager.get_chain_lock_by_height(1000)
35+
let entry = chainlock_manager.get_chain_lock_by_height(1000).await
3636
.expect("ChainLock should be retrievable after storing");
3737
assert_eq!(entry.chain_lock.block_height, 1000);
3838
assert_eq!(entry.chain_lock.block_hash, chainlock.block_hash);
@@ -67,11 +67,11 @@ mod tests {
6767
.expect("Second ChainLock should process successfully");
6868

6969
// Verify both are stored
70-
assert!(chainlock_manager.has_chain_lock_at_height(1000));
71-
assert!(chainlock_manager.has_chain_lock_at_height(2000));
70+
assert!(chainlock_manager.has_chain_lock_at_height(1000).await);
71+
assert!(chainlock_manager.has_chain_lock_at_height(2000).await);
7272

7373
// Get highest ChainLock
74-
let highest = chainlock_manager.get_highest_chain_locked_height();
74+
let highest = chainlock_manager.get_highest_chain_locked_height().await;
7575
assert_eq!(highest, Some(2000));
7676
}
7777

@@ -97,8 +97,8 @@ mod tests {
9797
}
9898

9999
// Test reorganization protection
100-
assert!(!chainlock_manager.would_violate_chain_lock(500, 999)); // Before ChainLocks - OK
101-
assert!(chainlock_manager.would_violate_chain_lock(1500, 2500)); // Would reorg ChainLock at 2000
102-
assert!(!chainlock_manager.would_violate_chain_lock(3001, 4000)); // After ChainLocks - OK
100+
assert!(!chainlock_manager.would_violate_chain_lock(500, 999).await); // Before ChainLocks - OK
101+
assert!(chainlock_manager.would_violate_chain_lock(1500, 2500).await); // Would reorg ChainLock at 2000
102+
assert!(!chainlock_manager.would_violate_chain_lock(3001, 4000).await); // After ChainLocks - OK
103103
}
104104
}

dash-spv/src/chain/checkpoints.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ pub struct Checkpoint {
3636
pub protocol_version: Option<u32>,
3737
/// Nonce value for the block
3838
pub nonce: u32,
39+
/// Block version
40+
pub version: u32,
3941
}
4042

4143
impl Checkpoint {
@@ -433,6 +435,17 @@ fn create_checkpoint(
433435
nonce: u32,
434436
masternode_list: Option<&str>,
435437
) -> Checkpoint {
438+
// Determine version based on height
439+
let version = if height == 0 {
440+
1 // Genesis block version
441+
} else if height < 750000 {
442+
2 // Pre-v0.12 blocks
443+
} else if height < 1700000 {
444+
536870912 // v0.12+ blocks (0x20000000)
445+
} else {
446+
536870912 // v0.14+ blocks (0x20000000)
447+
};
448+
436449
Checkpoint {
437450
height,
438451
block_hash: parse_block_hash_safe(hash),
@@ -448,6 +461,7 @@ fn create_checkpoint(
448461
ml.split("__").nth(1).and_then(|s| s.parse().ok())
449462
}),
450463
nonce,
464+
version,
451465
}
452466
}
453467

dash-spv/src/chain/reorg.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,18 @@ impl ReorgManager {
7979
}
8080

8181
/// Check if a fork has more work than the current chain and should trigger a reorg
82-
pub fn should_reorganize(
82+
pub async fn should_reorganize(
8383
&self,
8484
current_tip: &ChainTip,
8585
fork: &Fork,
8686
storage: &dyn ChainStorage,
8787
) -> Result<bool, String> {
88-
self.should_reorganize_with_chain_state(current_tip, fork, storage, None)
88+
self.should_reorganize_with_chain_state(current_tip, fork, storage, None).await
8989
}
9090

9191
/// Check if a fork has more work than the current chain and should trigger a reorg
9292
/// This version is checkpoint-aware when chain_state is provided
93-
pub fn should_reorganize_with_chain_state(
93+
pub async fn should_reorganize_with_chain_state(
9494
&self,
9595
current_tip: &ChainTip,
9696
fork: &Fork,
@@ -153,7 +153,7 @@ impl ReorgManager {
153153
if self.respect_chain_locks {
154154
if let Some(ref chain_lock_mgr) = self.chain_lock_manager {
155155
// Check if reorg would violate chain locks
156-
if chain_lock_mgr.would_violate_chain_lock(fork.fork_height, current_tip.height) {
156+
if chain_lock_mgr.would_violate_chain_lock(fork.fork_height, current_tip.height).await {
157157
return Err(format!(
158158
"Cannot reorg: would violate chain lock between heights {} and {}",
159159
fork.fork_height, current_tip.height
@@ -163,7 +163,7 @@ impl ReorgManager {
163163
// Fall back to checking individual blocks
164164
for height in (fork.fork_height + 1)..=current_tip.height {
165165
if let Ok(Some(header)) = storage.get_header_by_height(height) {
166-
if self.is_chain_locked(&header, storage)? {
166+
if self.is_chain_locked(&header, storage).await? {
167167
return Err(format!(
168168
"Cannot reorg past chain-locked block at height {}",
169169
height
@@ -478,15 +478,15 @@ impl ReorgManager {
478478
}
479479

480480
/// Check if a block is chain-locked
481-
fn is_chain_locked(
481+
async fn is_chain_locked(
482482
&self,
483483
header: &BlockHeader,
484484
storage: &dyn ChainStorage,
485485
) -> Result<bool, String> {
486486
if let Some(ref chain_lock_mgr) = self.chain_lock_manager {
487487
// Get the height of this header
488488
if let Ok(Some(height)) = storage.get_header_height(&header.block_hash()) {
489-
return Ok(chain_lock_mgr.is_block_chain_locked(&header.block_hash(), height));
489+
return Ok(chain_lock_mgr.is_block_chain_locked(&header.block_hash(), height).await);
490490
}
491491
}
492492
// If no chain lock manager or height not found, assume not locked

dash-spv/src/client/mod.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,18 @@ impl DashSpvClient {
818818

819819
// Check if we have connected peers and start initial sync operations (once)
820820
if !initial_sync_started && self.network.peer_count() > 0 {
821-
tracing::info!("🚀 Peers connected, starting initial sync operations...");
821+
tracing::info!("🚀 Peers connected (count: {}), starting initial sync operations...", self.network.peer_count());
822+
823+
// Log peer info
824+
let peer_info = self.network.peer_info();
825+
for (i, peer) in peer_info.iter().enumerate() {
826+
tracing::info!(" Peer {}: {} (version: {}, height: {:?})",
827+
i + 1,
828+
peer.address,
829+
peer.version.unwrap_or(0),
830+
peer.best_height
831+
);
832+
}
822833

823834
// Start initial sync with sequential sync manager
824835
match self.sync_manager.start_sync(&mut *self.network, &mut *self.storage).await {
@@ -1050,7 +1061,7 @@ impl DashSpvClient {
10501061
// Check if masternode sync has completed and update ChainLock validation
10511062
if !masternode_engine_updated && self.config.enable_masternodes {
10521063
// Check if we have a masternode engine available now
1053-
if let Ok(has_engine) = self.update_chainlock_validation() {
1064+
if let Ok(has_engine) = self.update_chainlock_validation().await {
10541065
if has_engine {
10551066
masternode_engine_updated = true;
10561067
info!("✅ Masternode sync complete - ChainLock validation enabled");
@@ -1682,12 +1693,12 @@ impl DashSpvClient {
16821693
/// Update ChainLock validation with masternode engine after sync completes.
16831694
/// This should be called when masternode sync finishes to enable full validation.
16841695
/// Returns true if the engine was successfully set.
1685-
pub fn update_chainlock_validation(&self) -> Result<bool> {
1696+
pub async fn update_chainlock_validation(&self) -> Result<bool> {
16861697
// Check if masternode sync has an engine available
16871698
if let Some(engine) = self.sync_manager.get_masternode_engine() {
16881699
// Clone the engine for the ChainLockManager
16891700
let engine_arc = Arc::new(engine.clone());
1690-
self.chainlock_manager.set_masternode_engine(engine_arc);
1701+
self.chainlock_manager.set_masternode_engine(engine_arc).await;
16911702

16921703
info!("Updated ChainLockManager with masternode engine for full validation");
16931704

0 commit comments

Comments
 (0)