1use std::{collections::BTreeSet, sync::Arc};
6
7use crate::{
8 Round,
9 block::{
10 BlockAPI, BlockRef, BlockTimestampMs, GENESIS_ROUND, SignedBlock, VerifiedBlock,
11 genesis_blocks,
12 },
13 context::Context,
14 error::{ConsensusError, ConsensusResult},
15 transaction::TransactionVerifier,
16};
17
18pub(crate) trait BlockVerifier: Send + Sync + 'static {
19 fn verify(&self, block: &SignedBlock) -> ConsensusResult<()>;
22
23 fn check_ancestors(
30 &self,
31 block: &VerifiedBlock,
32 ancestors: &[Option<VerifiedBlock>],
33 gc_enabled: bool,
34 gc_round: Round,
35 ) -> ConsensusResult<()>;
36}
37
38pub(crate) struct SignedBlockVerifier {
44 context: Arc<Context>,
45 genesis: BTreeSet<BlockRef>,
46 transaction_verifier: Arc<dyn TransactionVerifier>,
47}
48
49impl SignedBlockVerifier {
50 pub(crate) fn new(
51 context: Arc<Context>,
52 transaction_verifier: Arc<dyn TransactionVerifier>,
53 ) -> Self {
54 let genesis = genesis_blocks(context.clone())
55 .into_iter()
56 .map(|b| b.reference())
57 .collect();
58 Self {
59 context,
60 genesis,
61 transaction_verifier,
62 }
63 }
64
65 pub(crate) fn check_transactions(&self, batch: &[&[u8]]) -> ConsensusResult<()> {
66 let max_transaction_size_limit =
67 self.context.protocol_config.max_transaction_size_bytes() as usize;
68 for t in batch {
69 if t.len() > max_transaction_size_limit && max_transaction_size_limit > 0 {
70 return Err(ConsensusError::TransactionTooLarge {
71 size: t.len(),
72 limit: max_transaction_size_limit,
73 });
74 }
75 }
76
77 let max_num_transactions_limit =
78 self.context.protocol_config.max_num_transactions_in_block() as usize;
79 if batch.len() > max_num_transactions_limit && max_num_transactions_limit > 0 {
80 return Err(ConsensusError::TooManyTransactions {
81 count: batch.len(),
82 limit: max_num_transactions_limit,
83 });
84 }
85
86 let total_transactions_size_limit = self
87 .context
88 .protocol_config
89 .max_transactions_in_block_bytes() as usize;
90 if batch.iter().map(|t| t.len()).sum::<usize>() > total_transactions_size_limit
91 && total_transactions_size_limit > 0
92 {
93 return Err(ConsensusError::TooManyTransactionBytes {
94 size: batch.len(),
95 limit: total_transactions_size_limit,
96 });
97 }
98 Ok(())
99 }
100}
101
102impl BlockVerifier for SignedBlockVerifier {
104 fn verify(&self, block: &SignedBlock) -> ConsensusResult<()> {
105 let committee = &self.context.committee;
106 if block.epoch() != committee.epoch() {
109 return Err(ConsensusError::WrongEpoch {
110 expected: committee.epoch(),
111 actual: block.epoch(),
112 });
113 }
114 if block.round() == 0 {
115 return Err(ConsensusError::UnexpectedGenesisBlock);
116 }
117 if !committee.is_valid_index(block.author()) {
118 return Err(ConsensusError::InvalidAuthorityIndex {
119 index: block.author(),
120 max: committee.size() - 1,
121 });
122 }
123
124 block.verify_signature(&self.context)?;
126
127 if block.ancestors().len() > committee.size() {
130 return Err(ConsensusError::TooManyAncestors(
131 block.ancestors().len(),
132 committee.size(),
133 ));
134 }
135 if block.ancestors().is_empty() {
136 return Err(ConsensusError::InsufficientParentStakes {
137 parent_stakes: 0,
138 quorum: committee.quorum_threshold(),
139 });
140 }
141 let mut seen_ancestors = vec![false; committee.size()];
142 let mut parent_stakes = 0;
143 for (i, ancestor) in block.ancestors().iter().enumerate() {
144 if !committee.is_valid_index(ancestor.author) {
145 return Err(ConsensusError::InvalidAuthorityIndex {
146 index: ancestor.author,
147 max: committee.size() - 1,
148 });
149 }
150 if (i == 0 && ancestor.author != block.author())
151 || (i > 0 && ancestor.author == block.author())
152 {
153 return Err(ConsensusError::InvalidAncestorPosition {
154 block_authority: block.author(),
155 ancestor_authority: ancestor.author,
156 position: i,
157 });
158 }
159 if ancestor.round >= block.round() {
160 return Err(ConsensusError::InvalidAncestorRound {
161 ancestor: ancestor.round,
162 block: block.round(),
163 });
164 }
165 if ancestor.round == GENESIS_ROUND && !self.genesis.contains(ancestor) {
166 return Err(ConsensusError::InvalidGenesisAncestor(*ancestor));
167 }
168 if seen_ancestors[ancestor.author] {
169 return Err(ConsensusError::DuplicatedAncestorsAuthority(
170 ancestor.author,
171 ));
172 }
173 seen_ancestors[ancestor.author] = true;
174 if ancestor.round == block.round().checked_sub(1).unwrap() {
176 parent_stakes += committee.stake(ancestor.author);
177 }
178 }
179 if !committee.reached_quorum(parent_stakes) {
180 return Err(ConsensusError::InsufficientParentStakes {
181 parent_stakes,
182 quorum: committee.quorum_threshold(),
183 });
184 }
185
186 let batch: Vec<_> = block.transactions().iter().map(|t| t.data()).collect();
187
188 self.check_transactions(&batch)?;
189
190 self.transaction_verifier
191 .verify_batch(&batch)
192 .map_err(|e| ConsensusError::InvalidTransaction(format!("{e:?}")))
193 }
194
195 fn check_ancestors(
196 &self,
197 block: &VerifiedBlock,
198 ancestors: &[Option<VerifiedBlock>],
199 gc_enabled: bool,
200 gc_round: Round,
201 ) -> ConsensusResult<()> {
202 if gc_enabled {
203 let mut max_timestamp_ms = BlockTimestampMs::MIN;
208 for ancestor in ancestors.iter().flatten() {
209 if ancestor.round() <= gc_round {
210 continue;
211 }
212 max_timestamp_ms = max_timestamp_ms.max(ancestor.timestamp_ms());
213 if max_timestamp_ms > block.timestamp_ms() {
214 return Err(ConsensusError::InvalidBlockTimestamp {
215 max_timestamp_ms,
216 block_timestamp_ms: block.timestamp_ms(),
217 });
218 }
219 }
220 } else {
221 assert_eq!(block.ancestors().len(), ancestors.len());
222 let mut max_timestamp_ms = BlockTimestampMs::MIN;
224 for (ancestor_ref, ancestor_block) in block.ancestors().iter().zip(ancestors.iter()) {
225 let ancestor_block = ancestor_block
226 .as_ref()
227 .expect("There should never be an empty slot");
228 assert_eq!(ancestor_ref, &ancestor_block.reference());
229 max_timestamp_ms = max_timestamp_ms.max(ancestor_block.timestamp_ms());
230 }
231 if max_timestamp_ms > block.timestamp_ms() {
232 return Err(ConsensusError::InvalidBlockTimestamp {
233 max_timestamp_ms,
234 block_timestamp_ms: block.timestamp_ms(),
235 });
236 }
237 }
238 Ok(())
239 }
240}
241
242#[cfg(test)]
243pub(crate) struct NoopBlockVerifier;
244
245#[cfg(test)]
246impl BlockVerifier for NoopBlockVerifier {
247 fn verify(&self, _block: &SignedBlock) -> ConsensusResult<()> {
248 Ok(())
249 }
250
251 fn check_ancestors(
252 &self,
253 _block: &VerifiedBlock,
254 _ancestors: &[Option<VerifiedBlock>],
255 _gc_enabled: bool,
256 _gc_round: Round,
257 ) -> ConsensusResult<()> {
258 Ok(())
259 }
260}
261
262#[cfg(test)]
263mod test {
264 use consensus_config::AuthorityIndex;
265 use rstest::rstest;
266
267 use super::*;
268 use crate::{
269 block::{BlockDigest, BlockRef, TestBlock, Transaction},
270 context::Context,
271 transaction::{TransactionVerifier, ValidationError},
272 };
273
274 struct TxnSizeVerifier {}
275
276 impl TransactionVerifier for TxnSizeVerifier {
277 fn verify_batch(&self, transactions: &[&[u8]]) -> Result<(), ValidationError> {
279 for txn in transactions {
280 if txn.len() < 4 {
281 return Err(ValidationError::InvalidTransaction(format!(
282 "Length {} is too short!",
283 txn.len()
284 )));
285 }
286 }
287 Ok(())
288 }
289 }
290
291 #[tokio::test]
292 async fn test_verify_block() {
293 let (context, keypairs) = Context::new_for_test(4);
294 let context = Arc::new(context);
295 let authority_2_protocol_keypair = &keypairs[2].1;
296 let verifier = SignedBlockVerifier::new(context.clone(), Arc::new(TxnSizeVerifier {}));
297
298 let test_block = TestBlock::new(10, 2)
299 .set_ancestors(vec![
300 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
301 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
302 BlockRef::new(9, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
303 BlockRef::new(7, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
304 ])
305 .set_transactions(vec![Transaction::new(vec![4; 8])]);
306
307 {
309 let block = test_block.clone().build();
310 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
311 verifier.verify(&signed_block).unwrap();
312 }
313
314 {
316 let block = test_block.clone().set_epoch(1).build();
317 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
318 assert!(matches!(
319 verifier.verify(&signed_block),
320 Err(ConsensusError::WrongEpoch {
321 expected: _,
322 actual: _
323 })
324 ));
325 }
326
327 {
329 let block = test_block.clone().set_round(0).build();
330 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
331 assert!(matches!(
332 verifier.verify(&signed_block),
333 Err(ConsensusError::UnexpectedGenesisBlock)
334 ));
335 }
336
337 {
339 let block = test_block
340 .clone()
341 .set_author(AuthorityIndex::new_for_test(4))
342 .build();
343 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
344 assert!(matches!(
345 verifier.verify(&signed_block),
346 Err(ConsensusError::InvalidAuthorityIndex { index: _, max: _ })
347 ));
348 }
349
350 {
352 let block = test_block
353 .clone()
354 .set_author(AuthorityIndex::new_for_test(1))
355 .build();
356 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
357 assert!(matches!(
358 verifier.verify(&signed_block),
359 Err(ConsensusError::SignatureVerificationFailure(_))
360 ));
361 }
362
363 {
365 let block = test_block.clone().build();
366 let signed_block = SignedBlock::new(block, &keypairs[3].1).unwrap();
367 assert!(matches!(
368 verifier.verify(&signed_block),
369 Err(ConsensusError::SignatureVerificationFailure(_))
370 ));
371 }
372
373 {
375 let block = test_block.clone().build();
376 let mut signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
377 signed_block.clear_signature();
378 assert!(matches!(
379 verifier.verify(&signed_block),
380 Err(ConsensusError::MalformedSignature(_))
381 ));
382 }
383
384 {
386 let block = test_block
387 .clone()
388 .set_ancestors(vec![
389 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
390 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
391 BlockRef::new(9, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
392 BlockRef::new(10, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
393 ])
394 .build();
395 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
396 assert!(matches!(
397 verifier.verify(&signed_block),
398 Err(ConsensusError::InvalidAncestorRound {
399 ancestor: _,
400 block: _
401 })
402 ));
403 }
404
405 {
407 let block = test_block
408 .clone()
409 .set_ancestors(vec![
410 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
411 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
412 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
413 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
414 ])
415 .build();
416 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
417 assert!(matches!(
418 verifier.verify(&signed_block),
419 Err(ConsensusError::InsufficientParentStakes {
420 parent_stakes: _,
421 quorum: _
422 })
423 ));
424 }
425
426 {
428 let block = test_block
429 .clone()
430 .set_ancestors(vec![
431 BlockRef::new(9, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
432 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
433 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
434 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
435 BlockRef::new(9, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
436 ])
437 .build();
438 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
439 assert!(matches!(
440 verifier.verify(&signed_block),
441 Err(ConsensusError::TooManyAncestors(_, _))
442 ));
443 }
444
445 {
447 let block = test_block
448 .clone()
449 .set_ancestors(vec![
450 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
451 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
452 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
453 ])
454 .build();
455 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
456 assert!(matches!(
457 verifier.verify(&signed_block),
458 Err(ConsensusError::InvalidAncestorPosition {
459 block_authority: _,
460 ancestor_authority: _,
461 position: _
462 })
463 ));
464 }
465
466 {
468 let block = test_block
469 .clone()
470 .set_ancestors(vec![
471 BlockRef::new(9, AuthorityIndex::new_for_test(0), BlockDigest::MIN),
472 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
473 BlockRef::new(8, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
474 BlockRef::new(8, AuthorityIndex::new_for_test(3), BlockDigest::MIN),
475 ])
476 .build();
477 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
478 assert!(matches!(
479 verifier.verify(&signed_block),
480 Err(ConsensusError::InvalidAncestorPosition {
481 block_authority: _,
482 ancestor_authority: _,
483 position: _
484 })
485 ));
486 }
487
488 {
490 let block = test_block
491 .clone()
492 .set_ancestors(vec![
493 BlockRef::new(8, AuthorityIndex::new_for_test(2), BlockDigest::MIN),
494 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
495 BlockRef::new(8, AuthorityIndex::new_for_test(1), BlockDigest::MIN),
496 ])
497 .build();
498 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
499 assert!(matches!(
500 verifier.verify(&signed_block),
501 Err(ConsensusError::DuplicatedAncestorsAuthority(_))
502 ));
503 }
504
505 {
507 let block = test_block
508 .clone()
509 .set_transactions(vec![Transaction::new(vec![1; 2])])
510 .build();
511 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
512 assert!(matches!(
513 verifier.verify(&signed_block),
514 Err(ConsensusError::InvalidTransaction(_))
515 ));
516 }
517
518 {
520 let block = test_block
521 .clone()
522 .set_transactions(vec![Transaction::new(vec![4; 257 * 1024])])
523 .build();
524 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
525 assert!(matches!(
526 verifier.verify(&signed_block),
527 Err(ConsensusError::TransactionTooLarge { size: _, limit: _ })
528 ));
529 }
530
531 {
533 let block = test_block
534 .clone()
535 .set_transactions((0..1000).map(|_| Transaction::new(vec![4; 8])).collect())
536 .build();
537 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
538 assert!(matches!(
539 verifier.verify(&signed_block),
540 Err(ConsensusError::TooManyTransactions { count: _, limit: _ })
541 ));
542 }
543
544 {
546 let block = test_block
547 .clone()
548 .set_transactions(
549 (0..100)
550 .map(|_| Transaction::new(vec![4; 8 * 1024]))
551 .collect(),
552 )
553 .build();
554 let signed_block = SignedBlock::new(block, authority_2_protocol_keypair).unwrap();
555 assert!(matches!(
556 verifier.verify(&signed_block),
557 Err(ConsensusError::TooManyTransactionBytes { size: _, limit: _ })
558 ));
559 }
560 }
561
562 #[rstest]
566 #[tokio::test]
567 async fn test_check_ancestors(#[values(false, true)] gc_enabled: bool) {
568 let num_authorities = 4;
569 let (context, _keypairs) = Context::new_for_test(num_authorities);
570 let context = Arc::new(context);
571 let verifier = SignedBlockVerifier::new(context.clone(), Arc::new(TxnSizeVerifier {}));
572 let gc_round = 0;
573
574 let mut ancestor_blocks = vec![];
575 for i in 0..num_authorities {
576 let test_block = TestBlock::new(10, i as u32)
577 .set_timestamp_ms(1000 + 100 * i as BlockTimestampMs)
578 .build();
579 ancestor_blocks.push(Some(VerifiedBlock::new_for_test(test_block)));
580 }
581 let ancestor_refs = ancestor_blocks
582 .iter()
583 .flatten()
584 .map(|block| block.reference())
585 .collect::<Vec<_>>();
586
587 {
589 let block = TestBlock::new(11, 0)
590 .set_ancestors(ancestor_refs.clone())
591 .set_timestamp_ms(1500)
592 .build();
593 let verified_block = VerifiedBlock::new_for_test(block);
594 assert!(
595 verifier
596 .check_ancestors(&verified_block, &ancestor_blocks, gc_enabled, gc_round)
597 .is_ok()
598 );
599 }
600
601 {
603 let block = TestBlock::new(11, 0)
604 .set_ancestors(ancestor_refs.clone())
605 .set_timestamp_ms(1000)
606 .build();
607 let verified_block = VerifiedBlock::new_for_test(block);
608 assert!(matches!(
609 verifier.check_ancestors(&verified_block, &ancestor_blocks, gc_enabled, gc_round),
610 Err(ConsensusError::InvalidBlockTimestamp {
611 max_timestamp_ms: _,
612 block_timestamp_ms: _
613 })
614 ));
615 }
616 }
617
618 #[tokio::test]
619 async fn test_check_ancestors_passed_gc_round() {
620 let num_authorities = 4;
621 let (context, _keypairs) = Context::new_for_test(num_authorities);
622 let context = Arc::new(context);
623 let verifier = SignedBlockVerifier::new(context.clone(), Arc::new(TxnSizeVerifier {}));
624 let gc_enabled = true;
625 let gc_round = 3;
626
627 let mut ancestor_blocks = vec![];
628
629 let test_block = TestBlock::new(gc_round, 0_u32)
632 .set_timestamp_ms(1500 as BlockTimestampMs)
633 .build();
634 ancestor_blocks.push(Some(VerifiedBlock::new_for_test(test_block)));
635
636 for i in 1..=3 {
638 let test_block = TestBlock::new(gc_round + 1, i as u32)
639 .set_timestamp_ms(1000 + 100 * i as BlockTimestampMs)
640 .build();
641 ancestor_blocks.push(Some(VerifiedBlock::new_for_test(test_block)));
642 }
643
644 let ancestor_refs = ancestor_blocks
645 .iter()
646 .flatten()
647 .map(|block| block.reference())
648 .collect::<Vec<_>>();
649
650 {
652 let block = TestBlock::new(gc_round + 2, 0)
653 .set_ancestors(ancestor_refs.clone())
654 .set_timestamp_ms(1600)
655 .build();
656 let verified_block = VerifiedBlock::new_for_test(block);
657 assert!(
658 verifier
659 .check_ancestors(&verified_block, &ancestor_blocks, gc_enabled, gc_round)
660 .is_ok()
661 );
662 }
663
664 {
667 let block = TestBlock::new(11, 0)
668 .set_ancestors(ancestor_refs.clone())
669 .set_timestamp_ms(1400)
670 .build();
671 let verified_block = VerifiedBlock::new_for_test(block);
672 assert!(
673 verifier
674 .check_ancestors(&verified_block, &ancestor_blocks, gc_enabled, gc_round)
675 .is_ok()
676 );
677 }
678
679 {
682 let block = TestBlock::new(11, 0)
683 .set_ancestors(ancestor_refs.clone())
684 .set_timestamp_ms(1100)
685 .build();
686 let verified_block = VerifiedBlock::new_for_test(block);
687 assert!(matches!(
688 verifier.check_ancestors(&verified_block, &ancestor_blocks, gc_enabled, gc_round),
689 Err(ConsensusError::InvalidBlockTimestamp {
690 max_timestamp_ms: _,
691 block_timestamp_ms: _
692 })
693 ));
694 }
695 }
696}