1use std::cmp;
8use std::collections::BTreeMap;
9use std::sync::Arc;
10
11use dusk_bytes::Serializable;
12use dusk_consensus::config::{
13 CONSENSUS_MAX_ITER, MIN_EMERGENCY_BLOCK_TIME, MINIMUM_BLOCK_TIME,
14 RELAX_ITERATION_THRESHOLD, is_emergency_block, is_emergency_iter,
15};
16use dusk_consensus::errors::{
17 AttestationError, FailedIterationError, HeaderError,
18};
19use dusk_consensus::operations::Voter;
20use dusk_consensus::quorum::verifiers;
21use dusk_consensus::user::committee::CommitteeSet;
22use dusk_consensus::user::provisioners::{ContextProvisioners, Provisioners};
23use dusk_core::signatures::bls::{
24 self as core_bls, MultisigPublicKey, MultisigSignature,
25 PublicKey as BlsPublicKey,
26};
27use dusk_core::stake::EPOCH;
28use hex;
29use node_data::bls::PublicKeyBytes;
30use node_data::hard_fork::bls_version_at;
31use node_data::ledger::{Fault, InvalidFault, Seed};
32use node_data::message::payload::{RatificationResult, Vote};
33use node_data::message::{BLOCK_HEADER_VERSION, ConsensusHeader};
34use node_data::{StepName, get_current_timestamp, ledger};
35use tokio::sync::RwLock;
36use tracing::{debug, error};
37
38use crate::database;
39use crate::database::Ledger;
40
41pub(crate) const MARGIN_TIMESTAMP: u64 = 3;
45
46pub(crate) struct Validator<'a, DB: database::DB> {
51 pub(crate) db: Arc<RwLock<DB>>,
52 prev_header: &'a ledger::Header,
53 provisioners: &'a ContextProvisioners,
54}
55
56impl<'a, DB: database::DB> Validator<'a, DB> {
57 pub fn new(
58 db: Arc<RwLock<DB>>,
59 prev_header: &'a ledger::Header,
60 provisioners: &'a ContextProvisioners,
61 ) -> Self {
62 Self {
63 db,
64 prev_header,
65 provisioners,
66 }
67 }
68
69 pub async fn verify_block_header_fields(
87 &self,
88 header: &ledger::Header,
89 expected_generator: &PublicKeyBytes,
90 check_attestation: bool,
91 ) -> Result<(u8, Vec<Voter>, Vec<Voter>), HeaderError> {
92 self.verify_block_header_basic_fields(header, expected_generator)
93 .await?;
94
95 let cert_voters = self.verify_prev_block_cert(header).await?;
96
97 let mut att_voters = vec![];
98 if check_attestation {
99 att_voters = verify_att(
100 &header.att,
101 header.to_consensus_header(),
102 self.prev_header.seed,
103 self.provisioners.current(),
104 Some(RatificationResult::Success(Vote::Valid(header.hash))),
105 )
106 .await?;
107 }
108
109 let pni = self.verify_failed_iterations(header).await?;
110 Ok((pni, cert_voters, att_voters))
111 }
112
113 fn verify_block_generator(
114 &self,
115 header: &'a ledger::Header,
116 expected_generator: &PublicKeyBytes,
117 ) -> Result<MultisigPublicKey, HeaderError> {
118 if expected_generator != &header.generator_bls_pubkey {
119 return Err(HeaderError::InvalidBlockSignature(
120 "Signed by a different generator:".into(),
121 ));
122 }
123
124 let generator = header.generator_bls_pubkey.inner();
126 let generator = BlsPublicKey::from_bytes(generator).map_err(|err| {
127 HeaderError::InvalidBlockSignature(format!(
128 "invalid pk bytes: {err:?}"
129 ))
130 })?;
131 let bls_version = bls_version_at(header.height);
132 let generator = core_bls::aggregate(&[generator], bls_version)
133 .map_err(|err| {
134 HeaderError::InvalidBlockSignature(format!(
135 "failed aggregating single key: {err:?}"
136 ))
137 })?;
138
139 let block_sig = MultisigSignature::from_bytes(header.signature.inner())
141 .map_err(|err| {
142 HeaderError::InvalidBlockSignature(format!(
143 "invalid block signature bytes: {err:?}"
144 ))
145 })?;
146 core_bls::verify_multisig(
147 &generator,
148 &block_sig,
149 &header.hash,
150 bls_version,
151 )
152 .map_err(|err| {
153 HeaderError::InvalidBlockSignature(format!(
154 "invalid block signature: {err:?}"
155 ))
156 })?;
157
158 Ok(generator)
159 }
160
161 async fn verify_block_header_basic_fields(
163 &self,
164 header: &'a ledger::Header,
165 expected_generator: &PublicKeyBytes,
166 ) -> Result<(), HeaderError> {
167 let generator =
168 self.verify_block_generator(header, expected_generator)?;
169
170 if header.version != BLOCK_HEADER_VERSION {
171 return Err(HeaderError::UnsupportedVersion);
172 }
173
174 if header.hash == [0u8; 32] {
175 return Err(HeaderError::EmptyHash);
176 }
177
178 if header.height != self.prev_header.height + 1 {
179 return Err(HeaderError::MismatchHeight(
180 header.height,
181 self.prev_header.height,
182 ));
183 }
184
185 if header.timestamp < self.prev_header.timestamp + *MINIMUM_BLOCK_TIME {
187 return Err(HeaderError::BlockTimeLess);
188 }
189
190 if is_emergency_block(header.iteration)
198 && header.timestamp
199 < self.prev_header.timestamp
200 + MIN_EMERGENCY_BLOCK_TIME.as_secs()
201 {
202 return Err(HeaderError::BlockTimeLess);
203 }
204
205 let local_time = get_current_timestamp();
206
207 if header.timestamp > local_time + MARGIN_TIMESTAMP {
208 return Err(HeaderError::BlockTimeHigher(header.timestamp));
209 }
210
211 if header.prev_block_hash != self.prev_header.hash {
212 return Err(HeaderError::PrevBlockHash);
213 }
214
215 let block_exists = self
217 .db
218 .read()
219 .await
220 .view(|db| db.block_exists(&header.hash))
221 .map_err(|e| {
222 HeaderError::Storage(
223 "error checking Ledger::get_block_exists",
224 e,
225 )
226 })?;
227
228 if block_exists {
229 return Err(HeaderError::BlockExists);
230 }
231
232 self.verify_seed_field(header.seed.inner(), &generator, header.height)?;
234
235 Ok(())
236 }
237
238 fn verify_seed_field(
239 &self,
240 seed: &[u8; 48],
241 pk: &MultisigPublicKey,
242 block_height: u64,
243 ) -> Result<(), HeaderError> {
244 let signature = MultisigSignature::from_bytes(seed).map_err(|err| {
245 HeaderError::InvalidSeed(format!(
246 "invalid seed signature bytes: {err:?}"
247 ))
248 })?;
249
250 core_bls::verify_multisig(
251 pk,
252 &signature,
253 self.prev_header.seed.inner(),
254 bls_version_at(block_height),
255 )
256 .map_err(|err| {
257 HeaderError::InvalidSeed(format!("invalid seed: {err:?}"))
258 })?;
259
260 Ok(())
261 }
262
263 async fn verify_prev_block_cert(
264 &self,
265 candidate_block: &'a ledger::Header,
266 ) -> Result<Vec<Voter>, HeaderError> {
267 if self.prev_header.height == 0
268 || is_emergency_block(self.prev_header.iteration)
269 {
270 return Ok(vec![]);
271 }
272
273 let prev_block_hash = candidate_block.prev_block_hash;
274
275 let prev_block_seed = self
276 .db
277 .read()
278 .await
279 .view(|v| v.block_header(&self.prev_header.prev_block_hash))
280 .map_err(|e| {
281 HeaderError::Storage(
282 "error checking Ledger::fetch_block_header",
283 e,
284 )
285 })?
286 .ok_or(HeaderError::Generic("Header not found"))
287 .map(|h| h.seed)?;
288
289 let voters = verify_att(
290 &candidate_block.prev_block_cert,
291 self.prev_header.to_consensus_header(),
292 prev_block_seed,
293 self.provisioners.prev(),
294 Some(RatificationResult::Success(Vote::Valid(prev_block_hash))),
295 )
296 .await?;
297
298 Ok(voters)
299 }
300
301 async fn verify_failed_iterations(
306 &self,
307 candidate_block: &'a ledger::Header,
308 ) -> Result<u8, FailedIterationError> {
309 let mut failed_atts = 0u8;
310
311 let att_list = &candidate_block.failed_iterations.att_list;
312
313 if att_list.len() > RELAX_ITERATION_THRESHOLD as usize {
314 return Err(FailedIterationError::TooMany(att_list.len()));
315 }
316
317 for (iter, att) in att_list.iter().enumerate() {
318 if let Some((att, pk)) = att {
319 debug!(event = "verify fail attestation", iter);
320
321 let expected_pk = self.provisioners.current().get_generator(
322 iter as u8,
323 self.prev_header.seed,
324 candidate_block.height,
325 );
326
327 if pk != &expected_pk {
328 return Err(FailedIterationError::InvalidGenerator(
329 expected_pk,
330 ));
331 }
332
333 let mut consensus_header =
334 candidate_block.to_consensus_header();
335 consensus_header.iteration = iter as u8;
336
337 verify_att(
338 att,
339 consensus_header,
340 self.prev_header.seed,
341 self.provisioners.current(),
342 Some(RatificationResult::Fail(Vote::default())),
343 )
344 .await?;
345
346 failed_atts += 1;
347 }
348 }
349
350 let last_iter = cmp::min(candidate_block.iteration, CONSENSUS_MAX_ITER);
353
354 Ok(last_iter - failed_atts)
355 }
356
357 pub async fn get_voters(
362 blk: &'a ledger::Header,
363 provisioners: &Provisioners,
364 prev_block_seed: Seed,
365 ) -> Vec<Voter> {
366 let att = &blk.att;
367 let consensus_header = blk.to_consensus_header();
368
369 let committee = RwLock::new(CommitteeSet::new(provisioners));
370
371 let validation_voters = verifiers::get_step_voters(
372 &consensus_header,
373 &att.validation,
374 &committee,
375 prev_block_seed,
376 StepName::Validation,
377 )
378 .await;
379
380 let ratification_voters = verifiers::get_step_voters(
381 &consensus_header,
382 &att.ratification,
383 &committee,
384 prev_block_seed,
385 StepName::Ratification,
386 )
387 .await;
388
389 merge_voters(validation_voters, ratification_voters)
390 }
391
392 pub async fn verify_faults(
394 &self,
395 current_height: u64,
396 faults: &[Fault],
397 ) -> Result<(), InvalidFault> {
398 verify_faults(self.db.clone(), current_height, faults).await
399 }
400}
401
402pub async fn verify_faults<DB: database::DB>(
403 db: Arc<RwLock<DB>>,
404 current_height: u64,
405 faults: &[Fault],
406) -> Result<(), InvalidFault> {
407 for f in faults {
408 let fault_header = f.validate(current_height)?;
409 if is_emergency_iter(fault_header.iteration) {
410 return Err(InvalidFault::EmergencyIteration);
411 }
412 db.read()
413 .await
414 .view(|db| {
415 let prev_header = db
416 .block_header(&fault_header.prev_block_hash)?
417 .ok_or(anyhow::anyhow!("Slashing a non accepted header"))?;
418 if prev_header.height != fault_header.round - 1 {
421 anyhow::bail!("Invalid height for fault");
422 }
423
424 let start_height = fault_header.round.saturating_sub(EPOCH);
428 let stored_faults = db.faults_by_block(start_height)?;
429 if stored_faults.iter().any(|other| f.same(other)) {
430 anyhow::bail!("Double fault detected");
431 }
432
433 Ok(())
434 })
435 .map_err(|e| InvalidFault::Other(format!("{e:?}")))?;
436 }
437 Ok(())
438}
439
440pub async fn verify_att(
441 att: &ledger::Attestation,
442 consensus_header: ConsensusHeader,
443 seed: Seed,
444 eligible_provisioners: &Provisioners,
445 expected_result: Option<RatificationResult>,
446) -> Result<Vec<Voter>, AttestationError> {
447 if let Some(expected) = expected_result {
449 match (att.result, expected) {
450 (
452 RatificationResult::Success(Vote::Valid(r_hash)),
453 RatificationResult::Success(Vote::Valid(e_hash)),
454 ) => {
455 if r_hash != e_hash {
456 error!(
457 "Invalid Attestation. Expected: Valid({:?}), got: Valid({:?})",
458 hex::encode(e_hash),
459 hex::encode(r_hash)
460 );
461 return Err(AttestationError::InvalidHash(e_hash, r_hash));
462 }
463 }
464 (RatificationResult::Fail(_), RatificationResult::Fail(_)) => {}
466 _ => {
468 error!(
469 "Invalid Attestation. Expected: {:?}, got: {:?}",
470 expected, att.result
471 );
472 return Err(AttestationError::InvalidResult(
473 att.result, expected,
474 ));
475 }
476 }
477 }
478
479 let committee_set = RwLock::new(CommitteeSet::new(eligible_provisioners));
480 let vote = att.result.vote();
481
482 let validation_voters = verifiers::verify_step_votes(
484 &consensus_header,
485 vote,
486 &att.validation,
487 &committee_set,
488 seed,
489 StepName::Validation,
490 )
491 .await
492 .map_err(|s| AttestationError::InvalidVotes(StepName::Validation, s))?;
493
494 let ratification_voters = verifiers::verify_step_votes(
496 &consensus_header,
497 vote,
498 &att.ratification,
499 &committee_set,
500 seed,
501 StepName::Ratification,
502 )
503 .await
504 .map_err(|s| AttestationError::InvalidVotes(StepName::Ratification, s))?;
505
506 let voters = merge_voters(validation_voters, ratification_voters);
507 Ok(voters)
508}
509
510fn merge_voters(v1: Vec<Voter>, v2: Vec<Voter>) -> Vec<Voter> {
513 let mut voter_map = BTreeMap::new();
514
515 for (pk, count) in v1.into_iter().chain(v2.into_iter()) {
516 let counter = voter_map.entry(pk).or_default();
517 *counter += count;
518 }
519
520 voter_map.into_iter().collect()
521}