Skip to content

Commit 5e505f9

Browse files
committed
validator trait created, instalock and headers being validated with it
1 parent a927a4c commit 5e505f9

File tree

6 files changed

+115
-94
lines changed

6 files changed

+115
-94
lines changed

dash-spv/src/client/chainlock.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::error::{Result, SpvError};
1212
use crate::network::NetworkManager;
1313
use crate::storage::StorageManager;
1414
use crate::types::SpvEvent;
15+
use crate::validation::{InstantLockValidator, Validator};
1516
use key_wallet_manager::wallet_interface::WalletInterface;
1617

1718
use super::DashSpvClient;
@@ -99,8 +100,8 @@ impl<W: WalletInterface, N: NetworkManager, S: StorageManager> DashSpvClient<W,
99100

100101
// Validate the InstantLock (structure + BLS signature)
101102
// This is REQUIRED for security - never accept InstantLocks without signature verification
102-
let validator = crate::validation::InstantLockValidator::new();
103-
if let Err(e) = validator.validate(&islock, masternode_engine) {
103+
let validator = InstantLockValidator::new(masternode_engine);
104+
if let Err(e) = validator.validate(&islock) {
104105
// Penalize the peer that relayed the invalid InstantLock
105106
let reason = format!("Invalid InstantLock: {}", e);
106107
tracing::warn!("{}", reason);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use crate::client::ClientConfig;
1212
use crate::error::{SyncError, SyncResult};
1313
use crate::network::NetworkManager;
1414
use crate::storage::StorageManager;
15-
use crate::sync::headers::validate_headers;
1615
use crate::types::{ChainState, HashedBlockHeader};
16+
use crate::validation::{BlockHeaderValidator, Validator};
1717
use crate::ValidationMode;
1818
use std::sync::Arc;
1919
use tokio::sync::RwLock;
@@ -180,7 +180,7 @@ impl<S: StorageManager, N: NetworkManager> HeaderSyncManager<S, N> {
180180
}
181181

182182
if self.config.validation_mode != ValidationMode::None {
183-
validate_headers(&cached_headers).map_err(|e| {
183+
BlockHeaderValidator::new().validate(&cached_headers).map_err(|e| {
184184
let error = format!("Header validation failed: {}", e);
185185
tracing::error!(error);
186186
SyncError::Validation(error)

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//! Header synchronization with fork detection and reorganization handling.
22
33
mod manager;
4-
pub mod validation;
54

65
pub use manager::{HeaderSyncManager, ReorgConfig};
7-
pub use validation::validate_headers;
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,59 @@
1-
//! Header validation functionality.
2-
31
use rayon::prelude::*;
42
use std::time::Instant;
53

64
use crate::error::{ValidationError, ValidationResult};
75
use crate::types::HashedBlockHeader;
6+
use crate::validation::Validator;
87

9-
/// Validate a chain of headers.
10-
pub fn validate_headers(hashed_headers: &[HashedBlockHeader]) -> ValidationResult<()> {
11-
let start = Instant::now();
12-
13-
// Check PoW of i and continuity of i-1 to i in parallel
14-
hashed_headers.par_iter().enumerate().try_for_each(|(i, header)| {
15-
// For the first header, skip chain continuity check since we don't have i-1 here
16-
if i > 0 && header.header().prev_blockhash != *hashed_headers[i - 1].hash() {
17-
return Err(ValidationError::InvalidHeaderChain(format!(
18-
"Header {:?} does not connect to {:?}",
19-
hashed_headers[i - 1],
20-
header
21-
)));
22-
}
23-
// Check if PoW target is met
24-
if !header.header().target().is_met_by(*header.hash()) {
25-
return Err(ValidationError::InvalidProofOfWork);
26-
}
27-
Ok(())
28-
})?;
8+
#[derive(Default)]
9+
pub struct BlockHeaderValidator {}
2910

30-
tracing::trace!(
31-
"Header chain validation passed for {} headers, duration: {:?}",
32-
hashed_headers.len(),
33-
start.elapsed(),
34-
);
11+
impl BlockHeaderValidator {
12+
pub fn new() -> Self {
13+
Self {}
14+
}
15+
}
16+
17+
impl Validator<&[HashedBlockHeader]> for BlockHeaderValidator {
18+
fn validate(&self, hashed_headers: &[HashedBlockHeader]) -> ValidationResult<()> {
19+
let start = Instant::now();
20+
21+
// Check PoW of i and continuity of i-1 to i in parallel
22+
hashed_headers.par_iter().enumerate().try_for_each(|(i, header)| {
23+
// For the first header, skip chain continuity check since we don't have i-1 here
24+
if i > 0 && header.header().prev_blockhash != *hashed_headers[i - 1].hash() {
25+
return Err(ValidationError::InvalidHeaderChain(format!(
26+
"Header {:?} does not connect to {:?}",
27+
hashed_headers[i - 1],
28+
header
29+
)));
30+
}
31+
// Check if PoW target is met
32+
if !header.header().target().is_met_by(*header.hash()) {
33+
return Err(ValidationError::InvalidProofOfWork);
34+
}
35+
Ok(())
36+
})?;
37+
38+
tracing::trace!(
39+
"Header chain validation passed for {} headers, duration: {:?}",
40+
hashed_headers.len(),
41+
start.elapsed(),
42+
);
3543

36-
Ok(())
44+
Ok(())
45+
}
3746
}
3847

3948
#[cfg(test)]
4049
mod tests {
41-
use super::validate_headers;
42-
use crate::error::ValidationError;
43-
use crate::types::HashedBlockHeader;
4450
use dashcore::{
45-
block::{Header as BlockHeader, Version},
46-
blockdata::constants::genesis_block,
47-
CompactTarget, Network,
51+
block::Version, constants::genesis_block, CompactTarget, Header as BlockHeader, Network,
4852
};
4953
use dashcore_hashes::Hash;
5054

55+
use super::*;
56+
5157
// Very easy target to pass PoW checks for continuity tests
5258
const MAX_TARGET: u32 = 0x2100ffff;
5359

@@ -64,17 +70,23 @@ mod tests {
6470

6571
#[test]
6672
fn test_empty_headers() {
67-
assert!(validate_headers(&[]).is_ok());
73+
let validator = BlockHeaderValidator::new();
74+
75+
assert!(validator.validate(&[]).is_ok());
6876
}
6977

7078
#[test]
7179
fn test_single_header() {
80+
let validator = BlockHeaderValidator::new();
81+
7282
let header = create_test_header(dashcore::BlockHash::all_zeros(), 0);
73-
assert!(validate_headers(&[header]).is_ok());
83+
assert!(validator.validate(&[header]).is_ok());
7484
}
7585

7686
#[test]
7787
fn test_valid_chain() {
88+
let validator = BlockHeaderValidator::new();
89+
7890
let mut headers = vec![];
7991
let mut prev_hash = dashcore::BlockHash::all_zeros();
8092

@@ -84,22 +96,26 @@ mod tests {
8496
headers.push(header);
8597
}
8698

87-
assert!(validate_headers(&headers).is_ok());
99+
assert!(validator.validate(&headers).is_ok());
88100
}
89101

90102
#[test]
91103
fn test_broken_chain() {
104+
let validator = BlockHeaderValidator::new();
105+
92106
let header1 = create_test_header(dashcore::BlockHash::all_zeros(), 0);
93107
let header2 = create_test_header(*header1.hash(), 1);
94108
// header3 doesn't connect to header2
95109
let header3 = create_test_header(dashcore::BlockHash::all_zeros(), 2);
96110

97-
let result = validate_headers(&[header1, header2, header3]);
111+
let result = validator.validate(&[header1, header2, header3]);
98112
assert!(matches!(result, Err(ValidationError::InvalidHeaderChain(_))));
99113
}
100114

101115
#[test]
102116
fn test_invalid_pow() {
117+
let validator = BlockHeaderValidator::new();
118+
103119
let header = HashedBlockHeader::from(BlockHeader {
104120
version: Version::from_consensus(1),
105121
prev_blockhash: dashcore::BlockHash::all_zeros(),
@@ -109,16 +125,18 @@ mod tests {
109125
nonce: 0,
110126
});
111127

112-
let result = validate_headers(&[header]);
128+
let result = validator.validate(&[header]);
113129
assert!(matches!(result, Err(ValidationError::InvalidProofOfWork)));
114130
}
115131

116132
#[test]
117133
fn test_genesis_blocks() {
134+
let validator = BlockHeaderValidator::new();
135+
118136
for network in [Network::Dash, Network::Testnet, Network::Regtest] {
119137
let genesis = HashedBlockHeader::from(genesis_block(network).header);
120138
assert!(
121-
validate_headers(&[genesis]).is_ok(),
139+
validator.validate(&[genesis]).is_ok(),
122140
"Genesis block for {:?} should validate",
123141
network
124142
);
@@ -127,6 +145,8 @@ mod tests {
127145

128146
#[test]
129147
fn test_invalid_pow_mid_chain() {
148+
let validator = BlockHeaderValidator::new();
149+
130150
let header1 = create_test_header(dashcore::BlockHash::all_zeros(), 0);
131151
let header2 = create_test_header(*header1.hash(), 1);
132152

@@ -142,7 +162,7 @@ mod tests {
142162

143163
let header4 = create_test_header(*header3.hash(), 3);
144164

145-
let result = validate_headers(&[header1, header2, header3, header4]);
165+
let result = validator.validate(&[header1, header2, header3, header4]);
146166
assert!(matches!(result, Err(ValidationError::InvalidProofOfWork)));
147167
}
148168
}

0 commit comments

Comments
 (0)