Skip to content

Commit 837ce06

Browse files
committed
feat: Parallelize header validation with rayon
Pre-calculate `CachedHeader` block hashes in parallel and split header validation into two steps: 1. Validate continuity 2. Parallelized PoW checks ### Timing on a Macbook with M2 Pro | Validation Mode | Before (avg) | After (avg) | |-----------------|--------------|-------------| | Basic | 78.74 ms | 0.067 ms | | Full | 154.33 ms | 10.12 ms |
1 parent bd02c29 commit 837ce06

File tree

3 files changed

+20
-9
lines changed

3 files changed

+20
-9
lines changed

dash-spv/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ rand = "0.8"
4444
hex = "0.4"
4545
indexmap = "2.0"
4646

47+
# Parallelization
48+
rayon = "1.11"
49+
4750
# Terminal UI (optional)
4851
crossterm = { version = "0.27", optional = true }
4952

dash-spv/src/sync/headers/manager.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::sync::headers::validate_headers;
1616
use crate::sync::headers2::Headers2StateManager;
1717
use crate::types::{CachedHeader, ChainState};
1818
use std::sync::Arc;
19+
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
1920
use tokio::sync::RwLock;
2021

2122
/// Configuration for reorg handling
@@ -247,8 +248,15 @@ impl<S: StorageManager + Send + Sync + 'static, N: NetworkManager + Send + Sync
247248

248249
// Wrap headers in CachedHeader to avoid redundant X11 hashing
249250
// This prevents recomputing hashes during validation, logging, and storage
250-
let cached_headers: Vec<CachedHeader> =
251-
headers.iter().map(|h| CachedHeader::new(*h)).collect();
251+
// Precalculate the block hashes in parallel
252+
let cached_headers: Vec<CachedHeader> = headers
253+
.par_iter()
254+
.map(|h| {
255+
let cached = CachedHeader::new(*h);
256+
let _ = cached.block_hash();
257+
cached
258+
})
259+
.collect();
252260

253261
// Step 2: Validate Batch
254262
let first_cached = &cached_headers[0];

dash-spv/src/sync/headers/validation.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Header validation functionality.
22
33
use dashcore::{block::Header as BlockHeader, error::Error as DashError, BlockHash};
4+
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
45
use std::time::Instant;
56

67
use crate::error::{ValidationError, ValidationResult};
@@ -58,7 +59,7 @@ impl ValidationHeader for CachedHeader {
5859
/// Validate a chain of headers considering the validation mode.
5960
pub fn validate_headers<H>(headers: &[H], mode: ValidationMode) -> ValidationResult<()>
6061
where
61-
H: ValidationHeader,
62+
H: ValidationHeader + Send + Sync,
6263
{
6364
if mode == ValidationMode::None {
6465
tracing::debug!("Skipping header validation: disabled");
@@ -82,15 +83,14 @@ where
8283
));
8384
}
8485
}
85-
86-
if mode == ValidationMode::Full {
87-
// Validate proof of work with X11 hashing
88-
header.validate_pow()?;
89-
}
90-
9186
prev_block_hash = Some(header.block_hash());
9287
}
9388

89+
if mode == ValidationMode::Full {
90+
// Parallelized proof of work validation
91+
headers.par_iter().try_for_each(|header| header.validate_pow())?;
92+
}
93+
9494
tracing::debug!(
9595
"Header chain validation passed for {} headers in mode: {:?}, duration: {:?}",
9696
headers.len(),

0 commit comments

Comments
 (0)